From b10b37eabeb74ae748ad05fafc113a9f2dfed122 Mon Sep 17 00:00:00 2001 From: cekees Date: Wed, 27 May 2015 18:47:50 -0500 Subject: [PATCH 01/20] first cut a 2D flume for vegetation experiments --- 2d/waves_vegetation/ls_consrv_n.py | 48 ++ 2d/waves_vegetation/ls_consrv_p.py | 26 ++ 2d/waves_vegetation/ls_n.py | 62 +++ 2d/waves_vegetation/ls_p.py | 29 ++ 2d/waves_vegetation/redist_n.py | 67 +++ 2d/waves_vegetation/redist_p.py | 32 ++ 2d/waves_vegetation/tank.py | 498 +++++++++++++++++++++ 2d/waves_vegetation/tank_batch.py | 4 + 2d/waves_vegetation/tank_so.py | 32 ++ 2d/waves_vegetation/twp_navier_stokes_n.py | 67 +++ 2d/waves_vegetation/twp_navier_stokes_p.py | 141 ++++++ 2d/waves_vegetation/vof_n.py | 64 +++ 2d/waves_vegetation/vof_p.py | 46 ++ 13 files changed, 1116 insertions(+) create mode 100644 2d/waves_vegetation/ls_consrv_n.py create mode 100644 2d/waves_vegetation/ls_consrv_p.py create mode 100644 2d/waves_vegetation/ls_n.py create mode 100644 2d/waves_vegetation/ls_p.py create mode 100644 2d/waves_vegetation/redist_n.py create mode 100644 2d/waves_vegetation/redist_p.py create mode 100644 2d/waves_vegetation/tank.py create mode 100644 2d/waves_vegetation/tank_batch.py create mode 100644 2d/waves_vegetation/tank_so.py create mode 100644 2d/waves_vegetation/twp_navier_stokes_n.py create mode 100644 2d/waves_vegetation/twp_navier_stokes_p.py create mode 100644 2d/waves_vegetation/vof_n.py create mode 100644 2d/waves_vegetation/vof_p.py diff --git a/2d/waves_vegetation/ls_consrv_n.py b/2d/waves_vegetation/ls_consrv_n.py new file mode 100644 index 00000000..498ecfd6 --- /dev/null +++ b/2d/waves_vegetation/ls_consrv_n.py @@ -0,0 +1,48 @@ +from proteus import * +from tank import * +from ls_consrv_p import * + +timeIntegrator = ForwardIntegrator +timeIntegration = NoIntegration + +femSpaces = {0:basis} + +subgridError = None +massLumping = False +numericalFluxType = DoNothing +conservativeFlux = None +shockCapturing = None + +fullNewtonFlag = True +multilevelNonlinearSolver = Newton +levelNonlinearSolver = Newton + +nonlinearSmoother = None +linearSmoother = None + +matrix = SparseMatrix + +if useOldPETSc: + multilevelLinearSolver = PETSc + levelLinearSolver = PETSc +else: + multilevelLinearSolver = KSP_petsc4py + levelLinearSolver = KSP_petsc4py + +if useSuperlu: + multilevelLinearSolver = LU + levelLinearSolver = LU + +linear_solver_options_prefix = 'mcorr_' +nonlinearSolverConvergenceTest = 'r' +levelNonlinearSolverConvergenceTest = 'r' +linearSolverConvergenceTest = 'r-true' + +tolFac = 0.0 +linTolFac = 0.01 +l_atol_res = 0.01*mcorr_nl_atol_res +nl_atol_res = mcorr_nl_atol_res +useEisenstatWalker = False + +maxNonlinearIts = 50 +maxLineSearches = 0 diff --git a/2d/waves_vegetation/ls_consrv_p.py b/2d/waves_vegetation/ls_consrv_p.py new file mode 100644 index 00000000..84f85ac9 --- /dev/null +++ b/2d/waves_vegetation/ls_consrv_p.py @@ -0,0 +1,26 @@ +from proteus import * +from proteus.default_p import * +from tank import * +from proteus.mprans import MCorr + +LevelModelType = MCorr.LevelModel + +coefficients = MCorr.Coefficients(LSModel_index=2,V_model=0,me_model=4,VOFModel_index=1, + applyCorrection=applyCorrection,nd=nd,checkMass=False,useMetrics=useMetrics, + epsFactHeaviside=epsFact_consrv_heaviside, + epsFactDirac=epsFact_consrv_dirac, + epsFactDiffusion=epsFact_consrv_diffusion) + +class zero_phi: + def __init__(self): + pass + def uOfX(self,X): + return 0.0 + def uOfXT(self,X,t): + return 0.0 + +initialConditions = {0:zero_phi()} + + + + diff --git a/2d/waves_vegetation/ls_n.py b/2d/waves_vegetation/ls_n.py new file mode 100644 index 00000000..4cfc1db3 --- /dev/null +++ b/2d/waves_vegetation/ls_n.py @@ -0,0 +1,62 @@ +from proteus import * +from ls_p import * + +if timeDiscretization=='vbdf': + timeIntegration = VBDF + timeOrder=2 + stepController = Min_dt_cfl_controller +elif timeDiscretization=='flcbdf': + timeIntegration = FLCBDF + #stepController = FLCBDF_controller + stepController = Min_dt_cfl_controller + time_tol = 10.0*ls_nl_atol_res + atol_u = {0:time_tol} + rtol_u = {0:time_tol} +else: + timeIntegration = BackwardEuler_cfl + stepController = Min_dt_cfl_controller + +femSpaces = {0:basis} + +massLumping = False +conservativeFlux = None +numericalFluxType = NCLS.NumericalFlux +subgridError = NCLS.SubgridError(coefficients,nd) +shockCapturing = NCLS.ShockCapturing(coefficients,nd,shockCapturingFactor=ls_shockCapturingFactor,lag=ls_lag_shockCapturing) + +fullNewtonFlag = True +multilevelNonlinearSolver = Newton +levelNonlinearSolver = Newton + +nonlinearSmoother = None +linearSmoother = None + +matrix = SparseMatrix + +if useOldPETSc: + multilevelLinearSolver = PETSc + levelLinearSolver = PETSc +else: + multilevelLinearSolver = KSP_petsc4py + levelLinearSolver = KSP_petsc4py + +if useSuperlu: + multilevelLinearSolver = LU + levelLinearSolver = LU + +linear_solver_options_prefix = 'ncls_' +nonlinearSolverConvergenceTest = 'r' +levelNonlinearSolverConvergenceTest = 'r' +linearSolverConvergenceTest = 'r-true' + +tolFac = 0.0 +nl_atol_res = ls_nl_atol_res + +linTolFac = 0.0 +l_atol_res = 0.1*ls_nl_atol_res + +useEisenstatWalker = False + +maxNonlinearIts = 50 +maxLineSearches = 0 + diff --git a/2d/waves_vegetation/ls_p.py b/2d/waves_vegetation/ls_p.py new file mode 100644 index 00000000..fad3ff3a --- /dev/null +++ b/2d/waves_vegetation/ls_p.py @@ -0,0 +1,29 @@ +from proteus import * +from proteus.default_p import * +from tank import * +from proteus.mprans import NCLS + +LevelModelType = NCLS.LevelModel + +coefficients = NCLS.Coefficients(V_model=0,RD_model=3,ME_model=2, + checkMass=False, useMetrics=useMetrics, + epsFact=epsFact_consrv_heaviside,sc_uref=ls_sc_uref,sc_beta=ls_sc_beta,movingDomain=movingDomain) + +def getDBC_ls(x,flag): + if flag == boundaryTags['left']: + return wavePhi +# elif flag == boundaryTags['right']: +# return outflowPhi + else: + return None + +dirichletConditions = {0:getDBC_ls} + +advectiveFluxBoundaryConditions = {} +diffusiveFluxBoundaryConditions = {0:{}} + +class PerturbedSurface_phi: + def uOfXT(self,x,t): + return signedDistance(x) + +initialConditions = {0:PerturbedSurface_phi()} diff --git a/2d/waves_vegetation/redist_n.py b/2d/waves_vegetation/redist_n.py new file mode 100644 index 00000000..237f5e17 --- /dev/null +++ b/2d/waves_vegetation/redist_n.py @@ -0,0 +1,67 @@ +from proteus import * +from redist_p import * +from tank import * + +nl_atol_res = rd_nl_atol_res +tolFac = 0.0 +nl_atol_res = rd_nl_atol_res + +linTolFac = 0.01 +l_atol_res = 0.01*rd_nl_atol_res + +if redist_Newton: + timeIntegration = NoIntegration + stepController = Newton_controller + maxNonlinearIts = 50 + maxLineSearches = 0 + nonlinearSolverConvergenceTest = 'r' + levelNonlinearSolverConvergenceTest = 'r' + linearSolverConvergenceTest = 'r-true' + useEisenstatWalker = False +else: + timeIntegration = BackwardEuler_cfl + stepController = RDLS.PsiTC + runCFL=2.0 + psitc['nStepsForce']=3 + psitc['nStepsMax']=50 + psitc['reduceRatio']=2.0 + psitc['startRatio']=1.0 + rtol_res[0] = 0.0 + atol_res[0] = rd_nl_atol_res + useEisenstatWalker = False + maxNonlinearIts = 1 + maxLineSearches = 0 + nonlinearSolverConvergenceTest = 'rits' + levelNonlinearSolverConvergenceTest = 'rits' + linearSolverConvergenceTest = 'r-true' + +femSpaces = {0:basis} + +massLumping = False +numericalFluxType = DoNothing +conservativeFlux = None +subgridError = RDLS.SubgridError(coefficients,nd) +shockCapturing = RDLS.ShockCapturing(coefficients,nd,shockCapturingFactor=rd_shockCapturingFactor,lag=rd_lag_shockCapturing) + +fullNewtonFlag = True +multilevelNonlinearSolver = Newton +levelNonlinearSolver = Newton + +nonlinearSmoother = NLGaussSeidel +linearSmoother = None + +matrix = SparseMatrix + +if useOldPETSc: + multilevelLinearSolver = PETSc + levelLinearSolver = PETSc +else: + multilevelLinearSolver = KSP_petsc4py + levelLinearSolver = KSP_petsc4py + +if useSuperlu: + multilevelLinearSolver = LU + levelLinearSolver = LU + +linear_solver_options_prefix = 'rdls_' + diff --git a/2d/waves_vegetation/redist_p.py b/2d/waves_vegetation/redist_p.py new file mode 100644 index 00000000..5700202e --- /dev/null +++ b/2d/waves_vegetation/redist_p.py @@ -0,0 +1,32 @@ +from proteus import * +from proteus.default_p import * +from math import * +from tank import * +from proteus.mprans import RDLS +""" +The redistancing equation in the sloshbox test problem. +""" + +LevelModelType = RDLS.LevelModel + +coefficients = RDLS.Coefficients(applyRedistancing=applyRedistancing, + epsFact=epsFact_redistance, + nModelId=2, + rdModelId=3, + useMetrics=useMetrics, + backgroundDiffusionFactor=backgroundDiffusionFactor) + +def getDBC_rd(x,flag): + pass + +dirichletConditions = {0:getDBC_rd} +weakDirichletConditions = {0:RDLS.setZeroLSweakDirichletBCsSimple} + +advectiveFluxBoundaryConditions = {} +diffusiveFluxBoundaryConditions = {0:{}} + +class PerturbedSurface_phi: + def uOfXT(self,x,t): + return signedDistance(x) + +initialConditions = {0:PerturbedSurface_phi()} diff --git a/2d/waves_vegetation/tank.py b/2d/waves_vegetation/tank.py new file mode 100644 index 00000000..133278cb --- /dev/null +++ b/2d/waves_vegetation/tank.py @@ -0,0 +1,498 @@ +from math import * +import proteus.MeshTools +from proteus import Domain +from proteus.default_n import * +from proteus.Profiling import logEvent +from proteus.ctransportCoefficients import smoothedHeaviside +from proteus.ctransportCoefficients import smoothedHeaviside_integral +from proteus import Gauges +from proteus.Gauges import PointGauges,LineGauges,LineIntegralGauges +from proteus import WaveTools as WT + + +#wave generator +windVelocity = (0.0,0.0) +depth = 1.0 +inflowHeightMean = 1.0 +inflowVelocityMean = (0.0,0.0) +period = 1.134 +omega = 2.0*math.pi/period +waveheight = 0.05 +amplitude = waveheight/ 2.0 +wavelength = 1.5 +k = 2.0*math.pi/wavelength +waveDir = numpy.array([1,0,0]) +g = numpy.array([0,-9.81,0]) +waves = WT.RandomWaves( Tp = period, # Peak period + Hs = waveheight, # Height + d = depth, # Depth + fp = 1./period, #peak Frequency + bandFactor = 2.0, #fmin=fp/Bandfactor, fmax = Bandfactor * fp + N = 101, #No of frequencies for signal reconstruction + mwl = inflowHeightMean, # Sea water level + waveDir = waveDir, # waveDirection + g = g, # Gravity vector, defines the vertical + gamma=3.3, + spec_fun = WT.JONSWAP) + + + +# Discretization -- input options +genMesh=True +movingDomain=False +applyRedistancing=True +useOldPETSc=False +useSuperlu=False +timeDiscretization='be'#'be','vbdf','flcbdf' +spaceOrder = 1 +useHex = False +useRBLES = 0.0 +useMetrics = 1.0 +applyCorrection=True +useVF = 1.0 +useOnlyVF = False +useRANS = 0 # 0 -- None + # 1 -- K-Epsilon + # 2 -- K-Omega +# Input checks +if spaceOrder not in [1,2]: + print "INVALID: spaceOrder" + spaceOrder + sys.exit() + +if useRBLES not in [0.0, 1.0]: + print "INVALID: useRBLES" + useRBLES + sys.exit() + +if useMetrics not in [0.0, 1.0]: + print "INVALID: useMetrics" + sys.exit() + +# Discretization +nd = 2 +if spaceOrder == 1: + hFactor=1.0 + if useHex: + basis=C0_AffineLinearOnCubeWithNodalBasis + elementQuadrature = CubeGaussQuadrature(nd,2) + elementBoundaryQuadrature = CubeGaussQuadrature(nd-1,2) + else: + basis=C0_AffineLinearOnSimplexWithNodalBasis + elementQuadrature = SimplexGaussQuadrature(nd,3) + elementBoundaryQuadrature = SimplexGaussQuadrature(nd-1,3) +elif spaceOrder == 2: + hFactor=0.5 + if useHex: + basis=C0_AffineLagrangeOnCubeWithNodalBasis + elementQuadrature = CubeGaussQuadrature(nd,4) + elementBoundaryQuadrature = CubeGaussQuadrature(nd-1,4) + else: + basis=C0_AffineQuadraticOnSimplexWithNodalBasis + elementQuadrature = SimplexGaussQuadrature(nd,4) + elementBoundaryQuadrature = SimplexGaussQuadrature(nd-1,4) + +# Domain and mesh + +#for debugging, make the tank short +L = (45.4,1.0) +he = float(wavelength)/20.0#100 + +GenerationZoneLength = wavelength +AbsorptionZoneLength= wavelength*2.0 +spongeLayer = True +xSponge = GenerationZoneLength +xRelaxCenter = xSponge/2.0 +epsFact_solid = xSponge/2.0 +#zone 2 +xSponge_2 = L[0]-AbsorptionZoneLength +xRelaxCenter_2 = 0.5*(xSponge_2+L[0]) +epsFact_solid_2 = AbsorptionZoneLength/2.0 + +weak_bc_penalty_constant = 100.0 +nLevels = 1 +#parallelPartitioningType = proteus.MeshTools.MeshParallelPartitioningTypes.element +parallelPartitioningType = proteus.MeshTools.MeshParallelPartitioningTypes.node +nLayersOfOverlapForParallel = 0 +structured=False + + +gauge_dx=0.075 +PGL=[] +LGL=[] +for i in range(0,int(L[0]/gauge_dx+1)): #+1 only if gauge_dx is an exact + PGL.append([gauge_dx*i,0.5,0]) + LGL.append([(gauge_dx*i,0.0,0),(gauge_dx*i,L[1],0)]) + + +gaugeLocations=tuple(map(tuple,PGL)) +columnLines=tuple(map(tuple,LGL)) + + +pointGauges = PointGauges(gauges=((('u','v'), gaugeLocations), + (('p',), gaugeLocations)), + activeTime = (0, 1000.0), + sampleRate = 0, + fileName = 'combined_gauge_0_0.5_sample_all.txt') + +print gaugeLocations +print columnLines + +fields = ('vof',) + +columnGauge = LineIntegralGauges(gauges=((fields, columnLines),), + fileName='column_gauge.csv') + +#lineGauges = LineGauges(gaugeEndpoints={'lineGauge_y=0':((0.0,0.0,0.0),(L[0],0.0,0.0))},linePoints=24) + +#lineGauges_phi = LineGauges_phi(lineGauges.endpoints,linePoints=20) + + +if useHex: + nnx=ceil(L[0]/he)+1 + nny=ceil(L[1]/he)+1 + hex=True + domain = Domain.RectangularDomain(L) +else: + boundaries=['left','right','bottom','top','front','back'] + boundaryTags=dict([(key,i+1) for (i,key) in enumerate(boundaries)]) + if structured: + nnx=ceil(L[0]/he)+1 + nny=ceil(L[1]/he)+1 + elif spongeLayer: + vertices=[[0.0,0.0],#0 + [19.6, 19.6/44.0 ],#1 + [19.6+6.1, 19.6/44.0+6.1/20.0],#2 + [19.6+6.1+1.2, 19.6/44.0+6.1/20.0],#3 + [19.6+6.1+1.2+9.8, 19.6/44.0+6.1/20.0],#4 + [19.6+6.1+1.2+9.8+1.2, 19.6/44.0+6.1/20.0],#5 + [37.9, 19.5/44.0+6.1/20.0],#6 + [45.4, 19.5/44.0+11.3/20.0],#7 + [37.9, 19.5/44.0+11.3/20.0],#8 + [0.0, 19.5/44.0+11.3/20.0]]#9 + + vertexFlags=[boundaryTags['bottom'],#0 + boundaryTags['bottom'],#1 + boundaryTags['bottom'],#2 + boundaryTags['bottom'],#3 + boundaryTags['bottom'],#4 + boundaryTags['bottom'],#5 + boundaryTags['bottom'],#6 + boundaryTags['bottom'],#7 + boundaryTags['top'],#8 + boundaryTags['top']]#9 + segments=[[0,1],#0 + [1,2],#1 + [2,3],#2 + [3,4],#3 + [4,5],#4 + [5,6],#5 + [6,7],#6 + [7,8],#7 + [8,9],#8 + [9,0],#9 + [7,0]]#10 + + segmentFlags=[boundaryTags['bottom'],#0 + boundaryTags['bottom'],#1 + boundaryTags['bottom'],#2 + boundaryTags['bottom'],#3 + boundaryTags['bottom'],#4 + boundaryTags['bottom'],#5 + boundaryTags['bottom'],#6 + boundaryTags['top'],#7 + boundaryTags['top'],#8 + boundaryTags['left'],#9 + 0]#10 + + regions=[[0.001,0.5],[38,0.5]] + regionFlags=[1,2] + domain = Domain.PlanarStraightLineGraphDomain(vertices=vertices, + vertexFlags=vertexFlags, + segments=segments, + segmentFlags=segmentFlags, + regions=regions, + regionFlags=regionFlags) + #go ahead and add a boundary tags member + domain.boundaryTags = boundaryTags + domain.writePoly("mesh") + domain.writePLY("mesh") + domain.writeAsymptote("mesh") + triangleOptions="VApq30Dena%8.8f" % ((he**2)/2.0,) + + logEvent("""Mesh generated using: tetgen -%s %s""" % (triangleOptions,domain.polyfile+".poly")) + porosityTypes = numpy.array([1.0, + 1.0, + + 1.0]) + dragAlphaTypes = numpy.array([0.0, + 0.5/1.004e-6, + + 0.0]) + dragBetaTypes = numpy.array([0.0,0.0,0.0]) + + epsFact_solidTypes = np.array([0.0,epsFact_solid_2,0.0]) + + else: + vertices=[[0.0,0.0],#0 + [L[0],0.0],#1 + [L[0],L[1]],#2 + [0.0,L[1]]]#3 + + vertexFlags=[boundaryTags['bottom'], + boundaryTags['bottom'], + boundaryTags['top'], + boundaryTags['top']] + segments=[[0,1], + [1,2], + [2,3], + [3,0] + ] + segmentFlags=[boundaryTags['bottom'], + boundaryTags['right'], + boundaryTags['top'], + boundaryTags['left']] + + regions=[ [ 0.1*L[0] , 0.1*L[1] ], + [0.95*L[0] , 0.95*L[1] ] ] + regionFlags=[1,2] + domain = Domain.PlanarStraightLineGraphDomain(vertices=vertices, + vertexFlags=vertexFlags, + segments=segments, + segmentFlags=segmentFlags, + regions=regions, + regionFlags=regionFlags) + #go ahead and add a boundary tags member + domain.boundaryTags = boundaryTags + domain.writePoly("mesh") + domain.writePLY("mesh") + domain.writeAsymptote("mesh") + triangleOptions="VApq30Dena%8.8f" % ((he**2)/2.0,) + + logEvent("""Mesh generated using: tetgen -%s %s""" % (triangleOptions,domain.polyfile+".poly")) +# Time stepping +T=40*period +dt_fixed = T#2.0*0.5/20.0#T/2.0#period/21.0 +dt_init = min(0.1*dt_fixed,0.1) +runCFL=0.9 +nDTout = int(round(T/dt_fixed)) + +# Numerical parameters +ns_forceStrongDirichlet = False#True +backgroundDiffusionFactor=0.0 +if useMetrics: + ns_shockCapturingFactor = 0.25 + ns_lag_shockCapturing = True + ns_lag_subgridError = True + ls_shockCapturingFactor = 0.35 + ls_lag_shockCapturing = True + ls_sc_uref = 1.0 + ls_sc_beta = 1.0 + vof_shockCapturingFactor = 0.35 + vof_lag_shockCapturing = True + vof_sc_uref = 1.0 + vof_sc_beta = 1.0 + rd_shockCapturingFactor = 0.75 + rd_lag_shockCapturing = False + epsFact_density = 3.0 + epsFact_viscosity = epsFact_curvature = epsFact_vof = epsFact_consrv_heaviside = epsFact_consrv_dirac = epsFact_density + epsFact_redistance = 1.5 + epsFact_consrv_diffusion = 10.0 + redist_Newton = True + kappa_shockCapturingFactor = 0.1 + kappa_lag_shockCapturing = True#False + kappa_sc_uref = 1.0 + kappa_sc_beta = 1.0 + dissipation_shockCapturingFactor = 0.1 + dissipation_lag_shockCapturing = True#False + dissipation_sc_uref = 1.0 + dissipation_sc_beta = 1.0 +else: + ns_shockCapturingFactor = 0.9 + ns_lag_shockCapturing = True + ns_lag_subgridError = True + ls_shockCapturingFactor = 0.9 + ls_lag_shockCapturing = True + ls_sc_uref = 1.0 + ls_sc_beta = 1.0 + vof_shockCapturingFactor = 0.9 + vof_lag_shockCapturing = True + vof_sc_uref = 1.0 + vof_sc_beta = 1.0 + rd_shockCapturingFactor = 0.9 + rd_lag_shockCapturing = False + epsFact_density = 1.5 + epsFact_viscosity = epsFact_curvature = epsFact_vof = epsFact_consrv_heaviside = epsFact_consrv_dirac = epsFact_density + epsFact_redistance = 0.33 + epsFact_consrv_diffusion = 10.0 + redist_Newton = False + kappa_shockCapturingFactor = 0.9 + kappa_lag_shockCapturing = True#False + kappa_sc_uref = 1.0 + kappa_sc_beta = 1.0 + dissipation_shockCapturingFactor = 0.9 + dissipation_lag_shockCapturing = True#False + dissipation_sc_uref = 1.0 + dissipation_sc_beta = 1.0 + +ns_nl_atol_res = max(1.0e-10,0.0001*he**2) +vof_nl_atol_res = max(1.0e-10,0.0001*he**2) +ls_nl_atol_res = max(1.0e-10,0.0001*he**2) +rd_nl_atol_res = max(1.0e-10,0.005*he) +mcorr_nl_atol_res = max(1.0e-10,0.0001*he**2) +kappa_nl_atol_res = max(1.0e-10,0.001*he**2) +dissipation_nl_atol_res = max(1.0e-10,0.001*he**2) + +#turbulence +ns_closure=2 #1-classic smagorinsky, 2-dynamic smagorinsky, 3 -- k-epsilon, 4 -- k-omega +if useRANS == 1: + ns_closure = 3 +elif useRANS == 2: + ns_closure == 4 +# Water +rho_0 = 998.2 +nu_0 = 1.004e-6 + +# Air +rho_1 = 1.205 +nu_1 = 1.500e-5 + +# Surface tension +sigma_01 = 0.0 + +# Gravity +g = [0.0,-9.8] + +# Initial condition +waterLine_x = 2*L[0] +waterLine_z = inflowHeightMean + + +def signedDistance(x): + phi_x = x[0]-waterLine_x + phi_z = x[1]-waterLine_z + if phi_x < 0.0: + if phi_z < 0.0: + return max(phi_x,phi_z) + else: + return phi_z + else: + if phi_z < 0.0: + return phi_x + else: + return sqrt(phi_x**2 + phi_z**2) + + +def theta(x,t): + return k*x[0] - omega*t + pi/2.0 + +def z(x): + return x[1] - inflowHeightMean + +#sigma = omega - k*inflowVelocityMean[0] +h = inflowHeightMean # - transect[0][1] if lower left hand corner is not at z=0 + +#waveData + +def waveHeight(x,t): + return inflowHeightMean + waves.eta(x[0],x[1],x[2],t) +def waveVelocity_u(x,t): + return waves.u(x[0],x[1],x[2],t,"x") +def waveVelocity_v(x,t): + return waves.u(x[0],x[1],x[2],t,"y") +def waveVelocity_w(x,t): + return waves.u(x[0],x[1],x[2],t,"z") + + +#solution variables + +def wavePhi(x,t): + return x[1] - waveHeight(x,t) + +def waveVF(x,t): + return smoothedHeaviside(epsFact_consrv_heaviside*he,wavePhi(x,t)) + +def twpflowVelocity_u(x,t): + waterspeed = waveVelocity_u(x,t) + H = smoothedHeaviside(epsFact_consrv_heaviside*he,wavePhi(x,t)-epsFact_consrv_heaviside*he) + u = H*windVelocity[0] + (1.0-H)*waterspeed + return u + +def twpflowVelocity_v(x,t): + waterspeed = waveVelocity_v(x,t) + H = smoothedHeaviside(epsFact_consrv_heaviside*he,wavePhi(x,t)-epsFact_consrv_heaviside*he) + return H*windVelocity[1]+(1.0-H)*waterspeed + +def twpflowFlux(x,t): + return -twpflowVelocity_u(x,t) + +outflowHeight=inflowHeightMean + +def outflowVF(x,t): + return smoothedHeaviside(epsFact_consrv_heaviside*he,x[1] - outflowHeight) + +def outflowPhi(x,t): + return x[1] - outflowHeight + +def outflowPressure(x,t): + if x[1]>inflowHeightMean: + return (L[1]-x[1])*rho_1*abs(g[1]) + else: + return (L[1]-inflowHeightMean)*rho_1*abs(g[1])+(inflowHeightMean-x[1])*rho_0*abs(g[1]) + + + #p_L = L[1]*rho_1*g[1] + #phi_L = L[1] - outflowHeight + #phi = x[1] - outflowHeight + #return p_L -g[1]*(rho_0*(phi_L - phi)+(rho_1 -rho_0)*(smoothedHeaviside_integral(epsFact_consrv_heaviside*he,phi_L) + # -smoothedHeaviside_integral(epsFact_consrv_heaviside*he,phi))) + +def twpflowVelocity_w(x,t): + return 0.0 + +def zeroVel(x,t): + return 0.0 + +from collections import namedtuple + + +def zeroVel(x,t): + return 0.0 + +from collections import namedtuple + +RelaxationZone = namedtuple("RelaxationZone","center_x sign u v w") + +class RelaxationZoneWaveGenerator(AV_base): + """ Prescribe a velocity penalty scaling in a material zone via a Darcy-Forchheimer penalty + + :param zones: A dictionary mapping integer material types to Zones, where a Zone is a named tuple + specifying the x coordinate of the zone center and the velocity components + """ + def __init__(self,zones): + assert isinstance(zones,dict) + self.zones = zones + def calculate(self): + for l,m in enumerate(self.model.levelModelList): + for eN in range(m.coefficients.q_phi.shape[0]): + mType = m.mesh.elementMaterialTypes[eN] + if self.zones.has_key(mType): + for k in range(m.coefficients.q_phi.shape[1]): + t = m.timeIntegration.t + x = m.q['x'][eN,k] + m.coefficients.q_phi_solid[eN,k] = self.zones[mType].sign*(self.zones[mType].center_x - x[0]) + m.coefficients.q_velocity_solid[eN,k,0] = self.zones[mType].u(x,t) + m.coefficients.q_velocity_solid[eN,k,1] = self.zones[mType].v(x,t) + #m.coefficients.q_velocity_solid[eN,k,2] = self.zones[mType].w(x,t) + m.q['phi_solid'] = m.coefficients.q_phi_solid + m.q['velocity_solid'] = m.coefficients.q_velocity_solid + +rzWaveGenerator = RelaxationZoneWaveGenerator(zones={ + # 1:RelaxationZone(xRelaxCenter, + # 1.0, + # twpflowVelocity_u, + # twpflowVelocity_v, + # twpflowVelocity_w), + 1:RelaxationZone(xRelaxCenter_2, + 1.0, #currently Hs=1-exp_function + zeroVel, + zeroVel, + zeroVel)}) diff --git a/2d/waves_vegetation/tank_batch.py b/2d/waves_vegetation/tank_batch.py new file mode 100644 index 00000000..38fabd1d --- /dev/null +++ b/2d/waves_vegetation/tank_batch.py @@ -0,0 +1,4 @@ +simFlagsList[0]['storeQuantities']= ["q:'phi_solid'","q:'velocity_solid'"] +#simFlagsList[0]['storeQuantities']= ["q:velocity_solid"] +start +quit diff --git a/2d/waves_vegetation/tank_so.py b/2d/waves_vegetation/tank_so.py new file mode 100644 index 00000000..93429780 --- /dev/null +++ b/2d/waves_vegetation/tank_so.py @@ -0,0 +1,32 @@ +from proteus.default_so import * +import tank + +if tank.useOnlyVF: + pnList = [("twp_navier_stokes_p", "twp_navier_stokes_n"), + ("vof_p", "vof_n")] +else: + pnList = [("twp_navier_stokes_p", "twp_navier_stokes_n"), + ("vof_p", "vof_n"), + ("ls_p", "ls_n"), + ("redist_p", "redist_n"), + ("ls_consrv_p", "ls_consrv_n")] + + +if tank.useRANS > 0: + pnList.append(("kappa_p", + "kappa_n")) + pnList.append(("dissipation_p", + "dissipation_n")) +name = "tank_p" + +if tank.timeDiscretization == 'flcbdf': + systemStepControllerType = Sequential_MinFLCBDFModelStep + systemStepControllerType = Sequential_MinAdaptiveModelStep +else: + systemStepControllerType = Sequential_MinAdaptiveModelStep + +needEBQ_GLOBAL = False +needEBQ = False + +tnList = [0.0,tank.dt_init]+[i*tank.dt_fixed for i in range(1,tank.nDTout+1)] +archiveFlag = ArchiveFlags.EVERY_SEQUENCE_STEP diff --git a/2d/waves_vegetation/twp_navier_stokes_n.py b/2d/waves_vegetation/twp_navier_stokes_n.py new file mode 100644 index 00000000..9bee78a0 --- /dev/null +++ b/2d/waves_vegetation/twp_navier_stokes_n.py @@ -0,0 +1,67 @@ +from proteus import * +from twp_navier_stokes_p import * +from tank import * + +if timeDiscretization=='vbdf': + timeIntegration = VBDF + timeOrder=2 + stepController = Min_dt_cfl_controller +elif timeDiscretization=='flcbdf': + timeIntegration = FLCBDF + #stepController = FLCBDF_controller_sys + stepController = Min_dt_cfl_controller + time_tol = 10.0*ns_nl_atol_res + atol_u = {1:time_tol,2:time_tol} + rtol_u = {1:time_tol,2:time_tol} +else: + timeIntegration = BackwardEuler_cfl + stepController = Min_dt_cfl_controller + +femSpaces = {0:basis, + 1:basis, + 2:basis} + +massLumping = False +numericalFluxType = None +conservativeFlux = None + +numericalFluxType = RANS2P.NumericalFlux +subgridError = RANS2P.SubgridError(coefficients,nd,lag=ns_lag_subgridError,hFactor=hFactor) +shockCapturing = RANS2P.ShockCapturing(coefficients,nd,ns_shockCapturingFactor,lag=ns_lag_shockCapturing) + +fullNewtonFlag = True +multilevelNonlinearSolver = Newton +levelNonlinearSolver = Newton + +nonlinearSmoother = None + +linearSmoother = SimpleNavierStokes2D + +matrix = SparseMatrix + +if useOldPETSc: + multilevelLinearSolver = PETSc + levelLinearSolver = PETSc +else: + multilevelLinearSolver = KSP_petsc4py + levelLinearSolver = KSP_petsc4py + +if useSuperlu: + multilevelLinearSolver = LU + levelLinearSolver = LU + +linear_solver_options_prefix = 'rans2p_' +nonlinearSolverConvergenceTest = 'r' +levelNonlinearSolverConvergenceTest = 'r' +linearSolverConvergenceTest = 'r-true' + +tolFac = 0.0 +linTolFac = 0.01 +l_atol_res = 0.01*ns_nl_atol_res +nl_atol_res = ns_nl_atol_res +useEisenstatWalker = False +maxNonlinearIts = 50 +maxLineSearches = 0 +conservativeFlux = {0:'pwl-bdm-opt'} + +auxiliaryVariables=[pointGauges,rzWaveGenerator] diff --git a/2d/waves_vegetation/twp_navier_stokes_p.py b/2d/waves_vegetation/twp_navier_stokes_p.py new file mode 100644 index 00000000..600d84fc --- /dev/null +++ b/2d/waves_vegetation/twp_navier_stokes_p.py @@ -0,0 +1,141 @@ +from proteus import * +from proteus.default_p import * +from tank import * +from proteus.mprans import RANS2P + +LevelModelType = RANS2P.LevelModel +if useOnlyVF: + LS_model = None +else: + LS_model = 2 +if useRANS >= 1: + Closure_0_model = 5; Closure_1_model=6 + if useOnlyVF: + Closure_0_model=2; Closure_1_model=3 + if movingDomain: + Closure_0_model += 1; Closure_1_model += 1 +else: + Closure_0_model = None + Closure_1_model = None + +if spongeLayer or levee or slopingSpongeLayer: + coefficients = RANS2P.Coefficients(epsFact=epsFact_viscosity, + sigma=0.0, + rho_0 = rho_0, + nu_0 = nu_0, + rho_1 = rho_1, + nu_1 = nu_1, + g=g, + nd=nd, + VF_model=1, + LS_model=LS_model, + Closure_0_model=Closure_0_model, + Closure_1_model=Closure_1_model, + epsFact_density=epsFact_density, + stokes=False, + useVF=useVF, + useRBLES=useRBLES, + useMetrics=useMetrics, + eb_adjoint_sigma=1.0, + eb_penalty_constant=weak_bc_penalty_constant, + forceStrongDirichlet=ns_forceStrongDirichlet, + turbulenceClosureModel=ns_closure, + movingDomain=movingDomain, + porosityTypes=porosityTypes, + dragAlphaTypes=dragAlphaTypes, + dragBetaTypes=dragBetaTypes, + epsFact_solid = epsFact_solidTypes) +else: + coefficients = RANS2P.Coefficients(epsFact=epsFact_viscosity, + sigma=0.0, + rho_0 = rho_0, + nu_0 = nu_0, + rho_1 = rho_1, + nu_1 = nu_1, + g=g, + nd=nd, + VF_model=1, + LS_model=LS_model, + Closure_0_model=Closure_0_model, + Closure_1_model=Closure_1_model, + epsFact_density=epsFact_density, + stokes=False, + useVF=useVF, + useRBLES=useRBLES, + useMetrics=useMetrics, + eb_adjoint_sigma=1.0, + eb_penalty_constant=weak_bc_penalty_constant, + forceStrongDirichlet=ns_forceStrongDirichlet, + turbulenceClosureModel=ns_closure, + movingDomain=movingDomain) + +def getDBC_p(x,flag): + if flag == boundaryTags['top']: + return lambda x,t: 0.0 +# elif flag == boundaryTags['right']: +# return outflowPressure + +def getDBC_u(x,flag): + if flag == boundaryTags['left']: + return twpflowVelocity_u +# elif flag == boundaryTags['right']: +# return lambda x,t: 0.0 + +def getDBC_v(x,flag): + if flag == boundaryTags['left']: + return twpflowVelocity_v +# elif flag == boundaryTags['right']: +# return lambda x,t: 0.0 + +dirichletConditions = {0:getDBC_p, + 1:getDBC_u, + 2:getDBC_v} + +def getAFBC_p(x,flag): + if flag == boundaryTags['left']: + return lambda x,t: -twpflowVelocity_u(x,t) + elif flag == boundaryTags['bottom'] or flag == boundaryTags['right']: + return lambda x,t: 0.0 + +def getAFBC_u(x,flag): + if flag == boundaryTags['bottom'] or flag == boundaryTags['right']: + return lambda x,t: 0.0 + +def getAFBC_v(x,flag): + if flag == boundaryTags['bottom'] or flag == boundaryTags['right']: + return lambda x,t: 0.0 + +def getDFBC_u(x,flag): + if flag != boundaryTags['left']: + return lambda x,t: 0.0 + +def getDFBC_v(x,flag): + if flag != boundaryTags['left']: + return lambda x,t: 0.0 + +advectiveFluxBoundaryConditions = {0:getAFBC_p, + 1:getAFBC_u, + 2:getAFBC_v} + +diffusiveFluxBoundaryConditions = {0:{}, + 1:{1:getDFBC_u}, + 2:{2:getDFBC_v}} + +class PerturbedSurface_p: + def __init__(self,waterLevel): + self.waterLevel=waterLevel + def uOfXT(self,x,t): + if signedDistance(x) < 0: + return -(L[1] - self.waterLevel)*rho_1*g[1] - (self.waterLevel - x[1])*rho_0*g[1] + else: + return -(L[1] - self.waterLevel)*rho_1*g[1] + +class AtRest: + def __init__(self): + pass + def uOfXT(self,x,t): + return 0.0 + +initialConditions = {0:PerturbedSurface_p(waterLine_z), + 1:AtRest(), + 2:AtRest()} diff --git a/2d/waves_vegetation/vof_n.py b/2d/waves_vegetation/vof_n.py new file mode 100644 index 00000000..8862cd13 --- /dev/null +++ b/2d/waves_vegetation/vof_n.py @@ -0,0 +1,64 @@ +from proteus import * +from tank import * +from vof_p import * + +if timeDiscretization=='vbdf': + timeIntegration = VBDF + timeOrder=2 + stepController = Min_dt_cfl_controller +elif timeDiscretization=='flcbdf': + timeIntegration = FLCBDF + #stepController = FLCBDF_controller + stepController = Min_dt_cfl_controller + time_tol = 10.0*vof_nl_atol_res + atol_u = {0:time_tol} + rtol_u = {0:time_tol} +else: + timeIntegration = BackwardEuler_cfl + stepController = Min_dt_cfl_controller + +femSpaces = {0:basis} + +massLumping = False +numericalFluxType = VOF.NumericalFlux +conservativeFlux = None +subgridError = VOF.SubgridError(coefficients=coefficients,nd=nd) +shockCapturing = VOF.ShockCapturing(coefficients,nd,shockCapturingFactor=vof_shockCapturingFactor,lag=vof_lag_shockCapturing) + +fullNewtonFlag = True +multilevelNonlinearSolver = Newton +levelNonlinearSolver = Newton + +nonlinearSmoother = None +linearSmoother = None + +matrix = SparseMatrix + +if useOldPETSc: + multilevelLinearSolver = PETSc + levelLinearSolver = PETSc +else: + multilevelLinearSolver = KSP_petsc4py + levelLinearSolver = KSP_petsc4py + +if useSuperlu: + multilevelLinearSolver = LU + levelLinearSolver = LU + +linear_solver_options_prefix = 'vof_' +nonlinearSolverConvergenceTest = 'r' +levelNonlinearSolverConvergenceTest = 'r' +linearSolverConvergenceTest = 'r-true' + +tolFac = 0.0 +nl_atol_res = vof_nl_atol_res + +linTolFac = 0.0 +l_atol_res = 0.1*vof_nl_atol_res + +useEisenstatWalker = False + +maxNonlinearIts = 50 +maxLineSearches = 0 + +auxiliaryVariables = [columnGauge] diff --git a/2d/waves_vegetation/vof_p.py b/2d/waves_vegetation/vof_p.py new file mode 100644 index 00000000..94965ec8 --- /dev/null +++ b/2d/waves_vegetation/vof_p.py @@ -0,0 +1,46 @@ +from proteus import * +from proteus.default_p import * +from proteus.ctransportCoefficients import smoothedHeaviside +from tank import * +from proteus.mprans import VOF + +LevelModelType = VOF.LevelModel +if useOnlyVF: + RD_model = None + LS_model = None +else: + RD_model = 3 + LS_model = 2 + +coefficients = VOF.Coefficients(LS_model=LS_model,V_model=0,RD_model=RD_model,ME_model=1, + checkMass=False,useMetrics=useMetrics, + epsFact=epsFact_vof,sc_uref=vof_sc_uref,sc_beta=vof_sc_beta,movingDomain=movingDomain) + +def getDBC_vof(x,flag): + if flag == boundaryTags['left']: + return waveVF + elif flag == boundaryTags['top']:# or x[1] >= L[1] - 1.0e-12: + return lambda x,t: 1.0 +# elif flag == boundaryTags['right']: +# return outflowVF + +dirichletConditions = {0:getDBC_vof} + +def getAFBC_vof(x,flag): + if flag == boundaryTags['left']: + return None + elif flag == boundaryTags['top']:# or x[1] >= L[1] - 1.0e-12: + return None + # elif flag == boundaryTags['right']: + # return None + else: + return lambda x,t: 0.0 + +advectiveFluxBoundaryConditions = {0:getAFBC_vof} +diffusiveFluxBoundaryConditions = {0:{}} + +class PerturbedSurface_H: + def uOfXT(self,x,t): + return smoothedHeaviside(epsFact_consrv_heaviside*he,signedDistance(x)) + +initialConditions = {0:PerturbedSurface_H()} From 918b638cb985015d2572cd7957ebf6decf52f439 Mon Sep 17 00:00:00 2001 From: cekees Date: Tue, 2 Jun 2015 10:11:02 -0500 Subject: [PATCH 02/20] updated geometry, still needs work --- 2d/waves_vegetation/tank.py | 40 +++++++++++----------- 2d/waves_vegetation/twp_navier_stokes_n.py | 2 +- 2d/waves_vegetation/vof_n.py | 2 +- 3 files changed, 22 insertions(+), 22 deletions(-) diff --git a/2d/waves_vegetation/tank.py b/2d/waves_vegetation/tank.py index 133278cb..4e05fe19 100644 --- a/2d/waves_vegetation/tank.py +++ b/2d/waves_vegetation/tank.py @@ -94,7 +94,7 @@ #for debugging, make the tank short L = (45.4,1.0) -he = float(wavelength)/20.0#100 +he = float(wavelength)/2#0.0#100 GenerationZoneLength = wavelength AbsorptionZoneLength= wavelength*2.0 @@ -127,19 +127,19 @@ columnLines=tuple(map(tuple,LGL)) -pointGauges = PointGauges(gauges=((('u','v'), gaugeLocations), - (('p',), gaugeLocations)), - activeTime = (0, 1000.0), - sampleRate = 0, - fileName = 'combined_gauge_0_0.5_sample_all.txt') +#pointGauges = PointGauges(gauges=((('u','v'), gaugeLocations), +# (('p',), gaugeLocations)), +# activeTime = (0, 1000.0), +# sampleRate = 0, +# fileName = 'combined_gauge_0_0.5_sample_all.txt') -print gaugeLocations -print columnLines +#print gaugeLocations +#print columnLines fields = ('vof',) -columnGauge = LineIntegralGauges(gauges=((fields, columnLines),), - fileName='column_gauge.csv') +#columnGauge = LineIntegralGauges(gauges=((fields, columnLines),), +# fileName='column_gauge.csv') #lineGauges = LineGauges(gaugeEndpoints={'lineGauge_y=0':((0.0,0.0,0.0),(L[0],0.0,0.0))},linePoints=24) @@ -158,15 +158,15 @@ nnx=ceil(L[0]/he)+1 nny=ceil(L[1]/he)+1 elif spongeLayer: - vertices=[[0.0,0.0],#0 - [19.6, 19.6/44.0 ],#1 - [19.6+6.1, 19.6/44.0+6.1/20.0],#2 - [19.6+6.1+1.2, 19.6/44.0+6.1/20.0],#3 - [19.6+6.1+1.2+9.8, 19.6/44.0+6.1/20.0],#4 - [19.6+6.1+1.2+9.8+1.2, 19.6/44.0+6.1/20.0],#5 - [37.9, 19.5/44.0+6.1/20.0],#6 - [45.4, 19.5/44.0+11.3/20.0],#7 - [37.9, 19.5/44.0+11.3/20.0],#8 + vertices=[[0.0, 0.0 ],#0 + [19.6, 19.6/44.0 ],#1 + [19.6+6.1, 19.6/44.0+6.1/20.0 ],#2 + [19.6+6.1+1.2, 19.6/44.0+6.1/20.0 ],#3 + [19.6+6.1+1.2+9.8, 19.6/44.0+6.1/20.0 ],#4 + [19.6+6.1+1.2+9.8+1.2, 19.6/44.0+6.1/20.0 ],#5 + [37.9, 19.5/44.0+6.1/20.0 ],#6 + [45.4, 19.5/44.0+11.3/20.0 ],#7 + [37.9, 19.5/44.0+11.3/20.0 ],#8 [0.0, 19.5/44.0+11.3/20.0]]#9 vertexFlags=[boundaryTags['bottom'],#0 @@ -189,7 +189,7 @@ [7,8],#7 [8,9],#8 [9,0],#9 - [7,0]]#10 + [6,8]]#10 segmentFlags=[boundaryTags['bottom'],#0 boundaryTags['bottom'],#1 diff --git a/2d/waves_vegetation/twp_navier_stokes_n.py b/2d/waves_vegetation/twp_navier_stokes_n.py index 9bee78a0..aa449142 100644 --- a/2d/waves_vegetation/twp_navier_stokes_n.py +++ b/2d/waves_vegetation/twp_navier_stokes_n.py @@ -64,4 +64,4 @@ maxLineSearches = 0 conservativeFlux = {0:'pwl-bdm-opt'} -auxiliaryVariables=[pointGauges,rzWaveGenerator] +#auxiliaryVariables=[pointGauges,rzWaveGenerator] diff --git a/2d/waves_vegetation/vof_n.py b/2d/waves_vegetation/vof_n.py index 8862cd13..ce3fbe34 100644 --- a/2d/waves_vegetation/vof_n.py +++ b/2d/waves_vegetation/vof_n.py @@ -61,4 +61,4 @@ maxNonlinearIts = 50 maxLineSearches = 0 -auxiliaryVariables = [columnGauge] +#auxiliaryVariables = [columnGauge] From 74b52bbd032ec90e79ad1f64511dab854004f1d1 Mon Sep 17 00:00:00 2001 From: cekees Date: Tue, 2 Jun 2015 16:09:06 -0500 Subject: [PATCH 03/20] inputs to petsc --- inputTemplates/petsc.options.superlu_dist | 1 + 1 file changed, 1 insertion(+) diff --git a/inputTemplates/petsc.options.superlu_dist b/inputTemplates/petsc.options.superlu_dist index a14e35cf..1d7081cd 100644 --- a/inputTemplates/petsc.options.superlu_dist +++ b/inputTemplates/petsc.options.superlu_dist @@ -5,4 +5,5 @@ -mcorr_ksp_type preonly -mcorr_pc_type lu -mcorr_pc_factor_mat_solver_package superlu_dist -kappa_ksp_type preonly -kappa_pc_type lu -kappa_pc_factor_mat_solver_package superlu_dist -dissipation_ksp_type preonly -dissipation_pc_type lu -dissipation_pc_factor_mat_solver_package superlu_dist +-mesh_ksp_type preonly -mesh_pc_type lu -mesh_pc_factor_mat_solver_package superlu_dist From 5d734f1c94f77ed63a91f1072f2a407f05ba8f45 Mon Sep 17 00:00:00 2001 From: cekees Date: Tue, 6 Oct 2015 18:05:29 -0500 Subject: [PATCH 04/20] fixed some issues with tank geometry --- 2d/waves_vegetation/tank.py | 55 ++++++++++++--------- 2d/waves_vegetation/tank_so.py | 10 ++-- 2d/waves_vegetation/twp_navier_stokes_n.py | 2 +- 2d/waves_vegetation/twp_navier_stokes_p.py | 12 ++--- doc/source/chl.png | Bin 174928 -> 131 bytes doc/source/hrw.png | Bin 10648 -> 130 bytes 6 files changed, 43 insertions(+), 36 deletions(-) diff --git a/2d/waves_vegetation/tank.py b/2d/waves_vegetation/tank.py index 4e05fe19..e0b18f85 100644 --- a/2d/waves_vegetation/tank.py +++ b/2d/waves_vegetation/tank.py @@ -12,14 +12,14 @@ #wave generator windVelocity = (0.0,0.0) -depth = 1.0 -inflowHeightMean = 1.0 +depth = 19.6/44.0+6.1/20.0 + 0.457 +inflowHeightMean = 19.6/44.0+6.1/20.0 + 0.457 inflowVelocityMean = (0.0,0.0) -period = 1.134 +period = 2.0 omega = 2.0*math.pi/period -waveheight = 0.05 +waveheight = 0.192 amplitude = waveheight/ 2.0 -wavelength = 1.5 +wavelength = 3.91 k = 2.0*math.pi/wavelength waveDir = numpy.array([1,0,0]) g = numpy.array([0,-9.81,0]) @@ -34,6 +34,13 @@ g = g, # Gravity vector, defines the vertical gamma=3.3, spec_fun = WT.JONSWAP) +waves = WT.MonochromaticWaves( period = period, # Peak period + waveHeight = waveheight, # Height + depth = depth, # Depth + mwl = inflowHeightMean, # Sea water level + waveDir = waveDir, # waveDirection + g = g, # Gravity vector, defines the vertical + waveType="Linear") @@ -42,7 +49,7 @@ movingDomain=False applyRedistancing=True useOldPETSc=False -useSuperlu=False +useSuperlu=True timeDiscretization='be'#'be','vbdf','flcbdf' spaceOrder = 1 useHex = False @@ -94,7 +101,7 @@ #for debugging, make the tank short L = (45.4,1.0) -he = float(wavelength)/2#0.0#100 +he = float(wavelength)/50.0#0.0#100 GenerationZoneLength = wavelength AbsorptionZoneLength= wavelength*2.0 @@ -164,10 +171,10 @@ [19.6+6.1+1.2, 19.6/44.0+6.1/20.0 ],#3 [19.6+6.1+1.2+9.8, 19.6/44.0+6.1/20.0 ],#4 [19.6+6.1+1.2+9.8+1.2, 19.6/44.0+6.1/20.0 ],#5 - [37.9, 19.5/44.0+6.1/20.0 ],#6 - [45.4, 19.5/44.0+11.3/20.0 ],#7 - [37.9, 19.5/44.0+11.3/20.0 ],#8 - [0.0, 19.5/44.0+11.3/20.0]]#9 + [45.4, 19.6/44.0+11.3/20.0 ],#6 + [45.4, 19.6/44.0+11.3/20.0 +1.0],#7 + [37.9, 19.6/44.0+11.3/20.0 +1.0],#8 + [0.0, 19.6/44.0+11.3/20.0 +1.0]]#9 vertexFlags=[boundaryTags['bottom'],#0 boundaryTags['bottom'],#1 @@ -176,7 +183,7 @@ boundaryTags['bottom'],#4 boundaryTags['bottom'],#5 boundaryTags['bottom'],#6 - boundaryTags['bottom'],#7 + boundaryTags['top'],#7 boundaryTags['top'],#8 boundaryTags['top']]#9 segments=[[0,1],#0 @@ -189,7 +196,7 @@ [7,8],#7 [8,9],#8 [9,0],#9 - [6,8]]#10 + [5,8]]#10 segmentFlags=[boundaryTags['bottom'],#0 boundaryTags['bottom'],#1 @@ -197,7 +204,7 @@ boundaryTags['bottom'],#3 boundaryTags['bottom'],#4 boundaryTags['bottom'],#5 - boundaryTags['bottom'],#6 + boundaryTags['right'],#6 boundaryTags['top'],#7 boundaryTags['top'],#8 boundaryTags['left'],#9 @@ -218,7 +225,7 @@ domain.writeAsymptote("mesh") triangleOptions="VApq30Dena%8.8f" % ((he**2)/2.0,) - logEvent("""Mesh generated using: tetgen -%s %s""" % (triangleOptions,domain.polyfile+".poly")) + logEvent("""Mesh generated using: triangle -%s %s""" % (triangleOptions,domain.polyfile+".poly")) porosityTypes = numpy.array([1.0, 1.0, @@ -267,12 +274,12 @@ domain.writeAsymptote("mesh") triangleOptions="VApq30Dena%8.8f" % ((he**2)/2.0,) - logEvent("""Mesh generated using: tetgen -%s %s""" % (triangleOptions,domain.polyfile+".poly")) + logEvent("""Mesh generated using: triangle -%s %s""" % (triangleOptions,domain.polyfile+".poly")) # Time stepping T=40*period -dt_fixed = T#2.0*0.5/20.0#T/2.0#period/21.0 -dt_init = min(0.1*dt_fixed,0.1) -runCFL=0.9 +dt_fixed = period/11.0#2.0*0.5/20.0#T/2.0#period/21.0 +dt_init = min(0.001*dt_fixed,0.001) +runCFL=0.90 nDTout = int(round(T/dt_fixed)) # Numerical parameters @@ -282,21 +289,21 @@ ns_shockCapturingFactor = 0.25 ns_lag_shockCapturing = True ns_lag_subgridError = True - ls_shockCapturingFactor = 0.35 + ls_shockCapturingFactor = 0.25 ls_lag_shockCapturing = True ls_sc_uref = 1.0 ls_sc_beta = 1.0 - vof_shockCapturingFactor = 0.35 + vof_shockCapturingFactor = 0.25 vof_lag_shockCapturing = True vof_sc_uref = 1.0 vof_sc_beta = 1.0 - rd_shockCapturingFactor = 0.75 + rd_shockCapturingFactor = 0.25 rd_lag_shockCapturing = False epsFact_density = 3.0 epsFact_viscosity = epsFact_curvature = epsFact_vof = epsFact_consrv_heaviside = epsFact_consrv_dirac = epsFact_density epsFact_redistance = 1.5 epsFact_consrv_diffusion = 10.0 - redist_Newton = True + redist_Newton = False kappa_shockCapturingFactor = 0.1 kappa_lag_shockCapturing = True#False kappa_sc_uref = 1.0 @@ -342,7 +349,7 @@ dissipation_nl_atol_res = max(1.0e-10,0.001*he**2) #turbulence -ns_closure=2 #1-classic smagorinsky, 2-dynamic smagorinsky, 3 -- k-epsilon, 4 -- k-omega +ns_closure=0 #1-classic smagorinsky, 2-dynamic smagorinsky, 3 -- k-epsilon, 4 -- k-omega if useRANS == 1: ns_closure = 3 elif useRANS == 2: diff --git a/2d/waves_vegetation/tank_so.py b/2d/waves_vegetation/tank_so.py index 93429780..bf9f914f 100644 --- a/2d/waves_vegetation/tank_so.py +++ b/2d/waves_vegetation/tank_so.py @@ -10,14 +10,14 @@ ("ls_p", "ls_n"), ("redist_p", "redist_n"), ("ls_consrv_p", "ls_consrv_n")] - - + + if tank.useRANS > 0: pnList.append(("kappa_p", "kappa_n")) pnList.append(("dissipation_p", "dissipation_n")) -name = "tank_p" +name = "tank_p" if tank.timeDiscretization == 'flcbdf': systemStepControllerType = Sequential_MinFLCBDFModelStep @@ -28,5 +28,5 @@ needEBQ_GLOBAL = False needEBQ = False -tnList = [0.0,tank.dt_init]+[i*tank.dt_fixed for i in range(1,tank.nDTout+1)] -archiveFlag = ArchiveFlags.EVERY_SEQUENCE_STEP +tnList = [0.0,tank.dt_init]+[i*tank.dt_fixed for i in range(1,tank.nDTout+1)] +archiveFlag = ArchiveFlags.EVERY_USER_STEP diff --git a/2d/waves_vegetation/twp_navier_stokes_n.py b/2d/waves_vegetation/twp_navier_stokes_n.py index aa449142..c339d98c 100644 --- a/2d/waves_vegetation/twp_navier_stokes_n.py +++ b/2d/waves_vegetation/twp_navier_stokes_n.py @@ -35,7 +35,7 @@ nonlinearSmoother = None -linearSmoother = SimpleNavierStokes2D +#linearSmoother = SimpleNavierStokes2D matrix = SparseMatrix diff --git a/2d/waves_vegetation/twp_navier_stokes_p.py b/2d/waves_vegetation/twp_navier_stokes_p.py index 600d84fc..76cb66ad 100644 --- a/2d/waves_vegetation/twp_navier_stokes_p.py +++ b/2d/waves_vegetation/twp_navier_stokes_p.py @@ -74,7 +74,7 @@ def getDBC_p(x,flag): return lambda x,t: 0.0 # elif flag == boundaryTags['right']: # return outflowPressure - + def getDBC_u(x,flag): if flag == boundaryTags['left']: return twpflowVelocity_u @@ -93,22 +93,22 @@ def getDBC_v(x,flag): def getAFBC_p(x,flag): if flag == boundaryTags['left']: - return lambda x,t: -twpflowVelocity_u(x,t) + return twpflowFlux elif flag == boundaryTags['bottom'] or flag == boundaryTags['right']: return lambda x,t: 0.0 - + def getAFBC_u(x,flag): if flag == boundaryTags['bottom'] or flag == boundaryTags['right']: return lambda x,t: 0.0 - + def getAFBC_v(x,flag): if flag == boundaryTags['bottom'] or flag == boundaryTags['right']: return lambda x,t: 0.0 - + def getDFBC_u(x,flag): if flag != boundaryTags['left']: return lambda x,t: 0.0 - + def getDFBC_v(x,flag): if flag != boundaryTags['left']: return lambda x,t: 0.0 diff --git a/doc/source/chl.png b/doc/source/chl.png index 3f4fad58ffc61c0195e05e8efddef250276f7f0c..5d51c44e516d4eef7a7b8f852042409f623b0eb1 100644 GIT binary patch literal 131 zcmWN?NfN>!5CFhCuiyiQVVQyCH!OotrIHfN!PjeF`r`NO<0ac#=RB0U_jP;Jx&3dS zwB_+s^W>~9Ek-YLwrG$Jzw1l@H9F?yj=aiCqmAAxDd3DwcrJ5;-VL$uq=A NLCpSTslD4x5I+h7C!zoV literal 174928 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

6{PPuSRDXVmw|_y<A6?g7>)my(xdAp{2EpQK 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%0A4k{)JEX47jYtLh8M=9pRF9c9zT8(};j^lwgMm5; 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

-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 ja&-eZIl`$)$$aEs!5CFh?UcmVfg|Oswigw literal 10648 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 From ee04bd6c110883456f8339b4a6dd2b251bab9f79 Mon Sep 17 00:00:00 2001 From: cekees Date: Tue, 6 Oct 2015 18:19:45 -0500 Subject: [PATCH 05/20] changed coefficients of sponge layer --- 2d/waves_vegetation/tank.py | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/2d/waves_vegetation/tank.py b/2d/waves_vegetation/tank.py index e0b18f85..2f404639 100644 --- a/2d/waves_vegetation/tank.py +++ b/2d/waves_vegetation/tank.py @@ -104,14 +104,14 @@ he = float(wavelength)/50.0#0.0#100 GenerationZoneLength = wavelength -AbsorptionZoneLength= wavelength*2.0 +AbsorptionZoneLength= 45.4-37.9 spongeLayer = True xSponge = GenerationZoneLength xRelaxCenter = xSponge/2.0 epsFact_solid = xSponge/2.0 #zone 2 -xSponge_2 = L[0]-AbsorptionZoneLength -xRelaxCenter_2 = 0.5*(xSponge_2+L[0]) +xSponge_2 = 37.9 +xRelaxCenter_2 = 0.5*(37.9+45.4) epsFact_solid_2 = AbsorptionZoneLength/2.0 weak_bc_penalty_constant = 100.0 @@ -228,15 +228,13 @@ logEvent("""Mesh generated using: triangle -%s %s""" % (triangleOptions,domain.polyfile+".poly")) porosityTypes = numpy.array([1.0, 1.0, - 1.0]) dragAlphaTypes = numpy.array([0.0, - 0.5/1.004e-6, - - 0.0]) + 0.0, + 0.5/1.004e-6]) dragBetaTypes = numpy.array([0.0,0.0,0.0]) - epsFact_solidTypes = np.array([0.0,epsFact_solid_2,0.0]) + epsFact_solidTypes = np.array([0.0,0.0,epsFact_solid_2]) else: vertices=[[0.0,0.0],#0 From def9111fe65004515fa9add1f12c57dcbf597cd1 Mon Sep 17 00:00:00 2001 From: Steve Mattis Date: Wed, 7 Oct 2015 14:16:46 -0500 Subject: [PATCH 06/20] adds 3d wavetank from time series problem --- .../generate_monochromatic_linear.py | 30 + .../ls_consrv_n.py | 48 ++ .../ls_consrv_p.py | 26 + .../wavetank_vegetation_time_series/ls_n.py | 63 ++ .../wavetank_vegetation_time_series/ls_p.py | 29 + .../redist_n.py | 66 ++ .../redist_p.py | 32 + .../wavetank_vegetation_time_series/tank3D.py | 562 ++++++++++++++++++ .../tank3D_so.py | 41 ++ .../twp_navier_stokes_n.py | 69 +++ .../twp_navier_stokes_p.py | 218 +++++++ .../wavetank_vegetation_time_series/vof_n.py | 65 ++ .../wavetank_vegetation_time_series/vof_p.py | 47 ++ 13 files changed, 1296 insertions(+) create mode 100644 3d/waves_vegetation/generate_wave_series/generate_monochromatic_linear.py create mode 100644 3d/waves_vegetation/wavetank_vegetation_time_series/ls_consrv_n.py create mode 100644 3d/waves_vegetation/wavetank_vegetation_time_series/ls_consrv_p.py create mode 100644 3d/waves_vegetation/wavetank_vegetation_time_series/ls_n.py create mode 100644 3d/waves_vegetation/wavetank_vegetation_time_series/ls_p.py create mode 100644 3d/waves_vegetation/wavetank_vegetation_time_series/redist_n.py create mode 100644 3d/waves_vegetation/wavetank_vegetation_time_series/redist_p.py create mode 100644 3d/waves_vegetation/wavetank_vegetation_time_series/tank3D.py create mode 100644 3d/waves_vegetation/wavetank_vegetation_time_series/tank3D_so.py create mode 100644 3d/waves_vegetation/wavetank_vegetation_time_series/twp_navier_stokes_n.py create mode 100644 3d/waves_vegetation/wavetank_vegetation_time_series/twp_navier_stokes_p.py create mode 100644 3d/waves_vegetation/wavetank_vegetation_time_series/vof_n.py create mode 100644 3d/waves_vegetation/wavetank_vegetation_time_series/vof_p.py diff --git a/3d/waves_vegetation/generate_wave_series/generate_monochromatic_linear.py b/3d/waves_vegetation/generate_wave_series/generate_monochromatic_linear.py new file mode 100644 index 00000000..8d3c4ce3 --- /dev/null +++ b/3d/waves_vegetation/generate_wave_series/generate_monochromatic_linear.py @@ -0,0 +1,30 @@ +from proteus import WaveTools +import numpy as np +import math + +mwl = 0.5 +mw = WaveTools.MonochromaticWaves(period = 1.0, + waveHeight = 0.1, + mwl = mwl, + depth = 1.0, + g = np.array([0.0, 0.0, -9.81]), + waveDir = np.array([1.0, 0.0, 0.0]), + wavelength=None, + waveType="Linear", + Ycoeff = None, + Bcoeff =None, + meanVelocity = 0.0, + phi0 = math.pi/2.0) + +f = open('monochromatic_linear_time_series.txt', 'w') +num_points = 10000 +tList = np.linspace(0.0,100.0,num_points) +etaList = np.zeros(tList.shape) +for i in range(num_points): + etaList[i] = mw.eta(0.0,0.0,0.0,tList[i]) + mwl + +combined = np.vstack((tList,etaList)).transpose() +np.savetxt("monochromatic_linear_time_series.txt", combined) + + + diff --git a/3d/waves_vegetation/wavetank_vegetation_time_series/ls_consrv_n.py b/3d/waves_vegetation/wavetank_vegetation_time_series/ls_consrv_n.py new file mode 100644 index 00000000..d6fdb0a9 --- /dev/null +++ b/3d/waves_vegetation/wavetank_vegetation_time_series/ls_consrv_n.py @@ -0,0 +1,48 @@ +from proteus import * +from tank3D import * +from ls_consrv_p import * + +timeIntegrator = ForwardIntegrator +timeIntegration = NoIntegration + +femSpaces = {0:basis} + +subgridError = None +massLumping = False +numericalFluxType = DoNothing +conservativeFlux = None +shockCapturing = None + +fullNewtonFlag = True +multilevelNonlinearSolver = Newton +levelNonlinearSolver = Newton + +nonlinearSmoother = None +linearSmoother = None + +matrix = SparseMatrix + +if useOldPETSc: + multilevelLinearSolver = PETSc + levelLinearSolver = PETSc +else: + multilevelLinearSolver = KSP_petsc4py + levelLinearSolver = KSP_petsc4py + +if useSuperlu: + multilevelLinearSolver = LU + levelLinearSolver = LU + +linear_solver_options_prefix = 'mcorr_' +nonlinearSolverConvergenceTest = 'r' +levelNonlinearSolverConvergenceTest = 'r' +linearSolverConvergenceTest = 'r-true' + +tolFac = 0.0 +linTolFac = 0.01 +l_atol_res = 0.01*mcorr_nl_atol_res +nl_atol_res = mcorr_nl_atol_res +useEisenstatWalker = False + +maxNonlinearIts = 50 +maxLineSearches = 0 diff --git a/3d/waves_vegetation/wavetank_vegetation_time_series/ls_consrv_p.py b/3d/waves_vegetation/wavetank_vegetation_time_series/ls_consrv_p.py new file mode 100644 index 00000000..ceb09427 --- /dev/null +++ b/3d/waves_vegetation/wavetank_vegetation_time_series/ls_consrv_p.py @@ -0,0 +1,26 @@ +from proteus import * +from proteus.default_p import * +from tank3D import * +from proteus.mprans import MCorr + +LevelModelType = MCorr.LevelModel + +coefficients = MCorr.Coefficients(LSModel_index=2,V_model=0,me_model=4,VOFModel_index=1, + applyCorrection=applyCorrection,nd=nd,checkMass=False,useMetrics=useMetrics, + epsFactHeaviside=epsFact_consrv_heaviside, + epsFactDirac=epsFact_consrv_dirac, + epsFactDiffusion=epsFact_consrv_diffusion) + +class zero_phi: + def __init__(self): + pass + def uOfX(self,X): + return 0.0 + def uOfXT(self,X,t): + return 0.0 + +initialConditions = {0:zero_phi()} + + + + diff --git a/3d/waves_vegetation/wavetank_vegetation_time_series/ls_n.py b/3d/waves_vegetation/wavetank_vegetation_time_series/ls_n.py new file mode 100644 index 00000000..fde02e06 --- /dev/null +++ b/3d/waves_vegetation/wavetank_vegetation_time_series/ls_n.py @@ -0,0 +1,63 @@ +from proteus import * +from ls_p import * + +if timeDiscretization=='vbdf': + timeIntegration = VBDF + timeOrder=2 + stepController = Min_dt_cfl_controller +elif timeDiscretization=='flcbdf': + timeIntegration = FLCBDF + #stepController = FLCBDF_controller + stepController = Min_dt_cfl_controller + time_tol = 10.0*ls_nl_atol_res + atol_u = {0:time_tol} + rtol_u = {0:time_tol} +else: + timeIntegration = BackwardEuler_cfl + stepController = Min_dt_cfl_controller + +femSpaces = {0:basis} + +massLumping = False +conservativeFlux = None +numericalFluxType = NCLS.NumericalFlux +subgridError = NCLS.SubgridError(coefficients,nd) +shockCapturing = NCLS.ShockCapturing(coefficients,nd,shockCapturingFactor=ls_shockCapturingFactor,lag=ls_lag_shockCapturing) + +fullNewtonFlag = True +multilevelNonlinearSolver = Newton +levelNonlinearSolver = Newton + +nonlinearSmoother = None +linearSmoother = None + +matrix = SparseMatrix + +if useOldPETSc: + multilevelLinearSolver = PETSc + levelLinearSolver = PETSc +else: + multilevelLinearSolver = KSP_petsc4py + levelLinearSolver = KSP_petsc4py + +if useSuperlu: + multilevelLinearSolver = LU + levelLinearSolver = LU + +linear_solver_options_prefix = 'ncls_' +nonlinearSolverConvergenceTest = 'r' +levelNonlinearSolverConvergenceTest = 'r' +linearSolverConvergenceTest = 'r-true' + +tolFac = 0.0 +nl_atol_res = ls_nl_atol_res + +linTolFac = 0.0 +l_atol_res = 0.1*ls_nl_atol_res + +useEisenstatWalker = False + +maxNonlinearIts = 50 +maxLineSearches = 0 + + diff --git a/3d/waves_vegetation/wavetank_vegetation_time_series/ls_p.py b/3d/waves_vegetation/wavetank_vegetation_time_series/ls_p.py new file mode 100644 index 00000000..9d6237c1 --- /dev/null +++ b/3d/waves_vegetation/wavetank_vegetation_time_series/ls_p.py @@ -0,0 +1,29 @@ +from proteus import * +from proteus.default_p import * +from tank3D import * +from proteus.mprans import NCLS + +LevelModelType = NCLS.LevelModel + +coefficients = NCLS.Coefficients(V_model=0,RD_model=3,ME_model=2, + checkMass=False, useMetrics=useMetrics, + epsFact=epsFact_consrv_heaviside,sc_uref=ls_sc_uref,sc_beta=ls_sc_beta,movingDomain=movingDomain) + +def getDBC_ls(x,flag): + if flag == boundaryTags['left']: + return wavePhi +# elif flag == boundaryTags['right']: +# return outflowPhi + else: + return None + +dirichletConditions = {0:getDBC_ls} + +advectiveFluxBoundaryConditions = {} +diffusiveFluxBoundaryConditions = {0:{}} + +class PerturbedSurface_phi: + def uOfXT(self,x,t): + return signedDistance(x) + +initialConditions = {0:PerturbedSurface_phi()} diff --git a/3d/waves_vegetation/wavetank_vegetation_time_series/redist_n.py b/3d/waves_vegetation/wavetank_vegetation_time_series/redist_n.py new file mode 100644 index 00000000..4f85688b --- /dev/null +++ b/3d/waves_vegetation/wavetank_vegetation_time_series/redist_n.py @@ -0,0 +1,66 @@ +from proteus import * +from redist_p import * +from tank3D import * + +nl_atol_res = rd_nl_atol_res +tolFac = 0.0 +nl_atol_res = rd_nl_atol_res + +linTolFac = 0.01 +l_atol_res = 0.01*rd_nl_atol_res + +if redist_Newton: + timeIntegration = NoIntegration + stepController = Newton_controller + maxNonlinearIts = 50 + maxLineSearches = 0 + nonlinearSolverConvergenceTest = 'r' + levelNonlinearSolverConvergenceTest = 'r' + linearSolverConvergenceTest = 'r-true' + useEisenstatWalker = False +else: + timeIntegration = BackwardEuler_cfl + stepController = RDLS.PsiTC + runCFL=2.0 + psitc['nStepsForce']=3 + psitc['nStepsMax']=50 + psitc['reduceRatio']=2.0 + psitc['startRatio']=1.0 + rtol_res[0] = 0.0 + atol_res[0] = rd_nl_atol_res + useEisenstatWalker = False + maxNonlinearIts = 1 + maxLineSearches = 0 + nonlinearSolverConvergenceTest = 'rits' + levelNonlinearSolverConvergenceTest = 'rits' + linearSolverConvergenceTest = 'r-true' + +femSpaces = {0:basis} + +massLumping = False +numericalFluxType = DoNothing +conservativeFlux = None +subgridError = RDLS.SubgridError(coefficients,nd) +shockCapturing = RDLS.ShockCapturing(coefficients,nd,shockCapturingFactor=rd_shockCapturingFactor,lag=rd_lag_shockCapturing) + +fullNewtonFlag = True +multilevelNonlinearSolver = Newton +levelNonlinearSolver = Newton + +nonlinearSmoother = NLGaussSeidel +linearSmoother = None + +matrix = SparseMatrix + +if useOldPETSc: + multilevelLinearSolver = PETSc + levelLinearSolver = PETSc +else: + multilevelLinearSolver = KSP_petsc4py + levelLinearSolver = KSP_petsc4py + +if useSuperlu: + multilevelLinearSolver = LU + levelLinearSolver = LU + +linear_solver_options_prefix = 'rdls_' diff --git a/3d/waves_vegetation/wavetank_vegetation_time_series/redist_p.py b/3d/waves_vegetation/wavetank_vegetation_time_series/redist_p.py new file mode 100644 index 00000000..ea199426 --- /dev/null +++ b/3d/waves_vegetation/wavetank_vegetation_time_series/redist_p.py @@ -0,0 +1,32 @@ +from proteus import * +from proteus.default_p import * +from math import * +from tank3D import * +from proteus.mprans import RDLS +""" +The redistancing equation in the sloshbox test problem. +""" + +LevelModelType = RDLS.LevelModel + +coefficients = RDLS.Coefficients(applyRedistancing=applyRedistancing, + epsFact=epsFact_redistance, + nModelId=2, + rdModelId=3, + useMetrics=useMetrics, + backgroundDiffusionFactor=backgroundDiffusionFactor) + +def getDBC_rd(x,flag): + pass + +dirichletConditions = {0:getDBC_rd} +weakDirichletConditions = {0:RDLS.setZeroLSweakDirichletBCsSimple} + +advectiveFluxBoundaryConditions = {} +diffusiveFluxBoundaryConditions = {0:{}} + +class PerturbedSurface_phi: + def uOfXT(self,x,t): + return signedDistance(x) + +initialConditions = {0:PerturbedSurface_phi()} diff --git a/3d/waves_vegetation/wavetank_vegetation_time_series/tank3D.py b/3d/waves_vegetation/wavetank_vegetation_time_series/tank3D.py new file mode 100644 index 00000000..5637ec5a --- /dev/null +++ b/3d/waves_vegetation/wavetank_vegetation_time_series/tank3D.py @@ -0,0 +1,562 @@ +from math import * +import proteus.MeshTools +from proteus import Domain +from proteus.default_n import * +from proteus.Profiling import logEvent +from proteus.ctransportCoefficients import smoothedHeaviside +from proteus.ctransportCoefficients import smoothedHeaviside_integral +from proteus import Gauges +from proteus.Gauges import PointGauges,LineGauges,LineIntegralGauges +from proteus.WaveTools import timeSeries + +# Domain and mesh +L = (15.0, 0.5, 1.0) + +he = 1.0/20.0 + +#wave generator +windVelocity = (0.0,0.0,0.0) +inflowHeightMean = 0.5 +inflowVelocityMean = (0.0,0.0,0.0) +period = 1.0 +g = [0.0,0.0,-9.8] + +# Wave Conditions +Nf = 10 +tS = timeSeries(timeSeriesFile = "monochromatic_linear_time_series.txt", + d = L[2], + Npeaks = 1, #m depth + bandFactor = [2.0], #controls width of band around fp + peakFrequencies = [1.0], + N = 32, #number of frequency bins + Nwaves = 20, + mwl = inflowHeightMean, #mean water level + waveDir = np.array([1,0,0]), + g = np.array(g)) + +# Discretization -- input options + +genMesh=True +movingDomain=False +applyRedistancing=True +useOldPETSc=False +useSuperlu=False +timeDiscretization='be'#'vbdf'#'be','flcbdf' +spaceOrder = 1 +useHex = False +useRBLES = 0.0 +useMetrics = 1.0 +applyCorrection=True +useVF = 1.0 +useOnlyVF = False +useRANS = 0 # 0 -- None + # 1 -- K-Epsilon + # 2 -- K-Omega +# Input checks +if spaceOrder not in [1,2]: + print "INVALID: spaceOrder" + spaceOrder + sys.exit() + +if useRBLES not in [0.0, 1.0]: + print "INVALID: useRBLES" + useRBLES + sys.exit() + +if useMetrics not in [0.0, 1.0]: + print "INVALID: useMetrics" + sys.exit() + +# Discretization +nd = 3 +if spaceOrder == 1: + hFactor=1.0 + if useHex: + basis=C0_AffineLinearOnCubeWithNodalBasis + elementQuadrature = CubeGaussQuadrature(nd,2) + elementBoundaryQuadrature = CubeGaussQuadrature(nd-1,2) + else: + basis=C0_AffineLinearOnSimplexWithNodalBasis + elementQuadrature = SimplexGaussQuadrature(nd,3) + elementBoundaryQuadrature = SimplexGaussQuadrature(nd-1,3) +elif spaceOrder == 2: + hFactor=0.5 + if useHex: + basis=C0_AffineLagrangeOnCubeWithNodalBasis + elementQuadrature = CubeGaussQuadrature(nd,4) + elementBoundaryQuadrature = CubeGaussQuadrature(nd-1,4) + else: + basis=C0_AffineQuadraticOnSimplexWithNodalBasis + elementQuadrature = SimplexGaussQuadrature(nd,4) + elementBoundaryQuadrature = SimplexGaussQuadrature(nd-1,4) + + +GenerationZoneLength = 1.2 +AbsorptionZoneLength= 2.8 +spongeLayer = True #False +levee=spongeLayer +slopingSpongeLayer=spongeLayer +xSponge = GenerationZoneLength +ySponge = 0.5 +xRelaxCenter = xSponge/2.0 +epsFact_solid = xSponge/2.0 +#zone 2 +xSponge_2 = L[0]-AbsorptionZoneLength +ySponge_3= L[1]- ySponge +xRelaxCenter_2 = 0.5*(xSponge_2+L[0]) +epsFact_solid_2 = AbsorptionZoneLength/2.0 + +nLevels = 1 +weak_bc_penalty_constant = 100.0 +quasi2D=False +if quasi2D:#make tank one element wide + L = (L[0],he,L[2]) + +#parallelPartitioningType = proteus.MeshTools.MeshParallelPartitioningTypes.element +parallelPartitioningType = proteus.MeshTools.MeshParallelPartitioningTypes.node +nLayersOfOverlapForParallel = 0 + +structured=False + +gauge_dx=5.0 +PGL=[] +LGL=[] +for i in range(0,int(L[0]/gauge_dx+1)): #+1 only if gauge_dx is an exact + PGL.append([gauge_dx*i,L[1]/2.0,0.5]) + LGL.append([(gauge_dx*i,L[1]/2.0,0),(gauge_dx*i,L[1]/2.0,L[2])]) + + +gaugeLocations=tuple(map(tuple,PGL)) +columnLines=tuple(map(tuple,LGL)) + + +pointGauges = PointGauges(gauges=((('u','v'), gaugeLocations), + (('p',), gaugeLocations)), + activeTime = (0, 1000.0), + sampleRate = 0, + fileName = 'combined_gauge_0_0.5_sample_all.txt') + + +fields = ('vof',) + +columnGauge = LineIntegralGauges(gauges=((fields, columnLines),), + fileName='column_gauge.csv') + +#lineGauges = LineGauges(gaugeEndpoints={'lineGauge_y=0':((0.0,0.0,0.0),(L[0],0.0,0.0))},linePoints=24) + +#lineGauges_phi = LineGauges_phi(lineGauges.endpoints,linePoints=20) + + +if useHex: + nnx=4*Refinement+1 + nny=2*Refinement+1 + hex=True + domain = Domain.RectangularDomain(L) +else: + boundaries=['empty','left','right','bottom','top','front','back'] + boundaryTags=dict([(key,i+1) for (i,key) in enumerate(boundaries)]) + if structured: + nnx=4*Refinement + nny=2*Refinement + domain = Domain.RectangularDomain(L) + elif spongeLayer: + vertices=[[0.0,0.0,0.0],#0 + [xSponge,0.0,0.0],#1 + [xSponge_2,0.0,0.0],#2 + [L[0],0.0,0.0],#3 + [L[0],L[1],0.0],#4 + [xSponge_2,L[1],0.0],#5 + [xSponge,L[1],0.0],#6 + [0.0,L[1],0.0]]#7 + + + vertexFlags=[boundaryTags['bottom'], + boundaryTags['bottom'], + boundaryTags['bottom'], + boundaryTags['bottom'], + boundaryTags['bottom'], + boundaryTags['bottom'], + boundaryTags['bottom'], + boundaryTags['bottom']] + + + for v,vf in zip(vertices,vertexFlags): + vertices.append([v[0],v[1],L[2]]) + vertexFlags.append(boundaryTags['top']) + + print vertices + print vertexFlags + + segments=[[0,1], + [1,2], + [2,3], + [3,4], + [4,5], + [5,6], + [6,7], + [7,0], + [1,6], + [2,5]] + + segmentFlags=[boundaryTags['front'], + boundaryTags['front'], + boundaryTags['front'], + boundaryTags['right'], + boundaryTags['back'], + boundaryTags['back'], + boundaryTags['back'], + boundaryTags['left'], + boundaryTags['empty'], + boundaryTags['empty'] ] + + + facets=[] + facetFlags=[] + + for s,sF in zip(segments,segmentFlags): + facets.append([[s[0],s[1],s[1]+8,s[0]+8]]) + facetFlags.append(sF) + + bf=[[0,1,6,7],[1,2,5,6],[2,3,4,5]] + tf=[] + for i in range(0,3): + facets.append([bf[i]]) + tf=[ss + 8 for ss in bf[i]] + facets.append([tf]) + + for i in range(0,3): + facetFlags.append(boundaryTags['bottom']) + facetFlags.append(boundaryTags['top']) + + print facets + print facetFlags + + regions=[[xRelaxCenter, 0.5*L[1],0.0], + [xRelaxCenter_2, 0.5*L[1], 0.0], + [0.5*L[0],0.1*L[1], 0.0]] + regionFlags=[1,2,3] + + domain = Domain.PiecewiseLinearComplexDomain(vertices=vertices, + vertexFlags=vertexFlags, + facets=facets, + facetFlags=facetFlags, + regions=regions, + regionFlags=regionFlags, + ) + #go ahead and add a boundary tags member + domain.boundaryTags = boundaryTags + domain.writePoly("mesh") + domain.writePLY("mesh") + domain.writeAsymptote("mesh") + triangleOptions="KVApq1.4q12feena%21.16e" % ((he**3)/6.0,) + + + logEvent("""Mesh generated using: tetgen -%s %s""" % (triangleOptions,domain.polyfile+".poly")) + + porosityTypes = numpy.array([1.0, + 1.0, + 1.0, + 1.0]) + dragAlphaTypes = numpy.array([0.0, + 0.5/1.004e-6, + 0.5/1.004e-6, + 0.0]) + + dragBetaTypes = numpy.array([0.0,0.0,0.0,0.0]) + + epsFact_solidTypes = np.array([0.0,epsFact_solid,epsFact_solid_2,0.0]) + + else: + vertices=[[0.0,0.0,0.0],#0 + [L[0],0.0,0.0],#1 + [L[0],L[1],0.0],#2 + [0.0,L[1],0.0]]#3 + + + vertexFlags=[boundaryTags['bottom'], + boundaryTags['bottom'], + boundaryTags['bottom'], + boundaryTags['bottom']] + + + for v,vf in zip(vertices,vertexFlags): + vertices.append([v[0],v[1],L[2]]) + vertexFlags.append(boundaryTags['top']) + + segments=[[0,1], + [1,2], + [2,3], + [3,0]] + + segmentFlags=[boundaryTags['front'], + boundaryTags['right'], + boundaryTags['back'], + boundaryTags['left']] + + facets=[] + facetFlags=[] + + for s,sF in zip(segments,segmentFlags): + facets.append([[s[0],s[1],s[1]+4,s[0]+4]]) + facetFlags.append(sF) + + bf=[[0,1,2,3]] + tf=[] + for i in range(0,1): + facets.append([bf[i]]) + tf=[ss + 4 for ss in bf[i]] + facets.append([tf]) + + for i in range(0,1): + facetFlags.append(boundaryTags['bottom']) + facetFlags.append(boundaryTags['top']) + + for s,sF in zip(segments,segmentFlags): + segments.append([s[1]+4,s[0]+4]) + segmentFlags.append(sF) + + + regions=[[0.5*L[0],0.5*L[1], 0.0]] + regionFlags=[1] + + domain = Domain.PiecewiseLinearComplexDomain(vertices=vertices, + vertexFlags=vertexFlags, + facets=facets, + facetFlags=facetFlags, + regions=regions, + regionFlags=regionFlags) + #go ahead and add a boundary tags member + domain.boundaryTags = boundaryTags + domain.writePoly("mesh") + domain.writePLY("mesh") + domain.writeAsymptote("mesh") + triangleOptions="KVApq1.4q12feena%21.16e" % ((he**3)/6.0,) + + + logEvent("""Mesh generated using: tetgen -%s %s""" % (triangleOptions,domain.polyfile+".poly")) + +# Time stepping +T=2.0*period +dt_fixed = period/20.0 +dt_init = min(0.1*dt_fixed,0.1*he) +runCFL=0.90 +nDTout = int(round(T/dt_fixed)) + +# Numerical parameters +ns_forceStrongDirichlet = True #False#True +backgroundDiffusionFactor=0.01 +if useMetrics: + ns_shockCapturingFactor = 0.25 + ns_lag_shockCapturing = True + ns_lag_subgridError = True + ls_shockCapturingFactor = 0.25 + ls_lag_shockCapturing = True + ls_sc_uref = 1.0 + ls_sc_beta = 1.0 + vof_shockCapturingFactor = 0.25 + vof_lag_shockCapturing = True + vof_sc_uref = 1.0 + vof_sc_beta = 1.0 + rd_shockCapturingFactor = 0.25 + rd_lag_shockCapturing = False + epsFact_density = 3.0 + epsFact_viscosity = epsFact_curvature = epsFact_vof = epsFact_consrv_heaviside = epsFact_consrv_dirac = epsFact_density + epsFact_redistance = 0.33 + epsFact_consrv_diffusion = 0.1 + redist_Newton = False + kappa_shockCapturingFactor = 0.1 + kappa_lag_shockCapturing = True#False + kappa_sc_uref = 1.0 + kappa_sc_beta = 1.0 + dissipation_shockCapturingFactor = 0.1 + dissipation_lag_shockCapturing = True#False + dissipation_sc_uref = 1.0 + dissipation_sc_beta = 1.0 +else: + ns_shockCapturingFactor = 0.9 + ns_lag_shockCapturing = True + ns_lag_subgridError = True + ls_shockCapturingFactor = 0.9 + ls_lag_shockCapturing = True + ls_sc_uref = 1.0 + ls_sc_beta = 1.0 + vof_shockCapturingFactor = 0.9 + vof_lag_shockCapturing = True + vof_sc_uref = 1.0 + vof_sc_beta = 1.0 + rd_shockCapturingFactor = 0.9 + rd_lag_shockCapturing = False + epsFact_density = 1.5 + epsFact_viscosity = epsFact_curvature = epsFact_vof = epsFact_consrv_heaviside = epsFact_consrv_dirac = epsFact_density + epsFact_redistance = 0.33 + epsFact_consrv_diffusion = 1.0 + redist_Newton = False + kappa_shockCapturingFactor = 0.9 + kappa_lag_shockCapturing = True#False + kappa_sc_uref = 1.0 + kappa_sc_beta = 1.0 + dissipation_shockCapturingFactor = 0.9 + dissipation_lag_shockCapturing = True#False + dissipation_sc_uref = 1.0 + dissipation_sc_beta = 1.0 + +ns_nl_atol_res = max(1.0e-10,0.001*he**2) +vof_nl_atol_res = max(1.0e-10,0.001*he**2) +ls_nl_atol_res = max(1.0e-10,0.001*he**2) +rd_nl_atol_res = max(1.0e-10,0.005*he) +mcorr_nl_atol_res = max(1.0e-10,0.001*he**2) +kappa_nl_atol_res = max(1.0e-10,0.001*he**2) +dissipation_nl_atol_res = max(1.0e-10,0.001*he**2) + +#turbulence +ns_closure=2 #1-classic smagorinsky, 2-dynamic smagorinsky, 3 -- k-epsilon, 4 -- k-omega +if useRANS == 1: + ns_closure = 3 +elif useRANS == 2: + ns_closure == 4 +# Water +rho_0 = 998.2 +nu_0 = 1.004e-6 + +# Air +rho_1 = 1.205 +nu_1 = 1.500e-5 + +# Surface tension +sigma_01 = 0.0 + + +# Initial condition +waterLine_x = 2*L[0] +waterLine_z = inflowHeightMean +waterLine_y = 2*L[1] + +def signedDistance(x): + phi_z = x[2]-waterLine_z + return phi_z + +def theta(x,t): + return k*x[0] - omega*t + math.pi/2.0 + +def z(x): + return x[2] - inflowHeightMean + +def ramp(t): + t0=10 #ramptime + if tinflowHeightMean: + return (L[2]-x[2])*rho_1*abs(g[2]) + else: + return (L[2]-inflowHeightMean)*rho_1*abs(g[2])+(inflowHeightMean-x[2])*rho_0*abs(g[2]) + +def waterVelocity(x,t): + if x[2]>inflowHeightMean: + return 0.0 + else: + ic=inflowVelocityMean[0] + return ic + +def zeroVel(x,t): + return 0.0 + + +beam_quadOrder=3 +beam_useSparse=False +beamFilename="wavetankBeams" +#nBeamElements=max(nBeamElements,3) + +#beam info +beamLocation=[] +beamLength=[] +beamRadius=[] +EI=[] +GJ=[] +lam = 0.05 #3.0*2.54/100.0 #57.4e-3 +lamx = 3.0**0.5*lam +xs = 1.2 +ys = 0.0 +xList=[] +yList = [] +while xs <= 11.0: + xList.append(xs) + xs += lam +while ys<= L[1]: + yList.append(ys) + ys+=lamx +for i in xList: + for j in yList: + beamLocation.append((i,j)) + beamLength.append(0.415) + beamRadius.append(0.0032) + EI.append(3.0e-4) # needs to be fixed + GJ.append(1.5e-4) # needs to be fixed + +xs = 1.2+0.5*lam +ys = 0.5*lamx +xList=[] +yList = [] +while xs <= 11.0: + xList.append(xs) + xs += lam + +while ys<= L[1]: + yList.append(ys) + ys+=lamx + +for i in xList: + for j in yList: + beamLocation.append((i,j)) + beamLength.append(0.415) + beamRadius.append(0.0032) + EI.append(3.0e-4) # needs to be fixed + GJ.append(1.5e-4) # needs to be fixed +nBeamElements = int(beamLength[0]/he*0.5) +nBeamElements=max(nBeamElements,3) +print nBeamElements diff --git a/3d/waves_vegetation/wavetank_vegetation_time_series/tank3D_so.py b/3d/waves_vegetation/wavetank_vegetation_time_series/tank3D_so.py new file mode 100644 index 00000000..f8c11c9b --- /dev/null +++ b/3d/waves_vegetation/wavetank_vegetation_time_series/tank3D_so.py @@ -0,0 +1,41 @@ +from proteus.default_so import * +import tank3D + +if tank3D.useOnlyVF: + pnList = [("twp_navier_stokes_p", "twp_navier_stokes_n"), + ("vof_p", "vof_n")] +else: + pnList = [("twp_navier_stokes_p", "twp_navier_stokes_n"), + ("vof_p", "vof_n"), + ("ls_p", "ls_n"), + ("redist_p", "redist_n"), + ("ls_consrv_p", "ls_consrv_n")] + + +if tank3D.useRANS > 0: + pnList.append(("kappa_p", + "kappa_n")) + pnList.append(("dissipation_p", + "dissipation_n")) +name = "tank3D_p" + +if tank3D.timeDiscretization == 'flcbdf': + systemStepControllerType = Sequential_MinFLCBDFModelStep + systemStepControllerType = Sequential_MinAdaptiveModelStep +else: + systemStepControllerType = Sequential_MinAdaptiveModelStep + +needEBQ_GLOBAL = False +needEBQ = False + +tnList = [0.0,tank3D.dt_init]+[i*tank3D.dt_fixed for i in range(1,tank3D.nDTout+1)] + +info = open("TimeList.txt","w") + + +for time in tnList: + info.write(str(time)+"\n") +info.close() + + +archiveFlag = ArchiveFlags.EVERY_SEQUENCE_STEP diff --git a/3d/waves_vegetation/wavetank_vegetation_time_series/twp_navier_stokes_n.py b/3d/waves_vegetation/wavetank_vegetation_time_series/twp_navier_stokes_n.py new file mode 100644 index 00000000..4e5ff8d1 --- /dev/null +++ b/3d/waves_vegetation/wavetank_vegetation_time_series/twp_navier_stokes_n.py @@ -0,0 +1,69 @@ +from proteus import * +from twp_navier_stokes_p import * +from tank3D import * + +if timeDiscretization=='vbdf': + timeIntegration = VBDF + timeOrder=2 + stepController = Min_dt_cfl_controller +elif timeDiscretization=='flcbdf': + timeIntegration = FLCBDF + #stepController = FLCBDF_controller_sys + stepController = Min_dt_cfl_controller + time_tol = 10.0*ns_nl_atol_res + atol_u = {1:time_tol,2:time_tol,3:time_tol} + rtol_u = {1:time_tol,2:time_tol,3:time_tol} +else: + timeIntegration = BackwardEuler_cfl + stepController = Min_dt_cfl_controller + +femSpaces = {0:basis, + 1:basis, + 2:basis, + 3:basis} + +massLumping = False +numericalFluxType = None +conservativeFlux = None + +numericalFluxType = RANS2P.NumericalFlux +subgridError = RANS2P.SubgridError(coefficients,nd,lag=ns_lag_subgridError,hFactor=hFactor) +shockCapturing = RANS2P.ShockCapturing(coefficients,nd,ns_shockCapturingFactor,lag=ns_lag_shockCapturing) + +fullNewtonFlag = True +multilevelNonlinearSolver = Newton +levelNonlinearSolver = Newton + +nonlinearSmoother = None + +linearSmoother = SimpleNavierStokes3D + +matrix = SparseMatrix + +if useOldPETSc: + multilevelLinearSolver = PETSc + levelLinearSolver = PETSc +else: + multilevelLinearSolver = KSP_petsc4py + levelLinearSolver = KSP_petsc4py + +if useSuperlu: + multilevelLinearSolver = LU + levelLinearSolver = LU + +linear_solver_options_prefix = 'rans2p_' +nonlinearSolverConvergenceTest = 'r' +levelNonlinearSolverConvergenceTest = 'r' +linearSolverConvergenceTest = 'r-true' + +tolFac = 0.0 +linTolFac = 0.01 +l_atol_res = 0.01*ns_nl_atol_res +nl_atol_res = ns_nl_atol_res +useEisenstatWalker = False +maxNonlinearIts = 50 +maxLineSearches = 0 +conservativeFlux = {0:'pwl-bdm-opt'} + + +#auxiliaryVariables=[pointGauges,rzWaveGenerator] diff --git a/3d/waves_vegetation/wavetank_vegetation_time_series/twp_navier_stokes_p.py b/3d/waves_vegetation/wavetank_vegetation_time_series/twp_navier_stokes_p.py new file mode 100644 index 00000000..88041868 --- /dev/null +++ b/3d/waves_vegetation/wavetank_vegetation_time_series/twp_navier_stokes_p.py @@ -0,0 +1,218 @@ +from proteus import * +from proteus.default_p import * +from tank3D import * +from proteus.mprans import RANS2P +from proteus.ib import RANS2P_IB + +LevelModelType = RANS2P_IB.LevelModel +if useOnlyVF: + LS_model = None +else: + LS_model = 2 +if useRANS >= 1: + Closure_0_model = 5; Closure_1_model=6 + if useOnlyVF: + Closure_0_model=2; Closure_1_model=3 + if movingDomain: + Closure_0_model += 1; Closure_1_model += 1 +else: + Closure_0_model = None + Closure_1_model = None + +if spongeLayer or levee or slopingSpongeLayer: + coefficients = RANS2P_IB.Coefficients(epsFact=epsFact_viscosity, + sigma=0.0, + rho_0 = rho_0, + nu_0 = nu_0, + rho_1 = rho_1, + nu_1 = nu_1, + g=g, + nd=nd, + VF_model=1, + LS_model=LS_model, + Closure_0_model=Closure_0_model, + Closure_1_model=Closure_1_model, + epsFact_density=epsFact_density, + stokes=False, + useVF=useVF, + useRBLES=useRBLES, + useMetrics=useMetrics, + eb_adjoint_sigma=1.0, + eb_penalty_constant=weak_bc_penalty_constant, + forceStrongDirichlet=ns_forceStrongDirichlet, + turbulenceClosureModel=ns_closure, + movingDomain=movingDomain, + porosityTypes=porosityTypes, + dragAlphaTypes=dragAlphaTypes, + dragBetaTypes=dragBetaTypes, + epsFact_solid = epsFact_solidTypes, + beamLocation=beamLocation, + beamLength=beamLength, + beamRadius=beamRadius, + EI=EI, + GJ=GJ, + nBeamElements=nBeamElements, + beam_quadOrder=beam_quadOrder, + beamFilename=beamFilename, + beam_Cd=1.2, + beam_nlTol=1.0e-5, + beamRigid=True) +else: + coefficients = RANS2P_IB.Coefficients(epsFact=epsFact_viscosity, + sigma=0.0, + rho_0 = rho_0, + nu_0 = nu_0, + rho_1 = rho_1, + nu_1 = nu_1, + g=g, + nd=nd, + VF_model=1, + LS_model=LS_model, + Closure_0_model=Closure_0_model, + Closure_1_model=Closure_1_model, + epsFact_density=epsFact_density, + stokes=False, + useVF=useVF, + useRBLES=useRBLES, + useMetrics=useMetrics, + eb_adjoint_sigma=1.0, + eb_penalty_constant=weak_bc_penalty_constant, + forceStrongDirichlet=ns_forceStrongDirichlet, + turbulenceClosureModel=ns_closure, + movingDomain=movingDomain, + beamLocation=beamLocation, + beamLength=beamLength, + beamRadius=beamRadius, + EI=EI, + GJ=GJ, + nBeamElements=nBeamElements, + beam_quadOrder=beam_quadOrder, + beamFilename=beamFilename, + beam_Cd=1.2, + beam_nlTol=1.0e-5, + beamRigid=True) + + +def getDBC_p(x,flag): + if flag == boundaryTags['top']: + return lambda x,t: 0.0 + elif flag == boundaryTags['right']: + return outflowPressure + +def getDBC_u(x,flag): + if flag == boundaryTags['left']: + return twpflowVelocity_u + + +def getDBC_v(x,flag): + if flag == boundaryTags['left']: + return twpflowVelocity_v + +def getDBC_w(x,flag): + if flag == boundaryTags['left']: + return twpflowVelocity_w + +dirichletConditions = {0:getDBC_p, + 1:getDBC_u, + 2:getDBC_v, + 3:getDBC_w} + +def getAFBC_p(x,flag): + if flag == boundaryTags['left']: + return lambda x,t: -twpflowVelocity_u(x,t) + elif flag == boundaryTags['bottom'] or flag == boundaryTags['back'] or flag == boundaryTags['front']: + return lambda x,t: 0.0 + elif flag == boundaryTags['right']: + return lambda x,t: 0.0 + else: + return None + +def getAFBC_u(x,flag): + if flag == boundaryTags['bottom'] or flag == boundaryTags['back'] or flag == boundaryTags['front']: + return lambda x,t: 0.0 + elif flag == boundaryTags['right']: + return lambda x,t: 0.0 + else: + return None + +def getAFBC_v(x,flag): + if flag == boundaryTags['bottom'] or flag == boundaryTags['back'] or flag == boundaryTags['front']: + return lambda x,t: 0.0 + elif flag == boundaryTags['right']: + return lambda x,t: 0.0 + else: + return None + +def getAFBC_w(x,flag): + if flag == boundaryTags['bottom'] or flag == boundaryTags['back'] or flag == boundaryTags['front']: + return lambda x,t: 0.0 + elif flag == boundaryTags['right']: + return lambda x,t: 0.0 + else: + return None + +def getDFBC_u(x,flag): + if flag != boundaryTags['left']: + return lambda x,t: 0.0 + + +def getDFBC_v(x,flag): + if flag != boundaryTags['left']: + return lambda x,t: 0.0 + + +def getDFBC_w(x,flag): + if flag != boundaryTags['left']: + return lambda x,t: 0.0 +# if flag == boundaryTags['bottom']: +# return lambda x,t: 0.0 +# elif flag == boundaryTags['back']: +# return lambda x,t: 0.0 +# elif flag == boundaryTags['front']: +# return lambda x,t: 0.0 +# elif flag == boundaryTags['right']: +# return lambda x,t: 0.0 +# elif flag == boundaryTags['top']: +# return lambda x,t: 0.0 + + +advectiveFluxBoundaryConditions = {0:getAFBC_p, + 1:getAFBC_u, + 2:getAFBC_v, + 3:getAFBC_w} + +diffusiveFluxBoundaryConditions = {0:{}, + 1:{1:getDFBC_u}, + 2:{2:getDFBC_v}, + 3:{3:getDFBC_w}} + +class PerturbedSurface_p: + def __init__(self,waterLevel): + self.waterLevel=waterLevel + def uOfXT(self,x,t): + # if signedDistance(x) < 0: + # return -(L[2] - self.waterLevel)*rho_1*g[2] - (self.waterLevel - x[2])*rho_0*g[2] + # else: + # return -(L[2] - self.waterLevel)*rho_1*g[2] + if x[2]>inflowHeightMean: + return (L[2]-x[2])*rho_1*abs(g[2]) + else: + return (L[2]-inflowHeightMean)*rho_1*abs(g[2])+(inflowHeightMean-x[2])*rho_0*abs(g[2]) + +class AtRest: + def __init__(self): + pass + def uOfXT(self,x,t): + return 0.0 + +class WaterVelocity_u: + def __init__(self): + pass + def uOfXT(self,x,t): + + return waterVelocity(x,0) + +initialConditions = {0:PerturbedSurface_p(waterLine_z), + 1:AtRest(), + 2:AtRest(), + 3:AtRest()} diff --git a/3d/waves_vegetation/wavetank_vegetation_time_series/vof_n.py b/3d/waves_vegetation/wavetank_vegetation_time_series/vof_n.py new file mode 100644 index 00000000..de2fdd09 --- /dev/null +++ b/3d/waves_vegetation/wavetank_vegetation_time_series/vof_n.py @@ -0,0 +1,65 @@ +from proteus import * +from tank3D import * +from vof_p import * + +if timeDiscretization=='vbdf': + timeIntegration = VBDF + timeOrder=2 + stepController = Min_dt_cfl_controller +elif timeDiscretization=='flcbdf': + timeIntegration = FLCBDF + #stepController = FLCBDF_controller + stepController = Min_dt_cfl_controller + time_tol = 10.0*vof_nl_atol_res + atol_u = {0:time_tol} + rtol_u = {0:time_tol} +else: + timeIntegration = BackwardEuler_cfl + stepController = Min_dt_cfl_controller + +femSpaces = {0:basis} + +massLumping = False +numericalFluxType = VOF.NumericalFlux +conservativeFlux = None +subgridError = VOF.SubgridError(coefficients=coefficients,nd=nd) +shockCapturing = VOF.ShockCapturing(coefficients,nd,shockCapturingFactor=vof_shockCapturingFactor,lag=vof_lag_shockCapturing) + +fullNewtonFlag = True +multilevelNonlinearSolver = Newton +levelNonlinearSolver = Newton + +nonlinearSmoother = None +linearSmoother = None + +matrix = SparseMatrix + +if useOldPETSc: + multilevelLinearSolver = PETSc + levelLinearSolver = PETSc +else: + multilevelLinearSolver = KSP_petsc4py + levelLinearSolver = KSP_petsc4py + +if useSuperlu: + multilevelLinearSolver = LU + levelLinearSolver = LU + +linear_solver_options_prefix = 'vof_' +nonlinearSolverConvergenceTest = 'r' +levelNonlinearSolverConvergenceTest = 'r' +linearSolverConvergenceTest = 'r-true' + +tolFac = 0.0 +nl_atol_res = vof_nl_atol_res + +linTolFac = 0.0 +l_atol_res = 0.1*vof_nl_atol_res + +useEisenstatWalker = False + +maxNonlinearIts = 50 +maxLineSearches = 0 + +auxiliaryVariables = [columnGauge] + diff --git a/3d/waves_vegetation/wavetank_vegetation_time_series/vof_p.py b/3d/waves_vegetation/wavetank_vegetation_time_series/vof_p.py new file mode 100644 index 00000000..ea33ff3b --- /dev/null +++ b/3d/waves_vegetation/wavetank_vegetation_time_series/vof_p.py @@ -0,0 +1,47 @@ +from proteus import * +from proteus.default_p import * +from proteus.ctransportCoefficients import smoothedHeaviside +from tank3D import * +from proteus.mprans import VOF + +LevelModelType = VOF.LevelModel +if useOnlyVF: + RD_model = None + LS_model = None +else: + RD_model = 3 + LS_model = 2 + +coefficients = VOF.Coefficients(LS_model=LS_model,V_model=0,RD_model=RD_model,ME_model=1, + checkMass=False,useMetrics=useMetrics, + epsFact=epsFact_vof,sc_uref=vof_sc_uref,sc_beta=vof_sc_beta,movingDomain=movingDomain) + +def getDBC_vof(x,flag): + if flag == boundaryTags['left']: + return waveVF + elif flag == boundaryTags['top']:# or x[1] >= L[1] - 1.0e-12: + return lambda x,t: 1.0 +# elif flag == boundaryTags['right']: +# return outflowVF + + +dirichletConditions = {0:getDBC_vof} + +def getAFBC_vof(x,flag): + if flag == boundaryTags['left']: + return None + elif flag == boundaryTags['top']:# or x[1] >= L[1] - 1.0e-12: + return None +# elif flag == boundaryTags['right']: +# return None + else: + return lambda x,t: 0.0 + +advectiveFluxBoundaryConditions = {0:getAFBC_vof} +diffusiveFluxBoundaryConditions = {0:{}} + +class PerturbedSurface_H: + def uOfXT(self,x,t): + return smoothedHeaviside(epsFact_consrv_heaviside*he,signedDistance(x)) + +initialConditions = {0:PerturbedSurface_H()} From 671821db1d9ebc5feaaeec1efea462521ba3ba8b Mon Sep 17 00:00:00 2001 From: cekees Date: Wed, 7 Oct 2015 16:50:51 -0500 Subject: [PATCH 07/20] added and enabled gauges --- 2d/waves_vegetation/ProcessGauges.ipynb | 3 + 2d/waves_vegetation/tank.py | 103 ++++++++++++++------- 2d/waves_vegetation/twp_navier_stokes_n.py | 1 + 2d/waves_vegetation/vof_n.py | 2 +- 4 files changed, 76 insertions(+), 33 deletions(-) create mode 100644 2d/waves_vegetation/ProcessGauges.ipynb diff --git a/2d/waves_vegetation/ProcessGauges.ipynb b/2d/waves_vegetation/ProcessGauges.ipynb new file mode 100644 index 00000000..230154a2 --- /dev/null +++ b/2d/waves_vegetation/ProcessGauges.ipynb @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:34173c7a91125f2f0d8f64a932453e1965a134a6c26cc8a84c1c9b866c5d41b5 +size 204330 diff --git a/2d/waves_vegetation/tank.py b/2d/waves_vegetation/tank.py index 2f404639..1cb4dede 100644 --- a/2d/waves_vegetation/tank.py +++ b/2d/waves_vegetation/tank.py @@ -12,8 +12,8 @@ #wave generator windVelocity = (0.0,0.0) -depth = 19.6/44.0+6.1/20.0 + 0.457 -inflowHeightMean = 19.6/44.0+6.1/20.0 + 0.457 +depth = 17.2/44.0 + 6.1/20.0 + 0.457 +inflowHeightMean = 17.2/44.0 + 6.1/20.0 + 0.457 inflowVelocityMean = (0.0,0.0) period = 2.0 omega = 2.0*math.pi/period @@ -124,10 +124,24 @@ gauge_dx=0.075 PGL=[] -LGL=[] -for i in range(0,int(L[0]/gauge_dx+1)): #+1 only if gauge_dx is an exact - PGL.append([gauge_dx*i,0.5,0]) - LGL.append([(gauge_dx*i,0.0,0),(gauge_dx*i,L[1],0)]) +gauge_top = 19.5/44.0 + 1.5 +veg_gauge_bottom_y = 17.2/44.0 + 6.1/20.0 +LGL=[[(6.1, (6.1 - 5.4)/44.0, 0.0), (6.1,gauge_top,0.0)],#1 Goda + [(6.4, (6.4 - 5.4)/44.0, 0.0), (6.4,gauge_top,0.0)],#2 Goda + [(7.0, (7.0 - 5.4)/44.0, 0.0), (7.0,gauge_top,0.0)],#3 Goda + [(26.0, veg_gauge_bottom_y, 0.0), (26.0,gauge_top,0.0)],#4 veg + [(26.9, veg_gauge_bottom_y, 0.0), (26.9,gauge_top,0.0)],#5 + [(27.4, veg_gauge_bottom_y, 0.0), (27.4,gauge_top,0.0)],#6 + [(27.9, veg_gauge_bottom_y, 0.0), (27.9,gauge_top,0.0)],#7 + [(28.5, veg_gauge_bottom_y, 0.0), (28.5,gauge_top,0.0)],#8 + [(29.5, veg_gauge_bottom_y, 0.0), (29.5,gauge_top,0.0)],#9 + [(31.0, veg_gauge_bottom_y, 0.0), (31.0,gauge_top,0.0)],#10 + [(32.7, veg_gauge_bottom_y, 0.0), (32.7,gauge_top,0.0)],#11 + [(34.4, veg_gauge_bottom_y, 0.0), (34.4,gauge_top,0.0)],#12 + [(36.2, veg_gauge_bottom_y, 0.0), (36.2,gauge_top,0.0)]]#13 +#for i in range(0,int(L[0]/gauge_dx+1)): #+1 only if gauge_dx is an exact +# PGL.append([gauge_dx*i,0.5,0]) +# LGL.append([(gauge_dx*i,0.0,0),(gauge_dx*i,L[1],0)]) gaugeLocations=tuple(map(tuple,PGL)) @@ -145,10 +159,18 @@ fields = ('vof',) -#columnGauge = LineIntegralGauges(gauges=((fields, columnLines),), -# fileName='column_gauge.csv') +columnGauge = LineIntegralGauges(gauges=((fields, columnLines),), + fileName='column_gauge.csv') -#lineGauges = LineGauges(gaugeEndpoints={'lineGauge_y=0':((0.0,0.0,0.0),(L[0],0.0,0.0))},linePoints=24) +#v_resolution = max(he,0.05) +#linePoints = int((gauge_top - veg_gauge_bottom_y)/v_resolution) +lineGauges = LineGauges(gauges=((('u','v'),#fields in gauge set + (#lines for these fields + ((26.0, veg_gauge_bottom_y, 0.0),(26.0, gauge_top, 0.0)), + ),#end lines + ),#end gauge set + ),#end gauges + fileName="vegZoneVelocity.csv") #lineGauges_phi = LineGauges_phi(lineGauges.endpoints,linePoints=20) @@ -165,16 +187,20 @@ nnx=ceil(L[0]/he)+1 nny=ceil(L[1]/he)+1 elif spongeLayer: - vertices=[[0.0, 0.0 ],#0 - [19.6, 19.6/44.0 ],#1 - [19.6+6.1, 19.6/44.0+6.1/20.0 ],#2 - [19.6+6.1+1.2, 19.6/44.0+6.1/20.0 ],#3 - [19.6+6.1+1.2+9.8, 19.6/44.0+6.1/20.0 ],#4 - [19.6+6.1+1.2+9.8+1.2, 19.6/44.0+6.1/20.0 ],#5 - [45.4, 19.6/44.0+11.3/20.0 ],#6 - [45.4, 19.6/44.0+11.3/20.0 +1.0],#7 - [37.9, 19.6/44.0+11.3/20.0 +1.0],#8 - [0.0, 19.6/44.0+11.3/20.0 +1.0]]#9 + vertices=[[0.0, 0.0 ],#0 + [5.4, 0.0 ],#1 + [5.4 + 17.2, 17.2/44.0 ],#2 + [5.4 + 17.2 + 6.1, 17.2/44.0 + 6.1/20.0 ],#3 + [5.4 + 17.2 + 6.1 + 1.2, 17.2/44.0 + 6.1/20.0 ],#4 + [5.4 + 17.2 + 6.1 + 1.2 + 9.8, 17.2/44.0 + 6.1/20.0 ],#5 + [5.4 + 17.2 + 6.1 + 1.2 + 9.8 + 1.2, 17.2/44.0 + 6.1/20.0 ],#6 -- sponge + [5.4 + 17.2 + 6.1 + 1.2 + 9.8 + 1.2 + 7.5, 17.2/44.0 + 6.1/20.0 + 7.5/20.0],#7 + [5.4 + 17.2 + 6.1 + 1.2 + 9.8 + 1.2 + 7.5 + 3.0, 17.2/44.0 + 6.1/20.0 + 7.5/20.0],#8 + [5.4 + 17.2 + 6.1 + 1.2 + 9.8 + 1.2 + 7.5 + 3.0, 19.5/44.0],#9 + [5.4 + 17.2 + 6.1 + 1.2 + 9.8 + 1.2 + 7.5 + 3.0 + 12.0, 19.5/44.0],#10 + [5.4 + 17.2 + 6.1 + 1.2 + 9.8 + 1.2 + 7.5 + 3.0 + 12.0, 19.5/44.0 + 1.5],#11 + [5.4 + 17.2 + 6.1 + 1.2 + 9.8 + 1.2, 19.5/44.0 + 1.5],#12 -- sponge + [0.0, 19.5/44.0 + 1.5]]#13 vertexFlags=[boundaryTags['bottom'],#0 boundaryTags['bottom'],#1 @@ -183,9 +209,13 @@ boundaryTags['bottom'],#4 boundaryTags['bottom'],#5 boundaryTags['bottom'],#6 - boundaryTags['top'],#7 - boundaryTags['top'],#8 - boundaryTags['top']]#9 + boundaryTags['bottom'],#7 + boundaryTags['bottom'],#8 + boundaryTags['bottom'],#9 + boundaryTags['bottom'],#10 + boundaryTags['top'],#11 + boundaryTags['top'],#12 + boundaryTags['top']]#13 segments=[[0,1],#0 [1,2],#1 [2,3],#2 @@ -195,8 +225,12 @@ [6,7],#6 [7,8],#7 [8,9],#8 - [9,0],#9 - [5,8]]#10 + [9,10],#9 + [10,11],#10 + [11,12],#11 + [12,13],#12 + [13,0],#13 + [6,12]]#14 segmentFlags=[boundaryTags['bottom'],#0 boundaryTags['bottom'],#1 @@ -204,13 +238,18 @@ boundaryTags['bottom'],#3 boundaryTags['bottom'],#4 boundaryTags['bottom'],#5 - boundaryTags['right'],#6 - boundaryTags['top'],#7 - boundaryTags['top'],#8 - boundaryTags['left'],#9 - 0]#10 - - regions=[[0.001,0.5],[38,0.5]] + boundaryTags['bottom'],#6 + boundaryTags['bottom'],#7 + boundaryTags['bottom'],#8 + boundaryTags['bottom'],#9 + boundaryTags['right'],#10 + boundaryTags['top'],#11 + boundaryTags['top'],#12 + boundaryTags['left'],#13 + 0]#14 + + regions=[[0.5,0.5], + [5.4 + 17.2 + 6.1 + 1.2 + 9.8 + 1.2 + 7.5 + 3.0 + 12.0 -0.5, 19.5/44.0 + 1.5 - 0.5]] regionFlags=[1,2] domain = Domain.PlanarStraightLineGraphDomain(vertices=vertices, vertexFlags=vertexFlags, @@ -497,7 +536,7 @@ def calculate(self): # twpflowVelocity_v, # twpflowVelocity_w), 1:RelaxationZone(xRelaxCenter_2, - 1.0, #currently Hs=1-exp_function + -1.0, #currently Hs=1-exp_function zeroVel, zeroVel, zeroVel)}) diff --git a/2d/waves_vegetation/twp_navier_stokes_n.py b/2d/waves_vegetation/twp_navier_stokes_n.py index c339d98c..197b241f 100644 --- a/2d/waves_vegetation/twp_navier_stokes_n.py +++ b/2d/waves_vegetation/twp_navier_stokes_n.py @@ -64,4 +64,5 @@ maxLineSearches = 0 conservativeFlux = {0:'pwl-bdm-opt'} +auxiliaryVariables=[lineGauges] #auxiliaryVariables=[pointGauges,rzWaveGenerator] diff --git a/2d/waves_vegetation/vof_n.py b/2d/waves_vegetation/vof_n.py index ce3fbe34..8862cd13 100644 --- a/2d/waves_vegetation/vof_n.py +++ b/2d/waves_vegetation/vof_n.py @@ -61,4 +61,4 @@ maxNonlinearIts = 50 maxLineSearches = 0 -#auxiliaryVariables = [columnGauge] +auxiliaryVariables = [columnGauge] From 62091593c06d7ae9bfa2ba9364b864cf534f429d Mon Sep 17 00:00:00 2001 From: cekees Date: Wed, 7 Oct 2015 18:40:46 -0500 Subject: [PATCH 08/20] added Context and support for double-peaded spectrum --- 2d/waves_vegetation/tank.py | 104 ++++++++++++++++++++++++++---------- 1 file changed, 75 insertions(+), 29 deletions(-) diff --git a/2d/waves_vegetation/tank.py b/2d/waves_vegetation/tank.py index 1cb4dede..f0c475ed 100644 --- a/2d/waves_vegetation/tank.py +++ b/2d/waves_vegetation/tank.py @@ -9,47 +9,94 @@ from proteus.Gauges import PointGauges,LineGauges,LineIntegralGauges from proteus import WaveTools as WT +from proteus import Context +opts=Context.Options([ + ("wave_type", 'linear', "type of waves generated: 'linear', 'Nonlinear', 'single-peaked', 'double-peaked'"), + ("depth", 0.457, "water depth at leading edge of vegetation (not at wave generator)[m]"), + ("wave_height", 0.192, "wave height at leading edget of vegetation [m]"), + ("peak_period", 2.0, "Peak period [s]"), + ("peak_period2", 1.5, "Second peak period (only used in double-peaked case)[s]"), + ("peak_wavelength",3.91,"Peak wavelength in [m]"), + ("parallel", False, "Run in parallel")]) #wave generator windVelocity = (0.0,0.0) -depth = 17.2/44.0 + 6.1/20.0 + 0.457 -inflowHeightMean = 17.2/44.0 + 6.1/20.0 + 0.457 +veg_platform_height = 17.2/44.0 + 6.1/20.0 +depth = veg_platform_height + opts.depth +inflowHeightMean = depth inflowVelocityMean = (0.0,0.0) -period = 2.0 +period = opts.peak_period omega = 2.0*math.pi/period -waveheight = 0.192 +waveheight = opts.wave_height amplitude = waveheight/ 2.0 -wavelength = 3.91 +wavelength = opts.peak_wavelength k = 2.0*math.pi/wavelength waveDir = numpy.array([1,0,0]) g = numpy.array([0,-9.81,0]) -waves = WT.RandomWaves( Tp = period, # Peak period - Hs = waveheight, # Height - d = depth, # Depth - fp = 1./period, #peak Frequency - bandFactor = 2.0, #fmin=fp/Bandfactor, fmax = Bandfactor * fp - N = 101, #No of frequencies for signal reconstruction - mwl = inflowHeightMean, # Sea water level - waveDir = waveDir, # waveDirection - g = g, # Gravity vector, defines the vertical - gamma=3.3, - spec_fun = WT.JONSWAP) -waves = WT.MonochromaticWaves( period = period, # Peak period - waveHeight = waveheight, # Height - depth = depth, # Depth - mwl = inflowHeightMean, # Sea water level - waveDir = waveDir, # waveDirection - g = g, # Gravity vector, defines the vertical - waveType="Linear") - - +if opts.wave_type == 'linear': + waves = WT.MonochromaticWaves(period = period, # Peak period + waveHeight = waveheight, # Height + depth = depth, # Depth + mwl = inflowHeightMean, # Sea water level + waveDir = waveDir, # waveDirection + g = g, # Gravity vector, defines the vertical + waveType="Linear") +elif opts.wave_type == 'nonlinear': + waves = WT.MonochromaticWaves(period = period, # Peak period + waveHeight = waveheight, # Height + depth = depth, # Depth + mwl = inflowHeightMean, # Sea water level + waveDir = waveDir, # waveDirection + g = g, # Gravity vector, defines the vertical + waveType="Fenton", + Y = [0.04160592, #Surface elevation Fourier coefficients for non-dimensionalised solution + 0.00555874, + 0.00065892, + 0.00008144, + 0.00001078, + 0.00000151, + 0.00000023, + 0.00000007], + B = [0.05395079, + 0.00357780, + 0.00020506, + 0.00000719, + -0.00000016, + -0.00000005, + 0.00000000, + 0.00000000]) +elif opts.wave_type == 'single-peaked': + waves = WT.RandomWaves( Tp = period, # Peak period + Hs = waveheight, # Height + d = depth, # Depth + fp = 1./period, #peak Frequency + bandFactor = 2.0, #fmin=fp/Bandfactor, fmax = Bandfactor * fp + N = 101, #No of frequencies for signal reconstruction + mwl = inflowHeightMean, # Sea water level + waveDir = waveDir, # waveDirection + g = g, # Gravity vector, defines the vertical + gamma=3.3, + spec_fun = WT.JONSWAP) +elif opts.wave_type == 'double-peaked': + waves = WT.DoublePeakedRandomWaves( Tp = period, # Peak period + Hs = waveheight, # Height + d = depth, # Depth + fp = 1./period, #peak Frequency + bandFactor = 2.0, #fmin=fp/Bandfactor, fmax = Bandfactor * fp + N = 101, #No of frequencies for signal reconstruction + mwl = inflowHeightMean, # Sea water level + waveDir = waveDir, # waveDirection + g = g, # Gravity vector, defines the vertical + gamma=10.0, + spec_fun = WT.JONSWAP, + Tp_2 = opts.peak_period2) # Discretization -- input options genMesh=True movingDomain=False applyRedistancing=True useOldPETSc=False -useSuperlu=True +useSuperlu=not opts.parallel timeDiscretization='be'#'be','vbdf','flcbdf' spaceOrder = 1 useHex = False @@ -441,10 +488,9 @@ def waveHeight(x,t): def waveVelocity_u(x,t): return waves.u(x[0],x[1],x[2],t,"x") def waveVelocity_v(x,t): - return waves.u(x[0],x[1],x[2],t,"y") + return waves.u(x[0],x[1],x[2],t,"y") def waveVelocity_w(x,t): - return waves.u(x[0],x[1],x[2],t,"z") - + return waves.u(x[0],x[1],x[2],t,"z") #solution variables From fd81767895fcb9ecd02fd1e4c248f9c7a6890f35 Mon Sep 17 00:00:00 2001 From: Steve Mattis Date: Wed, 7 Oct 2015 22:43:30 -0500 Subject: [PATCH 09/20] adds 3d waves problem from 2d data --- .../ls_consrv_n.py | 48 ++ .../ls_consrv_p.py | 26 + .../wavetank_vegetation_from_2d/ls_n.py | 63 ++ .../wavetank_vegetation_from_2d/ls_p.py | 29 + .../wavetank_vegetation_from_2d/redist_n.py | 66 +++ .../wavetank_vegetation_from_2d/redist_p.py | 32 + .../wavetank_vegetation_from_2d/tank3D.py | 552 ++++++++++++++++++ .../wavetank_vegetation_from_2d/tank3D_so.py | 41 ++ .../twp_navier_stokes_n.py | 69 +++ .../twp_navier_stokes_p.py | 218 +++++++ .../vegZoneVelocityInterp.py | 43 ++ .../wavetank_vegetation_from_2d/vof_n.py | 65 +++ .../wavetank_vegetation_from_2d/vof_p.py | 47 ++ 13 files changed, 1299 insertions(+) create mode 100644 3d/waves_vegetation/wavetank_vegetation_from_2d/ls_consrv_n.py create mode 100644 3d/waves_vegetation/wavetank_vegetation_from_2d/ls_consrv_p.py create mode 100644 3d/waves_vegetation/wavetank_vegetation_from_2d/ls_n.py create mode 100644 3d/waves_vegetation/wavetank_vegetation_from_2d/ls_p.py create mode 100644 3d/waves_vegetation/wavetank_vegetation_from_2d/redist_n.py create mode 100644 3d/waves_vegetation/wavetank_vegetation_from_2d/redist_p.py create mode 100644 3d/waves_vegetation/wavetank_vegetation_from_2d/tank3D.py create mode 100644 3d/waves_vegetation/wavetank_vegetation_from_2d/tank3D_so.py create mode 100644 3d/waves_vegetation/wavetank_vegetation_from_2d/twp_navier_stokes_n.py create mode 100644 3d/waves_vegetation/wavetank_vegetation_from_2d/twp_navier_stokes_p.py create mode 100644 3d/waves_vegetation/wavetank_vegetation_from_2d/vegZoneVelocityInterp.py create mode 100644 3d/waves_vegetation/wavetank_vegetation_from_2d/vof_n.py create mode 100644 3d/waves_vegetation/wavetank_vegetation_from_2d/vof_p.py diff --git a/3d/waves_vegetation/wavetank_vegetation_from_2d/ls_consrv_n.py b/3d/waves_vegetation/wavetank_vegetation_from_2d/ls_consrv_n.py new file mode 100644 index 00000000..d6fdb0a9 --- /dev/null +++ b/3d/waves_vegetation/wavetank_vegetation_from_2d/ls_consrv_n.py @@ -0,0 +1,48 @@ +from proteus import * +from tank3D import * +from ls_consrv_p import * + +timeIntegrator = ForwardIntegrator +timeIntegration = NoIntegration + +femSpaces = {0:basis} + +subgridError = None +massLumping = False +numericalFluxType = DoNothing +conservativeFlux = None +shockCapturing = None + +fullNewtonFlag = True +multilevelNonlinearSolver = Newton +levelNonlinearSolver = Newton + +nonlinearSmoother = None +linearSmoother = None + +matrix = SparseMatrix + +if useOldPETSc: + multilevelLinearSolver = PETSc + levelLinearSolver = PETSc +else: + multilevelLinearSolver = KSP_petsc4py + levelLinearSolver = KSP_petsc4py + +if useSuperlu: + multilevelLinearSolver = LU + levelLinearSolver = LU + +linear_solver_options_prefix = 'mcorr_' +nonlinearSolverConvergenceTest = 'r' +levelNonlinearSolverConvergenceTest = 'r' +linearSolverConvergenceTest = 'r-true' + +tolFac = 0.0 +linTolFac = 0.01 +l_atol_res = 0.01*mcorr_nl_atol_res +nl_atol_res = mcorr_nl_atol_res +useEisenstatWalker = False + +maxNonlinearIts = 50 +maxLineSearches = 0 diff --git a/3d/waves_vegetation/wavetank_vegetation_from_2d/ls_consrv_p.py b/3d/waves_vegetation/wavetank_vegetation_from_2d/ls_consrv_p.py new file mode 100644 index 00000000..ceb09427 --- /dev/null +++ b/3d/waves_vegetation/wavetank_vegetation_from_2d/ls_consrv_p.py @@ -0,0 +1,26 @@ +from proteus import * +from proteus.default_p import * +from tank3D import * +from proteus.mprans import MCorr + +LevelModelType = MCorr.LevelModel + +coefficients = MCorr.Coefficients(LSModel_index=2,V_model=0,me_model=4,VOFModel_index=1, + applyCorrection=applyCorrection,nd=nd,checkMass=False,useMetrics=useMetrics, + epsFactHeaviside=epsFact_consrv_heaviside, + epsFactDirac=epsFact_consrv_dirac, + epsFactDiffusion=epsFact_consrv_diffusion) + +class zero_phi: + def __init__(self): + pass + def uOfX(self,X): + return 0.0 + def uOfXT(self,X,t): + return 0.0 + +initialConditions = {0:zero_phi()} + + + + diff --git a/3d/waves_vegetation/wavetank_vegetation_from_2d/ls_n.py b/3d/waves_vegetation/wavetank_vegetation_from_2d/ls_n.py new file mode 100644 index 00000000..fde02e06 --- /dev/null +++ b/3d/waves_vegetation/wavetank_vegetation_from_2d/ls_n.py @@ -0,0 +1,63 @@ +from proteus import * +from ls_p import * + +if timeDiscretization=='vbdf': + timeIntegration = VBDF + timeOrder=2 + stepController = Min_dt_cfl_controller +elif timeDiscretization=='flcbdf': + timeIntegration = FLCBDF + #stepController = FLCBDF_controller + stepController = Min_dt_cfl_controller + time_tol = 10.0*ls_nl_atol_res + atol_u = {0:time_tol} + rtol_u = {0:time_tol} +else: + timeIntegration = BackwardEuler_cfl + stepController = Min_dt_cfl_controller + +femSpaces = {0:basis} + +massLumping = False +conservativeFlux = None +numericalFluxType = NCLS.NumericalFlux +subgridError = NCLS.SubgridError(coefficients,nd) +shockCapturing = NCLS.ShockCapturing(coefficients,nd,shockCapturingFactor=ls_shockCapturingFactor,lag=ls_lag_shockCapturing) + +fullNewtonFlag = True +multilevelNonlinearSolver = Newton +levelNonlinearSolver = Newton + +nonlinearSmoother = None +linearSmoother = None + +matrix = SparseMatrix + +if useOldPETSc: + multilevelLinearSolver = PETSc + levelLinearSolver = PETSc +else: + multilevelLinearSolver = KSP_petsc4py + levelLinearSolver = KSP_petsc4py + +if useSuperlu: + multilevelLinearSolver = LU + levelLinearSolver = LU + +linear_solver_options_prefix = 'ncls_' +nonlinearSolverConvergenceTest = 'r' +levelNonlinearSolverConvergenceTest = 'r' +linearSolverConvergenceTest = 'r-true' + +tolFac = 0.0 +nl_atol_res = ls_nl_atol_res + +linTolFac = 0.0 +l_atol_res = 0.1*ls_nl_atol_res + +useEisenstatWalker = False + +maxNonlinearIts = 50 +maxLineSearches = 0 + + diff --git a/3d/waves_vegetation/wavetank_vegetation_from_2d/ls_p.py b/3d/waves_vegetation/wavetank_vegetation_from_2d/ls_p.py new file mode 100644 index 00000000..9d6237c1 --- /dev/null +++ b/3d/waves_vegetation/wavetank_vegetation_from_2d/ls_p.py @@ -0,0 +1,29 @@ +from proteus import * +from proteus.default_p import * +from tank3D import * +from proteus.mprans import NCLS + +LevelModelType = NCLS.LevelModel + +coefficients = NCLS.Coefficients(V_model=0,RD_model=3,ME_model=2, + checkMass=False, useMetrics=useMetrics, + epsFact=epsFact_consrv_heaviside,sc_uref=ls_sc_uref,sc_beta=ls_sc_beta,movingDomain=movingDomain) + +def getDBC_ls(x,flag): + if flag == boundaryTags['left']: + return wavePhi +# elif flag == boundaryTags['right']: +# return outflowPhi + else: + return None + +dirichletConditions = {0:getDBC_ls} + +advectiveFluxBoundaryConditions = {} +diffusiveFluxBoundaryConditions = {0:{}} + +class PerturbedSurface_phi: + def uOfXT(self,x,t): + return signedDistance(x) + +initialConditions = {0:PerturbedSurface_phi()} diff --git a/3d/waves_vegetation/wavetank_vegetation_from_2d/redist_n.py b/3d/waves_vegetation/wavetank_vegetation_from_2d/redist_n.py new file mode 100644 index 00000000..4f85688b --- /dev/null +++ b/3d/waves_vegetation/wavetank_vegetation_from_2d/redist_n.py @@ -0,0 +1,66 @@ +from proteus import * +from redist_p import * +from tank3D import * + +nl_atol_res = rd_nl_atol_res +tolFac = 0.0 +nl_atol_res = rd_nl_atol_res + +linTolFac = 0.01 +l_atol_res = 0.01*rd_nl_atol_res + +if redist_Newton: + timeIntegration = NoIntegration + stepController = Newton_controller + maxNonlinearIts = 50 + maxLineSearches = 0 + nonlinearSolverConvergenceTest = 'r' + levelNonlinearSolverConvergenceTest = 'r' + linearSolverConvergenceTest = 'r-true' + useEisenstatWalker = False +else: + timeIntegration = BackwardEuler_cfl + stepController = RDLS.PsiTC + runCFL=2.0 + psitc['nStepsForce']=3 + psitc['nStepsMax']=50 + psitc['reduceRatio']=2.0 + psitc['startRatio']=1.0 + rtol_res[0] = 0.0 + atol_res[0] = rd_nl_atol_res + useEisenstatWalker = False + maxNonlinearIts = 1 + maxLineSearches = 0 + nonlinearSolverConvergenceTest = 'rits' + levelNonlinearSolverConvergenceTest = 'rits' + linearSolverConvergenceTest = 'r-true' + +femSpaces = {0:basis} + +massLumping = False +numericalFluxType = DoNothing +conservativeFlux = None +subgridError = RDLS.SubgridError(coefficients,nd) +shockCapturing = RDLS.ShockCapturing(coefficients,nd,shockCapturingFactor=rd_shockCapturingFactor,lag=rd_lag_shockCapturing) + +fullNewtonFlag = True +multilevelNonlinearSolver = Newton +levelNonlinearSolver = Newton + +nonlinearSmoother = NLGaussSeidel +linearSmoother = None + +matrix = SparseMatrix + +if useOldPETSc: + multilevelLinearSolver = PETSc + levelLinearSolver = PETSc +else: + multilevelLinearSolver = KSP_petsc4py + levelLinearSolver = KSP_petsc4py + +if useSuperlu: + multilevelLinearSolver = LU + levelLinearSolver = LU + +linear_solver_options_prefix = 'rdls_' diff --git a/3d/waves_vegetation/wavetank_vegetation_from_2d/redist_p.py b/3d/waves_vegetation/wavetank_vegetation_from_2d/redist_p.py new file mode 100644 index 00000000..ea199426 --- /dev/null +++ b/3d/waves_vegetation/wavetank_vegetation_from_2d/redist_p.py @@ -0,0 +1,32 @@ +from proteus import * +from proteus.default_p import * +from math import * +from tank3D import * +from proteus.mprans import RDLS +""" +The redistancing equation in the sloshbox test problem. +""" + +LevelModelType = RDLS.LevelModel + +coefficients = RDLS.Coefficients(applyRedistancing=applyRedistancing, + epsFact=epsFact_redistance, + nModelId=2, + rdModelId=3, + useMetrics=useMetrics, + backgroundDiffusionFactor=backgroundDiffusionFactor) + +def getDBC_rd(x,flag): + pass + +dirichletConditions = {0:getDBC_rd} +weakDirichletConditions = {0:RDLS.setZeroLSweakDirichletBCsSimple} + +advectiveFluxBoundaryConditions = {} +diffusiveFluxBoundaryConditions = {0:{}} + +class PerturbedSurface_phi: + def uOfXT(self,x,t): + return signedDistance(x) + +initialConditions = {0:PerturbedSurface_phi()} diff --git a/3d/waves_vegetation/wavetank_vegetation_from_2d/tank3D.py b/3d/waves_vegetation/wavetank_vegetation_from_2d/tank3D.py new file mode 100644 index 00000000..51455672 --- /dev/null +++ b/3d/waves_vegetation/wavetank_vegetation_from_2d/tank3D.py @@ -0,0 +1,552 @@ +from math import * +import proteus.MeshTools +from proteus import Domain +from proteus.default_n import * +from proteus.Profiling import logEvent +from proteus.ctransportCoefficients import smoothedHeaviside +from proteus.ctransportCoefficients import smoothedHeaviside_integral +from proteus import Gauges +from proteus.Gauges import PointGauges,LineGauges,LineIntegralGauges +from proteus.WaveTools import timeSeries +import vegZoneVelocityInterp as vegZoneInterp + +height_2d = 0.6959 +# Domain and mesh +L = (15.0, 0.5, 1.0) + +he = 1.0/20.0 + +#wave generator +windVelocity = (0.0,0.0,0.0) +inflowHeightMean = vegZoneInterp.interp_phi.__call__(0.0) +inflowVelocityMean = (0.0,0.0,0.0) +period = 1.0 +g = [0.0,0.0,-9.8] + + +# Discretization -- input options + +genMesh=True +movingDomain=False +applyRedistancing=True +useOldPETSc=False +useSuperlu=False +timeDiscretization='be'#'vbdf'#'be','flcbdf' +spaceOrder = 1 +useHex = False +useRBLES = 0.0 +useMetrics = 1.0 +applyCorrection=True +useVF = 1.0 +useOnlyVF = False +useRANS = 0 # 0 -- None + # 1 -- K-Epsilon + # 2 -- K-Omega +# Input checks +if spaceOrder not in [1,2]: + print "INVALID: spaceOrder" + spaceOrder + sys.exit() + +if useRBLES not in [0.0, 1.0]: + print "INVALID: useRBLES" + useRBLES + sys.exit() + +if useMetrics not in [0.0, 1.0]: + print "INVALID: useMetrics" + sys.exit() + +# Discretization +nd = 3 +if spaceOrder == 1: + hFactor=1.0 + if useHex: + basis=C0_AffineLinearOnCubeWithNodalBasis + elementQuadrature = CubeGaussQuadrature(nd,2) + elementBoundaryQuadrature = CubeGaussQuadrature(nd-1,2) + else: + basis=C0_AffineLinearOnSimplexWithNodalBasis + elementQuadrature = SimplexGaussQuadrature(nd,3) + elementBoundaryQuadrature = SimplexGaussQuadrature(nd-1,3) +elif spaceOrder == 2: + hFactor=0.5 + if useHex: + basis=C0_AffineLagrangeOnCubeWithNodalBasis + elementQuadrature = CubeGaussQuadrature(nd,4) + elementBoundaryQuadrature = CubeGaussQuadrature(nd-1,4) + else: + basis=C0_AffineQuadraticOnSimplexWithNodalBasis + elementQuadrature = SimplexGaussQuadrature(nd,4) + elementBoundaryQuadrature = SimplexGaussQuadrature(nd-1,4) + + +GenerationZoneLength = 1.2 +AbsorptionZoneLength= 2.8 +spongeLayer = True #False +levee=spongeLayer +slopingSpongeLayer=spongeLayer +xSponge = GenerationZoneLength +ySponge = 0.5 +xRelaxCenter = xSponge/2.0 +epsFact_solid = xSponge/2.0 +#zone 2 +xSponge_2 = L[0]-AbsorptionZoneLength +ySponge_3= L[1]- ySponge +xRelaxCenter_2 = 0.5*(xSponge_2+L[0]) +epsFact_solid_2 = AbsorptionZoneLength/2.0 + +nLevels = 1 +weak_bc_penalty_constant = 100.0 +quasi2D=False +if quasi2D:#make tank one element wide + L = (L[0],he,L[2]) + +#parallelPartitioningType = proteus.MeshTools.MeshParallelPartitioningTypes.element +parallelPartitioningType = proteus.MeshTools.MeshParallelPartitioningTypes.node +nLayersOfOverlapForParallel = 0 + +structured=False + +gauge_dx=5.0 +PGL=[] +LGL=[] +for i in range(0,int(L[0]/gauge_dx+1)): #+1 only if gauge_dx is an exact + PGL.append([gauge_dx*i,L[1]/2.0,0.5]) + LGL.append([(gauge_dx*i,L[1]/2.0,0),(gauge_dx*i,L[1]/2.0,L[2])]) + + +gaugeLocations=tuple(map(tuple,PGL)) +columnLines=tuple(map(tuple,LGL)) + + +pointGauges = PointGauges(gauges=((('u','v'), gaugeLocations), + (('p',), gaugeLocations)), + activeTime = (0, 1000.0), + sampleRate = 0, + fileName = 'combined_gauge_0_0.5_sample_all.txt') + + +fields = ('vof',) + +columnGauge = LineIntegralGauges(gauges=((fields, columnLines),), + fileName='column_gauge.csv') + +#lineGauges = LineGauges(gaugeEndpoints={'lineGauge_y=0':((0.0,0.0,0.0),(L[0],0.0,0.0))},linePoints=24) + +#lineGauges_phi = LineGauges_phi(lineGauges.endpoints,linePoints=20) + + +if useHex: + nnx=4*Refinement+1 + nny=2*Refinement+1 + hex=True + domain = Domain.RectangularDomain(L) +else: + boundaries=['empty','left','right','bottom','top','front','back'] + boundaryTags=dict([(key,i+1) for (i,key) in enumerate(boundaries)]) + if structured: + nnx=4*Refinement + nny=2*Refinement + domain = Domain.RectangularDomain(L) + elif spongeLayer: + vertices=[[0.0,0.0,0.0],#0 + [xSponge,0.0,0.0],#1 + [xSponge_2,0.0,0.0],#2 + [L[0],0.0,0.0],#3 + [L[0],L[1],0.0],#4 + [xSponge_2,L[1],0.0],#5 + [xSponge,L[1],0.0],#6 + [0.0,L[1],0.0]]#7 + + + vertexFlags=[boundaryTags['bottom'], + boundaryTags['bottom'], + boundaryTags['bottom'], + boundaryTags['bottom'], + boundaryTags['bottom'], + boundaryTags['bottom'], + boundaryTags['bottom'], + boundaryTags['bottom']] + + + for v,vf in zip(vertices,vertexFlags): + vertices.append([v[0],v[1],L[2]]) + vertexFlags.append(boundaryTags['top']) + + print vertices + print vertexFlags + + segments=[[0,1], + [1,2], + [2,3], + [3,4], + [4,5], + [5,6], + [6,7], + [7,0], + [1,6], + [2,5]] + + segmentFlags=[boundaryTags['front'], + boundaryTags['front'], + boundaryTags['front'], + boundaryTags['right'], + boundaryTags['back'], + boundaryTags['back'], + boundaryTags['back'], + boundaryTags['left'], + boundaryTags['empty'], + boundaryTags['empty'] ] + + + facets=[] + facetFlags=[] + + for s,sF in zip(segments,segmentFlags): + facets.append([[s[0],s[1],s[1]+8,s[0]+8]]) + facetFlags.append(sF) + + bf=[[0,1,6,7],[1,2,5,6],[2,3,4,5]] + tf=[] + for i in range(0,3): + facets.append([bf[i]]) + tf=[ss + 8 for ss in bf[i]] + facets.append([tf]) + + for i in range(0,3): + facetFlags.append(boundaryTags['bottom']) + facetFlags.append(boundaryTags['top']) + + print facets + print facetFlags + + regions=[[xRelaxCenter, 0.5*L[1],0.0], + [xRelaxCenter_2, 0.5*L[1], 0.0], + [0.5*L[0],0.1*L[1], 0.0]] + regionFlags=[1,2,3] + + domain = Domain.PiecewiseLinearComplexDomain(vertices=vertices, + vertexFlags=vertexFlags, + facets=facets, + facetFlags=facetFlags, + regions=regions, + regionFlags=regionFlags, + ) + #go ahead and add a boundary tags member + domain.boundaryTags = boundaryTags + domain.writePoly("mesh") + domain.writePLY("mesh") + domain.writeAsymptote("mesh") + triangleOptions="KVApq1.4q12feena%21.16e" % ((he**3)/6.0,) + + + logEvent("""Mesh generated using: tetgen -%s %s""" % (triangleOptions,domain.polyfile+".poly")) + + porosityTypes = numpy.array([1.0, + 1.0, + 1.0, + 1.0]) + dragAlphaTypes = numpy.array([0.0, + 0.5/1.004e-6, + 0.5/1.004e-6, + 0.0]) + + dragBetaTypes = numpy.array([0.0,0.0,0.0,0.0]) + + epsFact_solidTypes = np.array([0.0,epsFact_solid,epsFact_solid_2,0.0]) + + else: + vertices=[[0.0,0.0,0.0],#0 + [L[0],0.0,0.0],#1 + [L[0],L[1],0.0],#2 + [0.0,L[1],0.0]]#3 + + + vertexFlags=[boundaryTags['bottom'], + boundaryTags['bottom'], + boundaryTags['bottom'], + boundaryTags['bottom']] + + + for v,vf in zip(vertices,vertexFlags): + vertices.append([v[0],v[1],L[2]]) + vertexFlags.append(boundaryTags['top']) + + segments=[[0,1], + [1,2], + [2,3], + [3,0]] + + segmentFlags=[boundaryTags['front'], + boundaryTags['right'], + boundaryTags['back'], + boundaryTags['left']] + + facets=[] + facetFlags=[] + + for s,sF in zip(segments,segmentFlags): + facets.append([[s[0],s[1],s[1]+4,s[0]+4]]) + facetFlags.append(sF) + + bf=[[0,1,2,3]] + tf=[] + for i in range(0,1): + facets.append([bf[i]]) + tf=[ss + 4 for ss in bf[i]] + facets.append([tf]) + + for i in range(0,1): + facetFlags.append(boundaryTags['bottom']) + facetFlags.append(boundaryTags['top']) + + for s,sF in zip(segments,segmentFlags): + segments.append([s[1]+4,s[0]+4]) + segmentFlags.append(sF) + + + regions=[[0.5*L[0],0.5*L[1], 0.0]] + regionFlags=[1] + + domain = Domain.PiecewiseLinearComplexDomain(vertices=vertices, + vertexFlags=vertexFlags, + facets=facets, + facetFlags=facetFlags, + regions=regions, + regionFlags=regionFlags) + #go ahead and add a boundary tags member + domain.boundaryTags = boundaryTags + domain.writePoly("mesh") + domain.writePLY("mesh") + domain.writeAsymptote("mesh") + triangleOptions="KVApq1.4q12feena%21.16e" % ((he**3)/6.0,) + + + logEvent("""Mesh generated using: tetgen -%s %s""" % (triangleOptions,domain.polyfile+".poly")) + +# Time stepping +T=2.0*period +dt_fixed = period/20.0 +dt_init = min(0.1*dt_fixed,0.1*he) +runCFL=0.90 +nDTout = int(round(T/dt_fixed)) + +# Numerical parameters +ns_forceStrongDirichlet = True #False#True +backgroundDiffusionFactor=0.01 +if useMetrics: + ns_shockCapturingFactor = 0.25 + ns_lag_shockCapturing = True + ns_lag_subgridError = True + ls_shockCapturingFactor = 0.25 + ls_lag_shockCapturing = True + ls_sc_uref = 1.0 + ls_sc_beta = 1.0 + vof_shockCapturingFactor = 0.25 + vof_lag_shockCapturing = True + vof_sc_uref = 1.0 + vof_sc_beta = 1.0 + rd_shockCapturingFactor = 0.25 + rd_lag_shockCapturing = False + epsFact_density = 3.0 + epsFact_viscosity = epsFact_curvature = epsFact_vof = epsFact_consrv_heaviside = epsFact_consrv_dirac = epsFact_density + epsFact_redistance = 0.33 + epsFact_consrv_diffusion = 0.1 + redist_Newton = False + kappa_shockCapturingFactor = 0.1 + kappa_lag_shockCapturing = True#False + kappa_sc_uref = 1.0 + kappa_sc_beta = 1.0 + dissipation_shockCapturingFactor = 0.1 + dissipation_lag_shockCapturing = True#False + dissipation_sc_uref = 1.0 + dissipation_sc_beta = 1.0 +else: + ns_shockCapturingFactor = 0.9 + ns_lag_shockCapturing = True + ns_lag_subgridError = True + ls_shockCapturingFactor = 0.9 + ls_lag_shockCapturing = True + ls_sc_uref = 1.0 + ls_sc_beta = 1.0 + vof_shockCapturingFactor = 0.9 + vof_lag_shockCapturing = True + vof_sc_uref = 1.0 + vof_sc_beta = 1.0 + rd_shockCapturingFactor = 0.9 + rd_lag_shockCapturing = False + epsFact_density = 1.5 + epsFact_viscosity = epsFact_curvature = epsFact_vof = epsFact_consrv_heaviside = epsFact_consrv_dirac = epsFact_density + epsFact_redistance = 0.33 + epsFact_consrv_diffusion = 1.0 + redist_Newton = False + kappa_shockCapturingFactor = 0.9 + kappa_lag_shockCapturing = True#False + kappa_sc_uref = 1.0 + kappa_sc_beta = 1.0 + dissipation_shockCapturingFactor = 0.9 + dissipation_lag_shockCapturing = True#False + dissipation_sc_uref = 1.0 + dissipation_sc_beta = 1.0 + +ns_nl_atol_res = max(1.0e-10,0.001*he**2) +vof_nl_atol_res = max(1.0e-10,0.001*he**2) +ls_nl_atol_res = max(1.0e-10,0.001*he**2) +rd_nl_atol_res = max(1.0e-10,0.005*he) +mcorr_nl_atol_res = max(1.0e-10,0.001*he**2) +kappa_nl_atol_res = max(1.0e-10,0.001*he**2) +dissipation_nl_atol_res = max(1.0e-10,0.001*he**2) + +#turbulence +ns_closure=2 #1-classic smagorinsky, 2-dynamic smagorinsky, 3 -- k-epsilon, 4 -- k-omega +if useRANS == 1: + ns_closure = 3 +elif useRANS == 2: + ns_closure == 4 +# Water +rho_0 = 998.2 +nu_0 = 1.004e-6 + +# Air +rho_1 = 1.205 +nu_1 = 1.500e-5 + +# Surface tension +sigma_01 = 0.0 + + +# Initial condition +waterLine_x = 2*L[0] +waterLine_z = inflowHeightMean +waterLine_y = 2*L[1] + +def signedDistance(x): + phi_z = x[2]-waterLine_z + return phi_z + +def theta(x,t): + return k*x[0] - omega*t + math.pi/2.0 + +def z(x): + return x[2] - inflowHeightMean + +def ramp(t): + t0=10 #ramptime + if tinflowHeightMean: + return (L[2]-x[2])*rho_1*abs(g[2]) + else: + return (L[2]-inflowHeightMean)*rho_1*abs(g[2])+(inflowHeightMean-x[2])*rho_0*abs(g[2]) + +def waterVelocity(x,t): + if x[2]>inflowHeightMean: + return 0.0 + else: + ic=inflowVelocityMean[0] + return ic + +def zeroVel(x,t): + return 0.0 + + +beam_quadOrder=3 +beam_useSparse=False +beamFilename="wavetankBeams" +#nBeamElements=max(nBeamElements,3) + +#beam info +beamLocation=[] +beamLength=[] +beamRadius=[] +EI=[] +GJ=[] +lam = 0.05 #3.0*2.54/100.0 #57.4e-3 +lamx = 3.0**0.5*lam +xs = 1.2 +ys = 0.0 +xList=[] +yList = [] +while xs <= 11.0: + xList.append(xs) + xs += lam +while ys<= L[1]: + yList.append(ys) + ys+=lamx +for i in xList: + for j in yList: + beamLocation.append((i,j)) + beamLength.append(0.415) + beamRadius.append(0.0032) + EI.append(3.0e-4) # needs to be fixed + GJ.append(1.5e-4) # needs to be fixed + +xs = 1.2+0.5*lam +ys = 0.5*lamx +xList=[] +yList = [] +while xs <= 11.0: + xList.append(xs) + xs += lam + +while ys<= L[1]: + yList.append(ys) + ys+=lamx + +for i in xList: + for j in yList: + beamLocation.append((i,j)) + beamLength.append(0.415) + beamRadius.append(0.0032) + EI.append(3.0e-4) # needs to be fixed + GJ.append(1.5e-4) # needs to be fixed +nBeamElements = int(beamLength[0]/he*0.5) +nBeamElements=max(nBeamElements,3) +print nBeamElements diff --git a/3d/waves_vegetation/wavetank_vegetation_from_2d/tank3D_so.py b/3d/waves_vegetation/wavetank_vegetation_from_2d/tank3D_so.py new file mode 100644 index 00000000..f8c11c9b --- /dev/null +++ b/3d/waves_vegetation/wavetank_vegetation_from_2d/tank3D_so.py @@ -0,0 +1,41 @@ +from proteus.default_so import * +import tank3D + +if tank3D.useOnlyVF: + pnList = [("twp_navier_stokes_p", "twp_navier_stokes_n"), + ("vof_p", "vof_n")] +else: + pnList = [("twp_navier_stokes_p", "twp_navier_stokes_n"), + ("vof_p", "vof_n"), + ("ls_p", "ls_n"), + ("redist_p", "redist_n"), + ("ls_consrv_p", "ls_consrv_n")] + + +if tank3D.useRANS > 0: + pnList.append(("kappa_p", + "kappa_n")) + pnList.append(("dissipation_p", + "dissipation_n")) +name = "tank3D_p" + +if tank3D.timeDiscretization == 'flcbdf': + systemStepControllerType = Sequential_MinFLCBDFModelStep + systemStepControllerType = Sequential_MinAdaptiveModelStep +else: + systemStepControllerType = Sequential_MinAdaptiveModelStep + +needEBQ_GLOBAL = False +needEBQ = False + +tnList = [0.0,tank3D.dt_init]+[i*tank3D.dt_fixed for i in range(1,tank3D.nDTout+1)] + +info = open("TimeList.txt","w") + + +for time in tnList: + info.write(str(time)+"\n") +info.close() + + +archiveFlag = ArchiveFlags.EVERY_SEQUENCE_STEP diff --git a/3d/waves_vegetation/wavetank_vegetation_from_2d/twp_navier_stokes_n.py b/3d/waves_vegetation/wavetank_vegetation_from_2d/twp_navier_stokes_n.py new file mode 100644 index 00000000..4e5ff8d1 --- /dev/null +++ b/3d/waves_vegetation/wavetank_vegetation_from_2d/twp_navier_stokes_n.py @@ -0,0 +1,69 @@ +from proteus import * +from twp_navier_stokes_p import * +from tank3D import * + +if timeDiscretization=='vbdf': + timeIntegration = VBDF + timeOrder=2 + stepController = Min_dt_cfl_controller +elif timeDiscretization=='flcbdf': + timeIntegration = FLCBDF + #stepController = FLCBDF_controller_sys + stepController = Min_dt_cfl_controller + time_tol = 10.0*ns_nl_atol_res + atol_u = {1:time_tol,2:time_tol,3:time_tol} + rtol_u = {1:time_tol,2:time_tol,3:time_tol} +else: + timeIntegration = BackwardEuler_cfl + stepController = Min_dt_cfl_controller + +femSpaces = {0:basis, + 1:basis, + 2:basis, + 3:basis} + +massLumping = False +numericalFluxType = None +conservativeFlux = None + +numericalFluxType = RANS2P.NumericalFlux +subgridError = RANS2P.SubgridError(coefficients,nd,lag=ns_lag_subgridError,hFactor=hFactor) +shockCapturing = RANS2P.ShockCapturing(coefficients,nd,ns_shockCapturingFactor,lag=ns_lag_shockCapturing) + +fullNewtonFlag = True +multilevelNonlinearSolver = Newton +levelNonlinearSolver = Newton + +nonlinearSmoother = None + +linearSmoother = SimpleNavierStokes3D + +matrix = SparseMatrix + +if useOldPETSc: + multilevelLinearSolver = PETSc + levelLinearSolver = PETSc +else: + multilevelLinearSolver = KSP_petsc4py + levelLinearSolver = KSP_petsc4py + +if useSuperlu: + multilevelLinearSolver = LU + levelLinearSolver = LU + +linear_solver_options_prefix = 'rans2p_' +nonlinearSolverConvergenceTest = 'r' +levelNonlinearSolverConvergenceTest = 'r' +linearSolverConvergenceTest = 'r-true' + +tolFac = 0.0 +linTolFac = 0.01 +l_atol_res = 0.01*ns_nl_atol_res +nl_atol_res = ns_nl_atol_res +useEisenstatWalker = False +maxNonlinearIts = 50 +maxLineSearches = 0 +conservativeFlux = {0:'pwl-bdm-opt'} + + +#auxiliaryVariables=[pointGauges,rzWaveGenerator] diff --git a/3d/waves_vegetation/wavetank_vegetation_from_2d/twp_navier_stokes_p.py b/3d/waves_vegetation/wavetank_vegetation_from_2d/twp_navier_stokes_p.py new file mode 100644 index 00000000..9f5c7798 --- /dev/null +++ b/3d/waves_vegetation/wavetank_vegetation_from_2d/twp_navier_stokes_p.py @@ -0,0 +1,218 @@ +from proteus import * +from proteus.default_p import * +from tank3D import * +from proteus.mprans import RANS2P +from proteus.mprans import RANS2P_IB + +LevelModelType = RANS2P_IB.LevelModel +if useOnlyVF: + LS_model = None +else: + LS_model = 2 +if useRANS >= 1: + Closure_0_model = 5; Closure_1_model=6 + if useOnlyVF: + Closure_0_model=2; Closure_1_model=3 + if movingDomain: + Closure_0_model += 1; Closure_1_model += 1 +else: + Closure_0_model = None + Closure_1_model = None + +if spongeLayer or levee or slopingSpongeLayer: + coefficients = RANS2P_IB.Coefficients(epsFact=epsFact_viscosity, + sigma=0.0, + rho_0 = rho_0, + nu_0 = nu_0, + rho_1 = rho_1, + nu_1 = nu_1, + g=g, + nd=nd, + VF_model=1, + LS_model=LS_model, + Closure_0_model=Closure_0_model, + Closure_1_model=Closure_1_model, + epsFact_density=epsFact_density, + stokes=False, + useVF=useVF, + useRBLES=useRBLES, + useMetrics=useMetrics, + eb_adjoint_sigma=1.0, + eb_penalty_constant=weak_bc_penalty_constant, + forceStrongDirichlet=ns_forceStrongDirichlet, + turbulenceClosureModel=ns_closure, + movingDomain=movingDomain, + porosityTypes=porosityTypes, + dragAlphaTypes=dragAlphaTypes, + dragBetaTypes=dragBetaTypes, + epsFact_solid = epsFact_solidTypes, + beamLocation=beamLocation, + beamLength=beamLength, + beamRadius=beamRadius, + EI=EI, + GJ=GJ, + nBeamElements=nBeamElements, + beam_quadOrder=beam_quadOrder, + beamFilename=beamFilename, + beam_Cd=1.2, + beam_nlTol=1.0e-5, + beamRigid=True) +else: + coefficients = RANS2P_IB.Coefficients(epsFact=epsFact_viscosity, + sigma=0.0, + rho_0 = rho_0, + nu_0 = nu_0, + rho_1 = rho_1, + nu_1 = nu_1, + g=g, + nd=nd, + VF_model=1, + LS_model=LS_model, + Closure_0_model=Closure_0_model, + Closure_1_model=Closure_1_model, + epsFact_density=epsFact_density, + stokes=False, + useVF=useVF, + useRBLES=useRBLES, + useMetrics=useMetrics, + eb_adjoint_sigma=1.0, + eb_penalty_constant=weak_bc_penalty_constant, + forceStrongDirichlet=ns_forceStrongDirichlet, + turbulenceClosureModel=ns_closure, + movingDomain=movingDomain, + beamLocation=beamLocation, + beamLength=beamLength, + beamRadius=beamRadius, + EI=EI, + GJ=GJ, + nBeamElements=nBeamElements, + beam_quadOrder=beam_quadOrder, + beamFilename=beamFilename, + beam_Cd=1.2, + beam_nlTol=1.0e-5, + beamRigid=True) + + +def getDBC_p(x,flag): + if flag == boundaryTags['top']: + return lambda x,t: 0.0 + elif flag == boundaryTags['right']: + return outflowPressure + +def getDBC_u(x,flag): + if flag == boundaryTags['left']: + return twpflowVelocity_u + + +def getDBC_v(x,flag): + if flag == boundaryTags['left']: + return twpflowVelocity_v + +def getDBC_w(x,flag): + if flag == boundaryTags['left']: + return twpflowVelocity_w + +dirichletConditions = {0:getDBC_p, + 1:getDBC_u, + 2:getDBC_v, + 3:getDBC_w} + +def getAFBC_p(x,flag): + if flag == boundaryTags['left']: + return lambda x,t: -twpflowVelocity_u(x,t) + elif flag == boundaryTags['bottom'] or flag == boundaryTags['back'] or flag == boundaryTags['front']: + return lambda x,t: 0.0 + elif flag == boundaryTags['right']: + return lambda x,t: 0.0 + else: + return None + +def getAFBC_u(x,flag): + if flag == boundaryTags['bottom'] or flag == boundaryTags['back'] or flag == boundaryTags['front']: + return lambda x,t: 0.0 + elif flag == boundaryTags['right']: + return lambda x,t: 0.0 + else: + return None + +def getAFBC_v(x,flag): + if flag == boundaryTags['bottom'] or flag == boundaryTags['back'] or flag == boundaryTags['front']: + return lambda x,t: 0.0 + elif flag == boundaryTags['right']: + return lambda x,t: 0.0 + else: + return None + +def getAFBC_w(x,flag): + if flag == boundaryTags['bottom'] or flag == boundaryTags['back'] or flag == boundaryTags['front']: + return lambda x,t: 0.0 + elif flag == boundaryTags['right']: + return lambda x,t: 0.0 + else: + return None + +def getDFBC_u(x,flag): + if flag != boundaryTags['left']: + return lambda x,t: 0.0 + + +def getDFBC_v(x,flag): + if flag != boundaryTags['left']: + return lambda x,t: 0.0 + + +def getDFBC_w(x,flag): + if flag != boundaryTags['left']: + return lambda x,t: 0.0 +# if flag == boundaryTags['bottom']: +# return lambda x,t: 0.0 +# elif flag == boundaryTags['back']: +# return lambda x,t: 0.0 +# elif flag == boundaryTags['front']: +# return lambda x,t: 0.0 +# elif flag == boundaryTags['right']: +# return lambda x,t: 0.0 +# elif flag == boundaryTags['top']: +# return lambda x,t: 0.0 + + +advectiveFluxBoundaryConditions = {0:getAFBC_p, + 1:getAFBC_u, + 2:getAFBC_v, + 3:getAFBC_w} + +diffusiveFluxBoundaryConditions = {0:{}, + 1:{1:getDFBC_u}, + 2:{2:getDFBC_v}, + 3:{3:getDFBC_w}} + +class PerturbedSurface_p: + def __init__(self,waterLevel): + self.waterLevel=waterLevel + def uOfXT(self,x,t): + # if signedDistance(x) < 0: + # return -(L[2] - self.waterLevel)*rho_1*g[2] - (self.waterLevel - x[2])*rho_0*g[2] + # else: + # return -(L[2] - self.waterLevel)*rho_1*g[2] + if x[2]>inflowHeightMean: + return (L[2]-x[2])*rho_1*abs(g[2]) + else: + return (L[2]-inflowHeightMean)*rho_1*abs(g[2])+(inflowHeightMean-x[2])*rho_0*abs(g[2]) + +class AtRest: + def __init__(self): + pass + def uOfXT(self,x,t): + return 0.0 + +class WaterVelocity_u: + def __init__(self): + pass + def uOfXT(self,x,t): + + return waterVelocity(x,0) + +initialConditions = {0:PerturbedSurface_p(waterLine_z), + 1:AtRest(), + 2:AtRest(), + 3:AtRest()} diff --git a/3d/waves_vegetation/wavetank_vegetation_from_2d/vegZoneVelocityInterp.py b/3d/waves_vegetation/wavetank_vegetation_from_2d/vegZoneVelocityInterp.py new file mode 100644 index 00000000..d3d763a1 --- /dev/null +++ b/3d/waves_vegetation/wavetank_vegetation_from_2d/vegZoneVelocityInterp.py @@ -0,0 +1,43 @@ +import numpy as np +import scipy.interpolate as interp +import matplotlib.pyplot as plt + +vals = np.loadtxt("vegZoneVelocity.csv", + skiprows = 1, + delimiter=',') + +f = open("vegZoneVelocity.csv", 'r') +first = f.readline() +f.close() +g = first.split(',') +zListU=[] +zListW=[] +for i in range(1,len(g)): + h = g[i].split() + if h[0] == 'u': + zListU.append(float(h[3])) + elif h[0] == 'v': + zListW.append(float(h[3])) + +time = vals[:,0] +zU = np.array(zListU) +zW = np.array(zListW) + +Uarray = vals[:,1:len(zListU)+1] +Warray = vals[:,len(zListU)+1::] + +interpU = interp.RectBivariateSpline(time,zU,Uarray, kx=1,ky=3) +interpW = interp.RectBivariateSpline(time,zW, Warray, kx=1, ky=3) +#plt.contourf(tt,zzU,Uarray) +#plt.imshow(Uarray) +#plt.show() +vals = np.loadtxt("column_gauge.csv", + skiprows=1, + delimiter=',') + + +time = vals[:,0] +water_height = vals[:,4] + +interp_phi=interp.interp1d(time,water_height) + diff --git a/3d/waves_vegetation/wavetank_vegetation_from_2d/vof_n.py b/3d/waves_vegetation/wavetank_vegetation_from_2d/vof_n.py new file mode 100644 index 00000000..de2fdd09 --- /dev/null +++ b/3d/waves_vegetation/wavetank_vegetation_from_2d/vof_n.py @@ -0,0 +1,65 @@ +from proteus import * +from tank3D import * +from vof_p import * + +if timeDiscretization=='vbdf': + timeIntegration = VBDF + timeOrder=2 + stepController = Min_dt_cfl_controller +elif timeDiscretization=='flcbdf': + timeIntegration = FLCBDF + #stepController = FLCBDF_controller + stepController = Min_dt_cfl_controller + time_tol = 10.0*vof_nl_atol_res + atol_u = {0:time_tol} + rtol_u = {0:time_tol} +else: + timeIntegration = BackwardEuler_cfl + stepController = Min_dt_cfl_controller + +femSpaces = {0:basis} + +massLumping = False +numericalFluxType = VOF.NumericalFlux +conservativeFlux = None +subgridError = VOF.SubgridError(coefficients=coefficients,nd=nd) +shockCapturing = VOF.ShockCapturing(coefficients,nd,shockCapturingFactor=vof_shockCapturingFactor,lag=vof_lag_shockCapturing) + +fullNewtonFlag = True +multilevelNonlinearSolver = Newton +levelNonlinearSolver = Newton + +nonlinearSmoother = None +linearSmoother = None + +matrix = SparseMatrix + +if useOldPETSc: + multilevelLinearSolver = PETSc + levelLinearSolver = PETSc +else: + multilevelLinearSolver = KSP_petsc4py + levelLinearSolver = KSP_petsc4py + +if useSuperlu: + multilevelLinearSolver = LU + levelLinearSolver = LU + +linear_solver_options_prefix = 'vof_' +nonlinearSolverConvergenceTest = 'r' +levelNonlinearSolverConvergenceTest = 'r' +linearSolverConvergenceTest = 'r-true' + +tolFac = 0.0 +nl_atol_res = vof_nl_atol_res + +linTolFac = 0.0 +l_atol_res = 0.1*vof_nl_atol_res + +useEisenstatWalker = False + +maxNonlinearIts = 50 +maxLineSearches = 0 + +auxiliaryVariables = [columnGauge] + diff --git a/3d/waves_vegetation/wavetank_vegetation_from_2d/vof_p.py b/3d/waves_vegetation/wavetank_vegetation_from_2d/vof_p.py new file mode 100644 index 00000000..ea33ff3b --- /dev/null +++ b/3d/waves_vegetation/wavetank_vegetation_from_2d/vof_p.py @@ -0,0 +1,47 @@ +from proteus import * +from proteus.default_p import * +from proteus.ctransportCoefficients import smoothedHeaviside +from tank3D import * +from proteus.mprans import VOF + +LevelModelType = VOF.LevelModel +if useOnlyVF: + RD_model = None + LS_model = None +else: + RD_model = 3 + LS_model = 2 + +coefficients = VOF.Coefficients(LS_model=LS_model,V_model=0,RD_model=RD_model,ME_model=1, + checkMass=False,useMetrics=useMetrics, + epsFact=epsFact_vof,sc_uref=vof_sc_uref,sc_beta=vof_sc_beta,movingDomain=movingDomain) + +def getDBC_vof(x,flag): + if flag == boundaryTags['left']: + return waveVF + elif flag == boundaryTags['top']:# or x[1] >= L[1] - 1.0e-12: + return lambda x,t: 1.0 +# elif flag == boundaryTags['right']: +# return outflowVF + + +dirichletConditions = {0:getDBC_vof} + +def getAFBC_vof(x,flag): + if flag == boundaryTags['left']: + return None + elif flag == boundaryTags['top']:# or x[1] >= L[1] - 1.0e-12: + return None +# elif flag == boundaryTags['right']: +# return None + else: + return lambda x,t: 0.0 + +advectiveFluxBoundaryConditions = {0:getAFBC_vof} +diffusiveFluxBoundaryConditions = {0:{}} + +class PerturbedSurface_H: + def uOfXT(self,x,t): + return smoothedHeaviside(epsFact_consrv_heaviside*he,signedDistance(x)) + +initialConditions = {0:PerturbedSurface_H()} From 021d397047e656262f1f174e53d218da6c2c7171 Mon Sep 17 00:00:00 2001 From: Steve Mattis Date: Thu, 8 Oct 2015 11:09:14 -0500 Subject: [PATCH 10/20] fixes bugs --- 3d/waves_vegetation/wavetank_vegetation_from_2d/tank3D.py | 8 ++++---- .../twp_navier_stokes_p.py | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/3d/waves_vegetation/wavetank_vegetation_from_2d/tank3D.py b/3d/waves_vegetation/wavetank_vegetation_from_2d/tank3D.py index 51455672..b8ad0d1b 100644 --- a/3d/waves_vegetation/wavetank_vegetation_from_2d/tank3D.py +++ b/3d/waves_vegetation/wavetank_vegetation_from_2d/tank3D.py @@ -18,7 +18,7 @@ #wave generator windVelocity = (0.0,0.0,0.0) -inflowHeightMean = vegZoneInterp.interp_phi.__call__(0.0) +inflowHeightMean = float(vegZoneInterp.interp_phi.__call__(0.0)) inflowVelocityMean = (0.0,0.0,0.0) period = 1.0 g = [0.0,0.0,-9.8] @@ -440,16 +440,16 @@ def ramp(t): # sigma = omega - k*inflowVelocityMean[0] def waveHeight(x,t): - return vegZoneInterp.interp_phi.__call__(t) + return float(vegZoneInterp.interp_phi.__call__(t)) def waveVelocity_u(x,t): - return vegZoneInterp.interpU.__call__(t,x[2]+height_2d) + return vegZoneInterp.interpU.__call__(t,x[2]+height_2d)[0][0] def waveVelocity_v(x,t): return 0.0 def waveVelocity_w(x,t): - return vegZoneInterp.interpW.__call__(t,x[2]+height_2d) + return vegZoneInterp.interpW.__call__(t,x[2]+height_2d)[0][0] #solution variables def wavePhi(x,t): diff --git a/3d/waves_vegetation/wavetank_vegetation_time_series/twp_navier_stokes_p.py b/3d/waves_vegetation/wavetank_vegetation_time_series/twp_navier_stokes_p.py index 88041868..9f5c7798 100644 --- a/3d/waves_vegetation/wavetank_vegetation_time_series/twp_navier_stokes_p.py +++ b/3d/waves_vegetation/wavetank_vegetation_time_series/twp_navier_stokes_p.py @@ -2,7 +2,7 @@ from proteus.default_p import * from tank3D import * from proteus.mprans import RANS2P -from proteus.ib import RANS2P_IB +from proteus.mprans import RANS2P_IB LevelModelType = RANS2P_IB.LevelModel if useOnlyVF: From 00398267594167d6a54de6d9a97b5b3dc7bd857c Mon Sep 17 00:00:00 2001 From: Steve Mattis Date: Thu, 8 Oct 2015 13:13:54 -0500 Subject: [PATCH 11/20] adds 3d tank generated by wavetools --- 2d/waves_vegetation/tank.py | 7 +- .../ls_consrv_n.py | 48 ++ .../ls_consrv_p.py | 26 + .../ls_n.py | 63 ++ .../ls_p.py | 29 + .../redist_n.py | 66 ++ .../redist_p.py | 32 + .../tank3D.py | 652 ++++++++++++++++++ .../tank3D_so.py | 41 ++ .../twp_navier_stokes_n.py | 69 ++ .../twp_navier_stokes_p.py | 218 ++++++ .../vof_n.py | 65 ++ .../vof_p.py | 47 ++ 13 files changed, 1360 insertions(+), 3 deletions(-) create mode 100644 3d/waves_vegetation/wavetank_vegetation_generate_from_wavetools/ls_consrv_n.py create mode 100644 3d/waves_vegetation/wavetank_vegetation_generate_from_wavetools/ls_consrv_p.py create mode 100644 3d/waves_vegetation/wavetank_vegetation_generate_from_wavetools/ls_n.py create mode 100644 3d/waves_vegetation/wavetank_vegetation_generate_from_wavetools/ls_p.py create mode 100644 3d/waves_vegetation/wavetank_vegetation_generate_from_wavetools/redist_n.py create mode 100644 3d/waves_vegetation/wavetank_vegetation_generate_from_wavetools/redist_p.py create mode 100644 3d/waves_vegetation/wavetank_vegetation_generate_from_wavetools/tank3D.py create mode 100644 3d/waves_vegetation/wavetank_vegetation_generate_from_wavetools/tank3D_so.py create mode 100644 3d/waves_vegetation/wavetank_vegetation_generate_from_wavetools/twp_navier_stokes_n.py create mode 100644 3d/waves_vegetation/wavetank_vegetation_generate_from_wavetools/twp_navier_stokes_p.py create mode 100644 3d/waves_vegetation/wavetank_vegetation_generate_from_wavetools/vof_n.py create mode 100644 3d/waves_vegetation/wavetank_vegetation_generate_from_wavetools/vof_p.py diff --git a/2d/waves_vegetation/tank.py b/2d/waves_vegetation/tank.py index f0c475ed..1a7285f9 100644 --- a/2d/waves_vegetation/tank.py +++ b/2d/waves_vegetation/tank.py @@ -41,15 +41,16 @@ waveDir = waveDir, # waveDirection g = g, # Gravity vector, defines the vertical waveType="Linear") -elif opts.wave_type == 'nonlinear': +elif opts.wave_type == 'Nonlinear': waves = WT.MonochromaticWaves(period = period, # Peak period waveHeight = waveheight, # Height + wavelength = wavelength, depth = depth, # Depth mwl = inflowHeightMean, # Sea water level waveDir = waveDir, # waveDirection g = g, # Gravity vector, defines the vertical waveType="Fenton", - Y = [0.04160592, #Surface elevation Fourier coefficients for non-dimensionalised solution + Ycoeff = [0.04160592, #Surface elevation Fourier coefficients for non-dimensionalised solution 0.00555874, 0.00065892, 0.00008144, @@ -57,7 +58,7 @@ 0.00000151, 0.00000023, 0.00000007], - B = [0.05395079, + Bcoeff = [0.05395079, 0.00357780, 0.00020506, 0.00000719, diff --git a/3d/waves_vegetation/wavetank_vegetation_generate_from_wavetools/ls_consrv_n.py b/3d/waves_vegetation/wavetank_vegetation_generate_from_wavetools/ls_consrv_n.py new file mode 100644 index 00000000..d6fdb0a9 --- /dev/null +++ b/3d/waves_vegetation/wavetank_vegetation_generate_from_wavetools/ls_consrv_n.py @@ -0,0 +1,48 @@ +from proteus import * +from tank3D import * +from ls_consrv_p import * + +timeIntegrator = ForwardIntegrator +timeIntegration = NoIntegration + +femSpaces = {0:basis} + +subgridError = None +massLumping = False +numericalFluxType = DoNothing +conservativeFlux = None +shockCapturing = None + +fullNewtonFlag = True +multilevelNonlinearSolver = Newton +levelNonlinearSolver = Newton + +nonlinearSmoother = None +linearSmoother = None + +matrix = SparseMatrix + +if useOldPETSc: + multilevelLinearSolver = PETSc + levelLinearSolver = PETSc +else: + multilevelLinearSolver = KSP_petsc4py + levelLinearSolver = KSP_petsc4py + +if useSuperlu: + multilevelLinearSolver = LU + levelLinearSolver = LU + +linear_solver_options_prefix = 'mcorr_' +nonlinearSolverConvergenceTest = 'r' +levelNonlinearSolverConvergenceTest = 'r' +linearSolverConvergenceTest = 'r-true' + +tolFac = 0.0 +linTolFac = 0.01 +l_atol_res = 0.01*mcorr_nl_atol_res +nl_atol_res = mcorr_nl_atol_res +useEisenstatWalker = False + +maxNonlinearIts = 50 +maxLineSearches = 0 diff --git a/3d/waves_vegetation/wavetank_vegetation_generate_from_wavetools/ls_consrv_p.py b/3d/waves_vegetation/wavetank_vegetation_generate_from_wavetools/ls_consrv_p.py new file mode 100644 index 00000000..ceb09427 --- /dev/null +++ b/3d/waves_vegetation/wavetank_vegetation_generate_from_wavetools/ls_consrv_p.py @@ -0,0 +1,26 @@ +from proteus import * +from proteus.default_p import * +from tank3D import * +from proteus.mprans import MCorr + +LevelModelType = MCorr.LevelModel + +coefficients = MCorr.Coefficients(LSModel_index=2,V_model=0,me_model=4,VOFModel_index=1, + applyCorrection=applyCorrection,nd=nd,checkMass=False,useMetrics=useMetrics, + epsFactHeaviside=epsFact_consrv_heaviside, + epsFactDirac=epsFact_consrv_dirac, + epsFactDiffusion=epsFact_consrv_diffusion) + +class zero_phi: + def __init__(self): + pass + def uOfX(self,X): + return 0.0 + def uOfXT(self,X,t): + return 0.0 + +initialConditions = {0:zero_phi()} + + + + diff --git a/3d/waves_vegetation/wavetank_vegetation_generate_from_wavetools/ls_n.py b/3d/waves_vegetation/wavetank_vegetation_generate_from_wavetools/ls_n.py new file mode 100644 index 00000000..fde02e06 --- /dev/null +++ b/3d/waves_vegetation/wavetank_vegetation_generate_from_wavetools/ls_n.py @@ -0,0 +1,63 @@ +from proteus import * +from ls_p import * + +if timeDiscretization=='vbdf': + timeIntegration = VBDF + timeOrder=2 + stepController = Min_dt_cfl_controller +elif timeDiscretization=='flcbdf': + timeIntegration = FLCBDF + #stepController = FLCBDF_controller + stepController = Min_dt_cfl_controller + time_tol = 10.0*ls_nl_atol_res + atol_u = {0:time_tol} + rtol_u = {0:time_tol} +else: + timeIntegration = BackwardEuler_cfl + stepController = Min_dt_cfl_controller + +femSpaces = {0:basis} + +massLumping = False +conservativeFlux = None +numericalFluxType = NCLS.NumericalFlux +subgridError = NCLS.SubgridError(coefficients,nd) +shockCapturing = NCLS.ShockCapturing(coefficients,nd,shockCapturingFactor=ls_shockCapturingFactor,lag=ls_lag_shockCapturing) + +fullNewtonFlag = True +multilevelNonlinearSolver = Newton +levelNonlinearSolver = Newton + +nonlinearSmoother = None +linearSmoother = None + +matrix = SparseMatrix + +if useOldPETSc: + multilevelLinearSolver = PETSc + levelLinearSolver = PETSc +else: + multilevelLinearSolver = KSP_petsc4py + levelLinearSolver = KSP_petsc4py + +if useSuperlu: + multilevelLinearSolver = LU + levelLinearSolver = LU + +linear_solver_options_prefix = 'ncls_' +nonlinearSolverConvergenceTest = 'r' +levelNonlinearSolverConvergenceTest = 'r' +linearSolverConvergenceTest = 'r-true' + +tolFac = 0.0 +nl_atol_res = ls_nl_atol_res + +linTolFac = 0.0 +l_atol_res = 0.1*ls_nl_atol_res + +useEisenstatWalker = False + +maxNonlinearIts = 50 +maxLineSearches = 0 + + diff --git a/3d/waves_vegetation/wavetank_vegetation_generate_from_wavetools/ls_p.py b/3d/waves_vegetation/wavetank_vegetation_generate_from_wavetools/ls_p.py new file mode 100644 index 00000000..9d6237c1 --- /dev/null +++ b/3d/waves_vegetation/wavetank_vegetation_generate_from_wavetools/ls_p.py @@ -0,0 +1,29 @@ +from proteus import * +from proteus.default_p import * +from tank3D import * +from proteus.mprans import NCLS + +LevelModelType = NCLS.LevelModel + +coefficients = NCLS.Coefficients(V_model=0,RD_model=3,ME_model=2, + checkMass=False, useMetrics=useMetrics, + epsFact=epsFact_consrv_heaviside,sc_uref=ls_sc_uref,sc_beta=ls_sc_beta,movingDomain=movingDomain) + +def getDBC_ls(x,flag): + if flag == boundaryTags['left']: + return wavePhi +# elif flag == boundaryTags['right']: +# return outflowPhi + else: + return None + +dirichletConditions = {0:getDBC_ls} + +advectiveFluxBoundaryConditions = {} +diffusiveFluxBoundaryConditions = {0:{}} + +class PerturbedSurface_phi: + def uOfXT(self,x,t): + return signedDistance(x) + +initialConditions = {0:PerturbedSurface_phi()} diff --git a/3d/waves_vegetation/wavetank_vegetation_generate_from_wavetools/redist_n.py b/3d/waves_vegetation/wavetank_vegetation_generate_from_wavetools/redist_n.py new file mode 100644 index 00000000..4f85688b --- /dev/null +++ b/3d/waves_vegetation/wavetank_vegetation_generate_from_wavetools/redist_n.py @@ -0,0 +1,66 @@ +from proteus import * +from redist_p import * +from tank3D import * + +nl_atol_res = rd_nl_atol_res +tolFac = 0.0 +nl_atol_res = rd_nl_atol_res + +linTolFac = 0.01 +l_atol_res = 0.01*rd_nl_atol_res + +if redist_Newton: + timeIntegration = NoIntegration + stepController = Newton_controller + maxNonlinearIts = 50 + maxLineSearches = 0 + nonlinearSolverConvergenceTest = 'r' + levelNonlinearSolverConvergenceTest = 'r' + linearSolverConvergenceTest = 'r-true' + useEisenstatWalker = False +else: + timeIntegration = BackwardEuler_cfl + stepController = RDLS.PsiTC + runCFL=2.0 + psitc['nStepsForce']=3 + psitc['nStepsMax']=50 + psitc['reduceRatio']=2.0 + psitc['startRatio']=1.0 + rtol_res[0] = 0.0 + atol_res[0] = rd_nl_atol_res + useEisenstatWalker = False + maxNonlinearIts = 1 + maxLineSearches = 0 + nonlinearSolverConvergenceTest = 'rits' + levelNonlinearSolverConvergenceTest = 'rits' + linearSolverConvergenceTest = 'r-true' + +femSpaces = {0:basis} + +massLumping = False +numericalFluxType = DoNothing +conservativeFlux = None +subgridError = RDLS.SubgridError(coefficients,nd) +shockCapturing = RDLS.ShockCapturing(coefficients,nd,shockCapturingFactor=rd_shockCapturingFactor,lag=rd_lag_shockCapturing) + +fullNewtonFlag = True +multilevelNonlinearSolver = Newton +levelNonlinearSolver = Newton + +nonlinearSmoother = NLGaussSeidel +linearSmoother = None + +matrix = SparseMatrix + +if useOldPETSc: + multilevelLinearSolver = PETSc + levelLinearSolver = PETSc +else: + multilevelLinearSolver = KSP_petsc4py + levelLinearSolver = KSP_petsc4py + +if useSuperlu: + multilevelLinearSolver = LU + levelLinearSolver = LU + +linear_solver_options_prefix = 'rdls_' diff --git a/3d/waves_vegetation/wavetank_vegetation_generate_from_wavetools/redist_p.py b/3d/waves_vegetation/wavetank_vegetation_generate_from_wavetools/redist_p.py new file mode 100644 index 00000000..ea199426 --- /dev/null +++ b/3d/waves_vegetation/wavetank_vegetation_generate_from_wavetools/redist_p.py @@ -0,0 +1,32 @@ +from proteus import * +from proteus.default_p import * +from math import * +from tank3D import * +from proteus.mprans import RDLS +""" +The redistancing equation in the sloshbox test problem. +""" + +LevelModelType = RDLS.LevelModel + +coefficients = RDLS.Coefficients(applyRedistancing=applyRedistancing, + epsFact=epsFact_redistance, + nModelId=2, + rdModelId=3, + useMetrics=useMetrics, + backgroundDiffusionFactor=backgroundDiffusionFactor) + +def getDBC_rd(x,flag): + pass + +dirichletConditions = {0:getDBC_rd} +weakDirichletConditions = {0:RDLS.setZeroLSweakDirichletBCsSimple} + +advectiveFluxBoundaryConditions = {} +diffusiveFluxBoundaryConditions = {0:{}} + +class PerturbedSurface_phi: + def uOfXT(self,x,t): + return signedDistance(x) + +initialConditions = {0:PerturbedSurface_phi()} diff --git a/3d/waves_vegetation/wavetank_vegetation_generate_from_wavetools/tank3D.py b/3d/waves_vegetation/wavetank_vegetation_generate_from_wavetools/tank3D.py new file mode 100644 index 00000000..8fe42d32 --- /dev/null +++ b/3d/waves_vegetation/wavetank_vegetation_generate_from_wavetools/tank3D.py @@ -0,0 +1,652 @@ +from math import * +import proteus.MeshTools +from proteus import Domain +from proteus.default_n import * +from proteus.Profiling import logEvent +from proteus.ctransportCoefficients import smoothedHeaviside +from proteus.ctransportCoefficients import smoothedHeaviside_integral +from proteus import Gauges +from proteus.Gauges import PointGauges,LineGauges,LineIntegralGauges +from proteus import WaveTools as WT + +from proteus import Context +opts=Context.Options([ + ("wave_type", 'linear', "type of waves generated: 'linear', 'Nonlinear', 'single-peaked', 'double-peaked'"), + ("depth", 0.457, "water depth at leading edge of vegetation (not at wave generator)[m]"), + ("wave_height", 0.192, "wave height at leading edget of vegetation [m]"), + ("peak_period", 2.0, "Peak period [s]"), + ("peak_period2", 1.5, "Second peak period (only used in double-peaked case)[s]"), + ("peak_wavelength",3.91,"Peak wavelength in [m]"), + ("parallel", False, "Run in parallel")]) + +#wave generator +windVelocity = (0.0,0.0,0.0) +#veg_platform_height = 17.2/44.0 + 6.1/20.0 +depth = opts.depth +inflowHeightMean = depth +inflowVelocityMean = (0.0,0.0,0,0) +period = opts.peak_period +omega = 2.0*math.pi/period +waveheight = opts.wave_height +amplitude = waveheight/ 2.0 +wavelength = opts.peak_wavelength +k = 2.0*math.pi/wavelength +waveDir = numpy.array([1,0,0]) +g = numpy.array([0.0,0.0,-9.81]) +if opts.wave_type == 'linear': + waves = WT.MonochromaticWaves(period = period, # Peak period + waveHeight = waveheight, # Height + depth = depth, # Depth + mwl = inflowHeightMean, # Sea water level + waveDir = waveDir, # waveDirection + g = g, # Gravity vector, defines the vertical + waveType="Linear") +elif opts.wave_type == 'Nonlinear': + waves = WT.MonochromaticWaves(period = period, # Peak period + waveHeight = waveheight, # Height + wavelength = wavelength, + depth = depth, # Depth + mwl = inflowHeightMean, # Sea water level + waveDir = waveDir, # waveDirection + g = g, # Gravity vector, defines the vertical + waveType="Fenton", + Ycoeff = [0.04160592, #Surface elevation Fourier coefficients for non-dimensionalised solution + 0.00555874, + 0.00065892, + 0.00008144, + 0.00001078, + 0.00000151, + 0.00000023, + 0.00000007], + Bcoeff = [0.05395079, + 0.00357780, + 0.00020506, + 0.00000719, + -0.00000016, + -0.00000005, + 0.00000000, + 0.00000000]) +elif opts.wave_type == 'single-peaked': + waves = WT.RandomWaves( Tp = period, # Peak period + Hs = waveheight, # Height + d = depth, # Depth + fp = 1./period, #peak Frequency + bandFactor = 2.0, #fmin=fp/Bandfactor, fmax = Bandfactor * fp + N = 101, #No of frequencies for signal reconstruction + mwl = inflowHeightMean, # Sea water level + waveDir = waveDir, # waveDirection + g = g, # Gravity vector, defines the vertical + gamma=3.3, + spec_fun = WT.JONSWAP) +# elif opts.wave_type == 'double-peaked': +# waves = WT.DoublePeakedRandomWaves( Tp = period, # Peak period +# Hs = waveheight, # Height +# d = depth, # Depth +# fp = 1./period, #peak Frequency +# bandFactor = 2.0, #fmin=fp/Bandfactor, fmax = Bandfactor * fp +# N = 101, #No of frequencies for signal reconstruction +# Hs = 2.0, #m significant wave height +# d = 2.0, #m depth +# fp = 1.0/5.0, #peak frequency +# bandFactor = 2.0, #controls width of band around fp +# N = 101, #number of frequency bins +# mwl = 0.0, #mean water level +# waveDir = np.array([1,0,0]), +# g = np.array([0, -9.81, 0]), #accelerationof gravity +# spec_fun = JONSWAP, +# gamma=3.3, mwl = inflowHeightMean, # Sea water level +# waveDir = waveDir, # waveDirection +# g = g, # Gravity vector, defines the vertical +# gamma=10.0, +# spec_fun = WT.JONSWAP, +# Tp_2 = opts.peak_period2) + +# Discretization -- input options +genMesh=True +movingDomain=False +applyRedistancing=True +useOldPETSc=False +useSuperlu=not opts.parallel +timeDiscretization='be'#'be','vbdf','flcbdf' +spaceOrder = 1 +useHex = False +useRBLES = 0.0 +useMetrics = 1.0 +applyCorrection=True +useVF = 1.0 +useOnlyVF = False +useRANS = 0 # 0 -- None + # 1 -- K-Epsilon + # 2 -- K-Omega +# Input checks +if spaceOrder not in [1,2]: + print "INVALID: spaceOrder" + spaceOrder + sys.exit() + +if useRBLES not in [0.0, 1.0]: + print "INVALID: useRBLES" + useRBLES + sys.exit() + +if useMetrics not in [0.0, 1.0]: + print "INVALID: useMetrics" + sys.exit() + +# Discretization +nd = 3 +if spaceOrder == 1: + hFactor=1.0 + if useHex: + basis=C0_AffineLinearOnCubeWithNodalBasis + elementQuadrature = CubeGaussQuadrature(nd,2) + elementBoundaryQuadrature = CubeGaussQuadrature(nd-1,2) + else: + basis=C0_AffineLinearOnSimplexWithNodalBasis + elementQuadrature = SimplexGaussQuadrature(nd,3) + elementBoundaryQuadrature = SimplexGaussQuadrature(nd-1,3) +elif spaceOrder == 2: + hFactor=0.5 + if useHex: + basis=C0_AffineLagrangeOnCubeWithNodalBasis + elementQuadrature = CubeGaussQuadrature(nd,4) + elementBoundaryQuadrature = CubeGaussQuadrature(nd-1,4) + else: + basis=C0_AffineQuadraticOnSimplexWithNodalBasis + elementQuadrature = SimplexGaussQuadrature(nd,4) + elementBoundaryQuadrature = SimplexGaussQuadrature(nd-1,4) + +# Domain and mesh + +#for debugging, make the tank short + +he = float(wavelength)/30.0#0.0#100 +L = (15.0, 1.5, 1.0) + +GenerationZoneLength = 1.2 +AbsorptionZoneLength= 2.8 +spongeLayer = True +xSponge = GenerationZoneLength +xRelaxCenter = xSponge/2.0 +epsFact_solid = xSponge/2.0 +#zone 2 +xSponge_2 = L[0] - AbsorptionZoneLength +xRelaxCenter_2 = 0.5*(xSponge_2+L[0]) +epsFact_solid_2 = AbsorptionZoneLength/2.0 + +weak_bc_penalty_constant = 100.0 +nLevels = 1 +#parallelPartitioningType = proteus.MeshTools.MeshParallelPartitioningTypes.element +parallelPartitioningType = proteus.MeshTools.MeshParallelPartitioningTypes.node +nLayersOfOverlapForParallel = 0 +structured=False + +if useHex: + nnx=4*Refinement+1 + nny=2*Refinement+1 + hex=True + domain = Domain.RectangularDomain(L) +else: + boundaries=['empty','left','right','bottom','top','front','back'] + boundaryTags=dict([(key,i+1) for (i,key) in enumerate(boundaries)]) + if structured: + nnx=4*Refinement + nny=2*Refinement + domain = Domain.RectangularDomain(L) + elif spongeLayer: + vertices=[[0.0,0.0,0.0],#0 + [xSponge,0.0,0.0],#1 + [xSponge_2,0.0,0.0],#2 + [L[0],0.0,0.0],#3 + [L[0],L[1],0.0],#4 + [xSponge_2,L[1],0.0],#5 + [xSponge,L[1],0.0],#6 + [0.0,L[1],0.0]]#7 + + + vertexFlags=[boundaryTags['bottom'], + boundaryTags['bottom'], + boundaryTags['bottom'], + boundaryTags['bottom'], + boundaryTags['bottom'], + boundaryTags['bottom'], + boundaryTags['bottom'], + boundaryTags['bottom']] + + + for v,vf in zip(vertices,vertexFlags): + vertices.append([v[0],v[1],L[2]]) + vertexFlags.append(boundaryTags['top']) + + print vertices + print vertexFlags + + segments=[[0,1], + [1,2], + [2,3], + [3,4], + [4,5], + [5,6], + [6,7], + [7,0], + [1,6], + [2,5]] + + segmentFlags=[boundaryTags['front'], + boundaryTags['front'], + boundaryTags['front'], + boundaryTags['right'], + boundaryTags['back'], + boundaryTags['back'], + boundaryTags['back'], + boundaryTags['left'], + boundaryTags['empty'], + boundaryTags['empty'] ] + + + facets=[] + facetFlags=[] + + for s,sF in zip(segments,segmentFlags): + facets.append([[s[0],s[1],s[1]+8,s[0]+8]]) + facetFlags.append(sF) + + bf=[[0,1,6,7],[1,2,5,6],[2,3,4,5]] + tf=[] + for i in range(0,3): + facets.append([bf[i]]) + tf=[ss + 8 for ss in bf[i]] + facets.append([tf]) + + for i in range(0,3): + facetFlags.append(boundaryTags['bottom']) + facetFlags.append(boundaryTags['top']) + + print facets + print facetFlags + + regions=[[xRelaxCenter, 0.5*L[1],0.0], + [xRelaxCenter_2, 0.5*L[1], 0.0], + [0.5*L[0],0.1*L[1], 0.0]] + regionFlags=[1,2,3] + + domain = Domain.PiecewiseLinearComplexDomain(vertices=vertices, + vertexFlags=vertexFlags, + facets=facets, + facetFlags=facetFlags, + regions=regions, + regionFlags=regionFlags, + ) + #go ahead and add a boundary tags member + domain.boundaryTags = boundaryTags + domain.writePoly("mesh") + domain.writePLY("mesh") + domain.writeAsymptote("mesh") + triangleOptions="KVApq1.4q12feena%21.16e" % ((he**3)/6.0,) + + + logEvent("""Mesh generated using: tetgen -%s %s""" % (triangleOptions,domain.polyfile+".poly")) + + porosityTypes = numpy.array([1.0, + 1.0, + 1.0, + 1.0]) + dragAlphaTypes = numpy.array([0.0, + 0.0, + 0.0, + 0.5/1.004e-6]) + + dragBetaTypes = numpy.array([0.0,0.0,0.0,0.0]) + + epsFact_solidTypes = np.array([0.0,0.0,0.0,0.0]) + + else: + vertices=[[0.0,0.0,0.0],#0 + [L[0],0.0,0.0],#1 + [L[0],L[1],0.0],#2 + [0.0,L[1],0.0]]#3 + + + vertexFlags=[boundaryTags['bottom'], + boundaryTags['bottom'], + boundaryTags['bottom'], + boundaryTags['bottom']] + + + for v,vf in zip(vertices,vertexFlags): + vertices.append([v[0],v[1],L[2]]) + vertexFlags.append(boundaryTags['top']) + + segments=[[0,1], + [1,2], + [2,3], + [3,0]] + + segmentFlags=[boundaryTags['front'], + boundaryTags['right'], + boundaryTags['back'], + boundaryTags['left']] + + facets=[] + facetFlags=[] + + for s,sF in zip(segments,segmentFlags): + facets.append([[s[0],s[1],s[1]+4,s[0]+4]]) + facetFlags.append(sF) + + bf=[[0,1,2,3]] + tf=[] + for i in range(0,1): + facets.append([bf[i]]) + tf=[ss + 4 for ss in bf[i]] + facets.append([tf]) + + for i in range(0,1): + facetFlags.append(boundaryTags['bottom']) + facetFlags.append(boundaryTags['top']) + + for s,sF in zip(segments,segmentFlags): + segments.append([s[1]+4,s[0]+4]) + segmentFlags.append(sF) + + + regions=[[0.5*L[0],0.5*L[1], 0.0]] + regionFlags=[1] + + domain = Domain.PiecewiseLinearComplexDomain(vertices=vertices, + vertexFlags=vertexFlags, + facets=facets, + facetFlags=facetFlags, + regions=regions, + regionFlags=regionFlags) + #go ahead and add a boundary tags member + domain.boundaryTags = boundaryTags + domain.writePoly("mesh") + domain.writePLY("mesh") + domain.writeAsymptote("mesh") + triangleOptions="KVApq1.4q12feena%21.16e" % ((he**3)/6.0,) + + + logEvent("""Mesh generated using: tetgen -%s %s""" % (triangleOptions,domain.polyfile+".poly")) + + + +# Time stepping +T=40*period +dt_fixed = period/11.0#2.0*0.5/20.0#T/2.0#period/21.0 +dt_init = min(0.001*dt_fixed,0.001) +runCFL=0.90 +nDTout = int(round(T/dt_fixed)) + +# Numerical parameters +ns_forceStrongDirichlet = False#True +backgroundDiffusionFactor=0.0 +if useMetrics: + ns_shockCapturingFactor = 0.25 + ns_lag_shockCapturing = True + ns_lag_subgridError = True + ls_shockCapturingFactor = 0.25 + ls_lag_shockCapturing = True + ls_sc_uref = 1.0 + ls_sc_beta = 1.0 + vof_shockCapturingFactor = 0.25 + vof_lag_shockCapturing = True + vof_sc_uref = 1.0 + vof_sc_beta = 1.0 + rd_shockCapturingFactor = 0.25 + rd_lag_shockCapturing = False + epsFact_density = 3.0 + epsFact_viscosity = epsFact_curvature = epsFact_vof = epsFact_consrv_heaviside = epsFact_consrv_dirac = epsFact_density + epsFact_redistance = 1.5 + epsFact_consrv_diffusion = 10.0 + redist_Newton = False + kappa_shockCapturingFactor = 0.1 + kappa_lag_shockCapturing = True#False + kappa_sc_uref = 1.0 + kappa_sc_beta = 1.0 + dissipation_shockCapturingFactor = 0.1 + dissipation_lag_shockCapturing = True#False + dissipation_sc_uref = 1.0 + dissipation_sc_beta = 1.0 +else: + ns_shockCapturingFactor = 0.9 + ns_lag_shockCapturing = True + ns_lag_subgridError = True + ls_shockCapturingFactor = 0.9 + ls_lag_shockCapturing = True + ls_sc_uref = 1.0 + ls_sc_beta = 1.0 + vof_shockCapturingFactor = 0.9 + vof_lag_shockCapturing = True + vof_sc_uref = 1.0 + vof_sc_beta = 1.0 + rd_shockCapturingFactor = 0.9 + rd_lag_shockCapturing = False + epsFact_density = 1.5 + epsFact_viscosity = epsFact_curvature = epsFact_vof = epsFact_consrv_heaviside = epsFact_consrv_dirac = epsFact_density + epsFact_redistance = 0.33 + epsFact_consrv_diffusion = 10.0 + redist_Newton = False + kappa_shockCapturingFactor = 0.9 + kappa_lag_shockCapturing = True#False + kappa_sc_uref = 1.0 + kappa_sc_beta = 1.0 + dissipation_shockCapturingFactor = 0.9 + dissipation_lag_shockCapturing = True#False + dissipation_sc_uref = 1.0 + dissipation_sc_beta = 1.0 + +ns_nl_atol_res = max(1.0e-10,0.0001*he**2) +vof_nl_atol_res = max(1.0e-10,0.0001*he**2) +ls_nl_atol_res = max(1.0e-10,0.0001*he**2) +rd_nl_atol_res = max(1.0e-10,0.005*he) +mcorr_nl_atol_res = max(1.0e-10,0.0001*he**2) +kappa_nl_atol_res = max(1.0e-10,0.001*he**2) +dissipation_nl_atol_res = max(1.0e-10,0.001*he**2) + +#turbulence +ns_closure=0 #1-classic smagorinsky, 2-dynamic smagorinsky, 3 -- k-epsilon, 4 -- k-omega +if useRANS == 1: + ns_closure = 3 +elif useRANS == 2: + ns_closure == 4 +# Water +rho_0 = 998.2 +nu_0 = 1.004e-6 + +# Air +rho_1 = 1.205 +nu_1 = 1.500e-5 + +# Surface tension +sigma_01 = 0.0 + +# Gravity +g = [0.0,0.0,-9.8] + +# Initial condition +waterLine_x = 2*L[0] +waterLine_z = inflowHeightMean + + +def signedDistance(x): + phi_x = x[0]-waterLine_x + phi_z = x[2]-waterLine_z + if phi_x < 0.0: + if phi_z < 0.0: + return max(phi_x,phi_z) + else: + return phi_z + else: + if phi_z < 0.0: + return phi_x + else: + return sqrt(phi_x**2 + phi_z**2) + + +def theta(x,t): + return k*x[0] - omega*t + pi/2.0 + +def z(x): + return x[2] - inflowHeightMean + +#sigma = omega - k*inflowVelocityMean[0] +h = inflowHeightMean # - transect[0][1] if lower left hand corner is not at z=0 + +#waveData + +def waveHeight(x,t): + return inflowHeightMean + waves.eta(x[0],x[1],x[2],t) +def waveVelocity_u(x,t): + return waves.u(x[0],x[1],x[2],t,"x") +def waveVelocity_v(x,t): + return waves.u(x[0],x[1],x[2],t,"y") +def waveVelocity_w(x,t): + return waves.u(x[0],x[1],x[2],t,"z") + +#solution variables + +def wavePhi(x,t): + return x[2] - waveHeight(x,t) + +def waveVF(x,t): + return smoothedHeaviside(epsFact_consrv_heaviside*he,wavePhi(x,t)) + +def twpflowVelocity_u(x,t): + waterspeed = waveVelocity_u(x,t) + H = smoothedHeaviside(epsFact_consrv_heaviside*he,wavePhi(x,t)-epsFact_consrv_heaviside*he) + u = H*windVelocity[0] + (1.0-H)*waterspeed + return u + +def twpflowVelocity_v(x,t): + waterspeed = waveVelocity_v(x,t) + H = smoothedHeaviside(epsFact_consrv_heaviside*he,wavePhi(x,t)-epsFact_consrv_heaviside*he) + return H*windVelocity[1]+(1.0-H)*waterspeed + +def twpflowFlux(x,t): + return -twpflowVelocity_u(x,t) + +outflowHeight=inflowHeightMean + +def outflowVF(x,t): + return smoothedHeaviside(epsFact_consrv_heaviside*he,x[2] - outflowHeight) + +def outflowPhi(x,t): + return x[2] - outflowHeight + +def outflowPressure(x,t): + if x[2]>inflowHeightMean: + return (L[2]-x[2])*rho_1*abs(g[2]) + else: + return (L[2]-inflowHeightMean)*rho_1*abs(g[2])+(inflowHeightMean-x[2])*rho_0*abs(g[2]) + + + #p_L = L[1]*rho_1*g[1] + #phi_L = L[1] - outflowHeight + #phi = x[1] - outflowHeight + #return p_L -g[1]*(rho_0*(phi_L - phi)+(rho_1 -rho_0)*(smoothedHeaviside_integral(epsFact_consrv_heaviside*he,phi_L) + # -smoothedHeaviside_integral(epsFact_consrv_heaviside*he,phi))) + +def twpflowVelocity_w(x,t): + return 0.0 + +def zeroVel(x,t): + return 0.0 + +from collections import namedtuple + + +def zeroVel(x,t): + return 0.0 + +from collections import namedtuple + +RelaxationZone = namedtuple("RelaxationZone","center_x sign u v w") + +class RelaxationZoneWaveGenerator(AV_base): + """ Prescribe a velocity penalty scaling in a material zone via a Darcy-Forchheimer penalty + + :param zones: A dictionary mapping integer material types to Zones, where a Zone is a named tuple + specifying the x coordinate of the zone center and the velocity components + """ + def __init__(self,zones): + assert isinstance(zones,dict) + self.zones = zones + def calculate(self): + for l,m in enumerate(self.model.levelModelList): + for eN in range(m.coefficients.q_phi.shape[0]): + mType = m.mesh.elementMaterialTypes[eN] + if self.zones.has_key(mType): + for k in range(m.coefficients.q_phi.shape[1]): + t = m.timeIntegration.t + x = m.q['x'][eN,k] + m.coefficients.q_phi_solid[eN,k] = self.zones[mType].sign*(self.zones[mType].center_x - x[0]) + m.coefficients.q_velocity_solid[eN,k,0] = self.zones[mType].u(x,t) + m.coefficients.q_velocity_solid[eN,k,1] = self.zones[mType].v(x,t) + #m.coefficients.q_velocity_solid[eN,k,2] = self.zones[mType].w(x,t) + m.q['phi_solid'] = m.coefficients.q_phi_solid + m.q['velocity_solid'] = m.coefficients.q_velocity_solid + +rzWaveGenerator = RelaxationZoneWaveGenerator(zones={ + # 1:RelaxationZone(xRelaxCenter, + # 1.0, + # twpflowVelocity_u, + # twpflowVelocity_v, + # twpflowVelocity_w), + 1:RelaxationZone(xRelaxCenter_2, + -1.0, #currently Hs=1-exp_function + zeroVel, + zeroVel, + zeroVel)}) + +beam_quadOrder=3 +beam_useSparse=False +beamFilename="wavetankBeams" +#nBeamElements=max(nBeamElements,3) + +#beam info +beamLocation=[] +beamLength=[] +beamRadius=[] +EI=[] +GJ=[] +lam = 0.25 #0.05 #3.0*2.54/100.0 #57.4e-3 +lamx = 3.0**0.5*lam +xs = 1.2 +ys = 0.0 +xList=[] +yList = [] +while xs <= 11.0: + xList.append(xs) + xs += lam +while ys<= L[1]: + yList.append(ys) + ys+=lamx +for i in xList: + for j in yList: + beamLocation.append((i,j)) + beamLength.append(0.415) + beamRadius.append(0.0032) + EI.append(3.0e-4) # needs to be fixed + GJ.append(1.5e-4) # needs to be fixed + +xs = 1.2+0.5*lam +ys = 0.5*lamx +xList=[] +yList = [] +while xs <= 11.0: + xList.append(xs) + xs += lam + +while ys<= L[1]: + yList.append(ys) + ys+=lamx + +for i in xList: + for j in yList: + beamLocation.append((i,j)) + beamLength.append(0.415) + beamRadius.append(0.0032) + EI.append(3.0e-4) # needs to be fixed + GJ.append(1.5e-4) # needs to be fixed +nBeamElements = int(beamLength[0]/he*0.5) +nBeamElements=max(nBeamElements,3) +print nBeamElements diff --git a/3d/waves_vegetation/wavetank_vegetation_generate_from_wavetools/tank3D_so.py b/3d/waves_vegetation/wavetank_vegetation_generate_from_wavetools/tank3D_so.py new file mode 100644 index 00000000..f8c11c9b --- /dev/null +++ b/3d/waves_vegetation/wavetank_vegetation_generate_from_wavetools/tank3D_so.py @@ -0,0 +1,41 @@ +from proteus.default_so import * +import tank3D + +if tank3D.useOnlyVF: + pnList = [("twp_navier_stokes_p", "twp_navier_stokes_n"), + ("vof_p", "vof_n")] +else: + pnList = [("twp_navier_stokes_p", "twp_navier_stokes_n"), + ("vof_p", "vof_n"), + ("ls_p", "ls_n"), + ("redist_p", "redist_n"), + ("ls_consrv_p", "ls_consrv_n")] + + +if tank3D.useRANS > 0: + pnList.append(("kappa_p", + "kappa_n")) + pnList.append(("dissipation_p", + "dissipation_n")) +name = "tank3D_p" + +if tank3D.timeDiscretization == 'flcbdf': + systemStepControllerType = Sequential_MinFLCBDFModelStep + systemStepControllerType = Sequential_MinAdaptiveModelStep +else: + systemStepControllerType = Sequential_MinAdaptiveModelStep + +needEBQ_GLOBAL = False +needEBQ = False + +tnList = [0.0,tank3D.dt_init]+[i*tank3D.dt_fixed for i in range(1,tank3D.nDTout+1)] + +info = open("TimeList.txt","w") + + +for time in tnList: + info.write(str(time)+"\n") +info.close() + + +archiveFlag = ArchiveFlags.EVERY_SEQUENCE_STEP diff --git a/3d/waves_vegetation/wavetank_vegetation_generate_from_wavetools/twp_navier_stokes_n.py b/3d/waves_vegetation/wavetank_vegetation_generate_from_wavetools/twp_navier_stokes_n.py new file mode 100644 index 00000000..4e5ff8d1 --- /dev/null +++ b/3d/waves_vegetation/wavetank_vegetation_generate_from_wavetools/twp_navier_stokes_n.py @@ -0,0 +1,69 @@ +from proteus import * +from twp_navier_stokes_p import * +from tank3D import * + +if timeDiscretization=='vbdf': + timeIntegration = VBDF + timeOrder=2 + stepController = Min_dt_cfl_controller +elif timeDiscretization=='flcbdf': + timeIntegration = FLCBDF + #stepController = FLCBDF_controller_sys + stepController = Min_dt_cfl_controller + time_tol = 10.0*ns_nl_atol_res + atol_u = {1:time_tol,2:time_tol,3:time_tol} + rtol_u = {1:time_tol,2:time_tol,3:time_tol} +else: + timeIntegration = BackwardEuler_cfl + stepController = Min_dt_cfl_controller + +femSpaces = {0:basis, + 1:basis, + 2:basis, + 3:basis} + +massLumping = False +numericalFluxType = None +conservativeFlux = None + +numericalFluxType = RANS2P.NumericalFlux +subgridError = RANS2P.SubgridError(coefficients,nd,lag=ns_lag_subgridError,hFactor=hFactor) +shockCapturing = RANS2P.ShockCapturing(coefficients,nd,ns_shockCapturingFactor,lag=ns_lag_shockCapturing) + +fullNewtonFlag = True +multilevelNonlinearSolver = Newton +levelNonlinearSolver = Newton + +nonlinearSmoother = None + +linearSmoother = SimpleNavierStokes3D + +matrix = SparseMatrix + +if useOldPETSc: + multilevelLinearSolver = PETSc + levelLinearSolver = PETSc +else: + multilevelLinearSolver = KSP_petsc4py + levelLinearSolver = KSP_petsc4py + +if useSuperlu: + multilevelLinearSolver = LU + levelLinearSolver = LU + +linear_solver_options_prefix = 'rans2p_' +nonlinearSolverConvergenceTest = 'r' +levelNonlinearSolverConvergenceTest = 'r' +linearSolverConvergenceTest = 'r-true' + +tolFac = 0.0 +linTolFac = 0.01 +l_atol_res = 0.01*ns_nl_atol_res +nl_atol_res = ns_nl_atol_res +useEisenstatWalker = False +maxNonlinearIts = 50 +maxLineSearches = 0 +conservativeFlux = {0:'pwl-bdm-opt'} + + +#auxiliaryVariables=[pointGauges,rzWaveGenerator] diff --git a/3d/waves_vegetation/wavetank_vegetation_generate_from_wavetools/twp_navier_stokes_p.py b/3d/waves_vegetation/wavetank_vegetation_generate_from_wavetools/twp_navier_stokes_p.py new file mode 100644 index 00000000..9f5c7798 --- /dev/null +++ b/3d/waves_vegetation/wavetank_vegetation_generate_from_wavetools/twp_navier_stokes_p.py @@ -0,0 +1,218 @@ +from proteus import * +from proteus.default_p import * +from tank3D import * +from proteus.mprans import RANS2P +from proteus.mprans import RANS2P_IB + +LevelModelType = RANS2P_IB.LevelModel +if useOnlyVF: + LS_model = None +else: + LS_model = 2 +if useRANS >= 1: + Closure_0_model = 5; Closure_1_model=6 + if useOnlyVF: + Closure_0_model=2; Closure_1_model=3 + if movingDomain: + Closure_0_model += 1; Closure_1_model += 1 +else: + Closure_0_model = None + Closure_1_model = None + +if spongeLayer or levee or slopingSpongeLayer: + coefficients = RANS2P_IB.Coefficients(epsFact=epsFact_viscosity, + sigma=0.0, + rho_0 = rho_0, + nu_0 = nu_0, + rho_1 = rho_1, + nu_1 = nu_1, + g=g, + nd=nd, + VF_model=1, + LS_model=LS_model, + Closure_0_model=Closure_0_model, + Closure_1_model=Closure_1_model, + epsFact_density=epsFact_density, + stokes=False, + useVF=useVF, + useRBLES=useRBLES, + useMetrics=useMetrics, + eb_adjoint_sigma=1.0, + eb_penalty_constant=weak_bc_penalty_constant, + forceStrongDirichlet=ns_forceStrongDirichlet, + turbulenceClosureModel=ns_closure, + movingDomain=movingDomain, + porosityTypes=porosityTypes, + dragAlphaTypes=dragAlphaTypes, + dragBetaTypes=dragBetaTypes, + epsFact_solid = epsFact_solidTypes, + beamLocation=beamLocation, + beamLength=beamLength, + beamRadius=beamRadius, + EI=EI, + GJ=GJ, + nBeamElements=nBeamElements, + beam_quadOrder=beam_quadOrder, + beamFilename=beamFilename, + beam_Cd=1.2, + beam_nlTol=1.0e-5, + beamRigid=True) +else: + coefficients = RANS2P_IB.Coefficients(epsFact=epsFact_viscosity, + sigma=0.0, + rho_0 = rho_0, + nu_0 = nu_0, + rho_1 = rho_1, + nu_1 = nu_1, + g=g, + nd=nd, + VF_model=1, + LS_model=LS_model, + Closure_0_model=Closure_0_model, + Closure_1_model=Closure_1_model, + epsFact_density=epsFact_density, + stokes=False, + useVF=useVF, + useRBLES=useRBLES, + useMetrics=useMetrics, + eb_adjoint_sigma=1.0, + eb_penalty_constant=weak_bc_penalty_constant, + forceStrongDirichlet=ns_forceStrongDirichlet, + turbulenceClosureModel=ns_closure, + movingDomain=movingDomain, + beamLocation=beamLocation, + beamLength=beamLength, + beamRadius=beamRadius, + EI=EI, + GJ=GJ, + nBeamElements=nBeamElements, + beam_quadOrder=beam_quadOrder, + beamFilename=beamFilename, + beam_Cd=1.2, + beam_nlTol=1.0e-5, + beamRigid=True) + + +def getDBC_p(x,flag): + if flag == boundaryTags['top']: + return lambda x,t: 0.0 + elif flag == boundaryTags['right']: + return outflowPressure + +def getDBC_u(x,flag): + if flag == boundaryTags['left']: + return twpflowVelocity_u + + +def getDBC_v(x,flag): + if flag == boundaryTags['left']: + return twpflowVelocity_v + +def getDBC_w(x,flag): + if flag == boundaryTags['left']: + return twpflowVelocity_w + +dirichletConditions = {0:getDBC_p, + 1:getDBC_u, + 2:getDBC_v, + 3:getDBC_w} + +def getAFBC_p(x,flag): + if flag == boundaryTags['left']: + return lambda x,t: -twpflowVelocity_u(x,t) + elif flag == boundaryTags['bottom'] or flag == boundaryTags['back'] or flag == boundaryTags['front']: + return lambda x,t: 0.0 + elif flag == boundaryTags['right']: + return lambda x,t: 0.0 + else: + return None + +def getAFBC_u(x,flag): + if flag == boundaryTags['bottom'] or flag == boundaryTags['back'] or flag == boundaryTags['front']: + return lambda x,t: 0.0 + elif flag == boundaryTags['right']: + return lambda x,t: 0.0 + else: + return None + +def getAFBC_v(x,flag): + if flag == boundaryTags['bottom'] or flag == boundaryTags['back'] or flag == boundaryTags['front']: + return lambda x,t: 0.0 + elif flag == boundaryTags['right']: + return lambda x,t: 0.0 + else: + return None + +def getAFBC_w(x,flag): + if flag == boundaryTags['bottom'] or flag == boundaryTags['back'] or flag == boundaryTags['front']: + return lambda x,t: 0.0 + elif flag == boundaryTags['right']: + return lambda x,t: 0.0 + else: + return None + +def getDFBC_u(x,flag): + if flag != boundaryTags['left']: + return lambda x,t: 0.0 + + +def getDFBC_v(x,flag): + if flag != boundaryTags['left']: + return lambda x,t: 0.0 + + +def getDFBC_w(x,flag): + if flag != boundaryTags['left']: + return lambda x,t: 0.0 +# if flag == boundaryTags['bottom']: +# return lambda x,t: 0.0 +# elif flag == boundaryTags['back']: +# return lambda x,t: 0.0 +# elif flag == boundaryTags['front']: +# return lambda x,t: 0.0 +# elif flag == boundaryTags['right']: +# return lambda x,t: 0.0 +# elif flag == boundaryTags['top']: +# return lambda x,t: 0.0 + + +advectiveFluxBoundaryConditions = {0:getAFBC_p, + 1:getAFBC_u, + 2:getAFBC_v, + 3:getAFBC_w} + +diffusiveFluxBoundaryConditions = {0:{}, + 1:{1:getDFBC_u}, + 2:{2:getDFBC_v}, + 3:{3:getDFBC_w}} + +class PerturbedSurface_p: + def __init__(self,waterLevel): + self.waterLevel=waterLevel + def uOfXT(self,x,t): + # if signedDistance(x) < 0: + # return -(L[2] - self.waterLevel)*rho_1*g[2] - (self.waterLevel - x[2])*rho_0*g[2] + # else: + # return -(L[2] - self.waterLevel)*rho_1*g[2] + if x[2]>inflowHeightMean: + return (L[2]-x[2])*rho_1*abs(g[2]) + else: + return (L[2]-inflowHeightMean)*rho_1*abs(g[2])+(inflowHeightMean-x[2])*rho_0*abs(g[2]) + +class AtRest: + def __init__(self): + pass + def uOfXT(self,x,t): + return 0.0 + +class WaterVelocity_u: + def __init__(self): + pass + def uOfXT(self,x,t): + + return waterVelocity(x,0) + +initialConditions = {0:PerturbedSurface_p(waterLine_z), + 1:AtRest(), + 2:AtRest(), + 3:AtRest()} diff --git a/3d/waves_vegetation/wavetank_vegetation_generate_from_wavetools/vof_n.py b/3d/waves_vegetation/wavetank_vegetation_generate_from_wavetools/vof_n.py new file mode 100644 index 00000000..db0de251 --- /dev/null +++ b/3d/waves_vegetation/wavetank_vegetation_generate_from_wavetools/vof_n.py @@ -0,0 +1,65 @@ +from proteus import * +from tank3D import * +from vof_p import * + +if timeDiscretization=='vbdf': + timeIntegration = VBDF + timeOrder=2 + stepController = Min_dt_cfl_controller +elif timeDiscretization=='flcbdf': + timeIntegration = FLCBDF + #stepController = FLCBDF_controller + stepController = Min_dt_cfl_controller + time_tol = 10.0*vof_nl_atol_res + atol_u = {0:time_tol} + rtol_u = {0:time_tol} +else: + timeIntegration = BackwardEuler_cfl + stepController = Min_dt_cfl_controller + +femSpaces = {0:basis} + +massLumping = False +numericalFluxType = VOF.NumericalFlux +conservativeFlux = None +subgridError = VOF.SubgridError(coefficients=coefficients,nd=nd) +shockCapturing = VOF.ShockCapturing(coefficients,nd,shockCapturingFactor=vof_shockCapturingFactor,lag=vof_lag_shockCapturing) + +fullNewtonFlag = True +multilevelNonlinearSolver = Newton +levelNonlinearSolver = Newton + +nonlinearSmoother = None +linearSmoother = None + +matrix = SparseMatrix + +if useOldPETSc: + multilevelLinearSolver = PETSc + levelLinearSolver = PETSc +else: + multilevelLinearSolver = KSP_petsc4py + levelLinearSolver = KSP_petsc4py + +if useSuperlu: + multilevelLinearSolver = LU + levelLinearSolver = LU + +linear_solver_options_prefix = 'vof_' +nonlinearSolverConvergenceTest = 'r' +levelNonlinearSolverConvergenceTest = 'r' +linearSolverConvergenceTest = 'r-true' + +tolFac = 0.0 +nl_atol_res = vof_nl_atol_res + +linTolFac = 0.0 +l_atol_res = 0.1*vof_nl_atol_res + +useEisenstatWalker = False + +maxNonlinearIts = 50 +maxLineSearches = 0 + +#auxiliaryVariables = [columnGauge] + diff --git a/3d/waves_vegetation/wavetank_vegetation_generate_from_wavetools/vof_p.py b/3d/waves_vegetation/wavetank_vegetation_generate_from_wavetools/vof_p.py new file mode 100644 index 00000000..ea33ff3b --- /dev/null +++ b/3d/waves_vegetation/wavetank_vegetation_generate_from_wavetools/vof_p.py @@ -0,0 +1,47 @@ +from proteus import * +from proteus.default_p import * +from proteus.ctransportCoefficients import smoothedHeaviside +from tank3D import * +from proteus.mprans import VOF + +LevelModelType = VOF.LevelModel +if useOnlyVF: + RD_model = None + LS_model = None +else: + RD_model = 3 + LS_model = 2 + +coefficients = VOF.Coefficients(LS_model=LS_model,V_model=0,RD_model=RD_model,ME_model=1, + checkMass=False,useMetrics=useMetrics, + epsFact=epsFact_vof,sc_uref=vof_sc_uref,sc_beta=vof_sc_beta,movingDomain=movingDomain) + +def getDBC_vof(x,flag): + if flag == boundaryTags['left']: + return waveVF + elif flag == boundaryTags['top']:# or x[1] >= L[1] - 1.0e-12: + return lambda x,t: 1.0 +# elif flag == boundaryTags['right']: +# return outflowVF + + +dirichletConditions = {0:getDBC_vof} + +def getAFBC_vof(x,flag): + if flag == boundaryTags['left']: + return None + elif flag == boundaryTags['top']:# or x[1] >= L[1] - 1.0e-12: + return None +# elif flag == boundaryTags['right']: +# return None + else: + return lambda x,t: 0.0 + +advectiveFluxBoundaryConditions = {0:getAFBC_vof} +diffusiveFluxBoundaryConditions = {0:{}} + +class PerturbedSurface_H: + def uOfXT(self,x,t): + return smoothedHeaviside(epsFact_consrv_heaviside*he,signedDistance(x)) + +initialConditions = {0:PerturbedSurface_H()} From 8d78c800fcea17ec316b2f2d7e53246600e69bae Mon Sep 17 00:00:00 2001 From: cekees Date: Thu, 8 Oct 2015 13:54:20 -0500 Subject: [PATCH 12/20] fix sponge layer index --- 2d/waves_vegetation/tank.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/2d/waves_vegetation/tank.py b/2d/waves_vegetation/tank.py index f0c475ed..1cb59000 100644 --- a/2d/waves_vegetation/tank.py +++ b/2d/waves_vegetation/tank.py @@ -581,7 +581,7 @@ def calculate(self): # twpflowVelocity_u, # twpflowVelocity_v, # twpflowVelocity_w), - 1:RelaxationZone(xRelaxCenter_2, + 2:RelaxationZone(xRelaxCenter_2, -1.0, #currently Hs=1-exp_function zeroVel, zeroVel, From a0af92017e6e14eb07b0669c3c5b0758d53d4ad5 Mon Sep 17 00:00:00 2001 From: Steve Mattis Date: Thu, 8 Oct 2015 15:06:03 -0500 Subject: [PATCH 13/20] adds context to 3d waves from 2d --- .../wavetank_vegetation_from_2d/tank3D.py | 282 ++++++++++-------- .../vegZoneVelocityInterp.py | 4 +- .../wavetank_vegetation_from_2d/vof_n.py | 2 +- 3 files changed, 161 insertions(+), 127 deletions(-) diff --git a/3d/waves_vegetation/wavetank_vegetation_from_2d/tank3D.py b/3d/waves_vegetation/wavetank_vegetation_from_2d/tank3D.py index b8ad0d1b..05d83822 100644 --- a/3d/waves_vegetation/wavetank_vegetation_from_2d/tank3D.py +++ b/3d/waves_vegetation/wavetank_vegetation_from_2d/tank3D.py @@ -1,37 +1,47 @@ from math import * import proteus.MeshTools from proteus import Domain -from proteus.default_n import * +from proteus.default_n import * from proteus.Profiling import logEvent from proteus.ctransportCoefficients import smoothedHeaviside from proteus.ctransportCoefficients import smoothedHeaviside_integral from proteus import Gauges from proteus.Gauges import PointGauges,LineGauges,LineIntegralGauges -from proteus.WaveTools import timeSeries import vegZoneVelocityInterp as vegZoneInterp -height_2d = 0.6959 -# Domain and mesh -L = (15.0, 0.5, 1.0) -he = 1.0/20.0 +from proteus import Context +opts=Context.Options([ + ("wave_type", 'linear', "type of waves generated: 'linear', 'Nonlinear', 'single-peaked', 'double-peaked'"), + ("depth", 0.457, "water depth at leading edge of vegetation (not at wave generator)[m]"), + ("wave_height", 0.192, "wave height at leading edget of vegetation [m]"), + ("peak_period", 2.0, "Peak period [s]"), + ("peak_period2", 1.5, "Second peak period (only used in double-peaked case)[s]"), + ("peak_wavelength",3.91,"Peak wavelength in [m]"), + ("parallel", False, "Run in parallel")]) #wave generator windVelocity = (0.0,0.0,0.0) -inflowHeightMean = float(vegZoneInterp.interp_phi.__call__(0.0)) -inflowVelocityMean = (0.0,0.0,0.0) -period = 1.0 -g = [0.0,0.0,-9.8] - - -# Discretization -- input options - +#veg_platform_height = 17.2/44.0 + 6.1/20.0 +depth = opts.depth +inflowHeightMean = depth +inflowVelocityMean = (0.0,0.0,0,0) +period = opts.peak_period +omega = 2.0*math.pi/period +waveheight = opts.wave_height +amplitude = waveheight/ 2.0 +wavelength = opts.peak_wavelength +k = 2.0*math.pi/wavelength +waveDir = numpy.array([1,0,0]) +g = numpy.array([0.0,0.0,-9.81]) + +# Discretization -- input options genMesh=True movingDomain=False applyRedistancing=True useOldPETSc=False -useSuperlu=False -timeDiscretization='be'#'vbdf'#'be','flcbdf' +useSuperlu=not opts.parallel +timeDiscretization='be'#'be','vbdf','flcbdf' spaceOrder = 1 useHex = False useRBLES = 0.0 @@ -45,95 +55,63 @@ # Input checks if spaceOrder not in [1,2]: print "INVALID: spaceOrder" + spaceOrder - sys.exit() - + sys.exit() + if useRBLES not in [0.0, 1.0]: - print "INVALID: useRBLES" + useRBLES + print "INVALID: useRBLES" + useRBLES sys.exit() if useMetrics not in [0.0, 1.0]: print "INVALID: useMetrics" sys.exit() - -# Discretization + +# Discretization nd = 3 if spaceOrder == 1: hFactor=1.0 if useHex: basis=C0_AffineLinearOnCubeWithNodalBasis elementQuadrature = CubeGaussQuadrature(nd,2) - elementBoundaryQuadrature = CubeGaussQuadrature(nd-1,2) + elementBoundaryQuadrature = CubeGaussQuadrature(nd-1,2) else: basis=C0_AffineLinearOnSimplexWithNodalBasis elementQuadrature = SimplexGaussQuadrature(nd,3) - elementBoundaryQuadrature = SimplexGaussQuadrature(nd-1,3) + elementBoundaryQuadrature = SimplexGaussQuadrature(nd-1,3) elif spaceOrder == 2: hFactor=0.5 - if useHex: + if useHex: basis=C0_AffineLagrangeOnCubeWithNodalBasis elementQuadrature = CubeGaussQuadrature(nd,4) - elementBoundaryQuadrature = CubeGaussQuadrature(nd-1,4) - else: - basis=C0_AffineQuadraticOnSimplexWithNodalBasis + elementBoundaryQuadrature = CubeGaussQuadrature(nd-1,4) + else: + basis=C0_AffineQuadraticOnSimplexWithNodalBasis elementQuadrature = SimplexGaussQuadrature(nd,4) elementBoundaryQuadrature = SimplexGaussQuadrature(nd-1,4) - + +# Domain and mesh + +#for debugging, make the tank short + +he = float(wavelength)/30.0#0.0#100 +L = (15.0, he, 1.0) GenerationZoneLength = 1.2 AbsorptionZoneLength= 2.8 -spongeLayer = True #False -levee=spongeLayer -slopingSpongeLayer=spongeLayer +spongeLayer = True xSponge = GenerationZoneLength -ySponge = 0.5 xRelaxCenter = xSponge/2.0 epsFact_solid = xSponge/2.0 #zone 2 -xSponge_2 = L[0]-AbsorptionZoneLength -ySponge_3= L[1]- ySponge +xSponge_2 = L[0] - AbsorptionZoneLength xRelaxCenter_2 = 0.5*(xSponge_2+L[0]) epsFact_solid_2 = AbsorptionZoneLength/2.0 -nLevels = 1 weak_bc_penalty_constant = 100.0 -quasi2D=False -if quasi2D:#make tank one element wide - L = (L[0],he,L[2]) - +nLevels = 1 #parallelPartitioningType = proteus.MeshTools.MeshParallelPartitioningTypes.element parallelPartitioningType = proteus.MeshTools.MeshParallelPartitioningTypes.node nLayersOfOverlapForParallel = 0 - -structured=False - -gauge_dx=5.0 -PGL=[] -LGL=[] -for i in range(0,int(L[0]/gauge_dx+1)): #+1 only if gauge_dx is an exact - PGL.append([gauge_dx*i,L[1]/2.0,0.5]) - LGL.append([(gauge_dx*i,L[1]/2.0,0),(gauge_dx*i,L[1]/2.0,L[2])]) - - -gaugeLocations=tuple(map(tuple,PGL)) -columnLines=tuple(map(tuple,LGL)) - - -pointGauges = PointGauges(gauges=((('u','v'), gaugeLocations), - (('p',), gaugeLocations)), - activeTime = (0, 1000.0), - sampleRate = 0, - fileName = 'combined_gauge_0_0.5_sample_all.txt') - - -fields = ('vof',) - -columnGauge = LineIntegralGauges(gauges=((fields, columnLines),), - fileName='column_gauge.csv') - -#lineGauges = LineGauges(gaugeEndpoints={'lineGauge_y=0':((0.0,0.0,0.0),(L[0],0.0,0.0))},linePoints=24) - -#lineGauges_phi = LineGauges_phi(lineGauges.endpoints,linePoints=20) - +structured=False if useHex: nnx=4*Refinement+1 @@ -246,13 +224,13 @@ 1.0, 1.0]) dragAlphaTypes = numpy.array([0.0, - 0.5/1.004e-6, - 0.5/1.004e-6, - 0.0]) + 0.0, + 0.0, + 0.5/1.004e-6]) dragBetaTypes = numpy.array([0.0,0.0,0.0,0.0]) - epsFact_solidTypes = np.array([0.0,epsFact_solid,epsFact_solid_2,0.0]) + epsFact_solidTypes = np.array([0.0,0.0,0.0,0.0]) else: vertices=[[0.0,0.0,0.0],#0 @@ -323,16 +301,18 @@ logEvent("""Mesh generated using: tetgen -%s %s""" % (triangleOptions,domain.polyfile+".poly")) + + # Time stepping -T=2.0*period -dt_fixed = period/20.0 -dt_init = min(0.1*dt_fixed,0.1*he) +T=40*period +dt_fixed = period/11.0#2.0*0.5/20.0#T/2.0#period/21.0 +dt_init = min(0.001*dt_fixed,0.001) runCFL=0.90 nDTout = int(round(T/dt_fixed)) # Numerical parameters -ns_forceStrongDirichlet = True #False#True -backgroundDiffusionFactor=0.01 +ns_forceStrongDirichlet = False#True +backgroundDiffusionFactor=0.0 if useMetrics: ns_shockCapturingFactor = 0.25 ns_lag_shockCapturing = True @@ -349,8 +329,8 @@ rd_lag_shockCapturing = False epsFact_density = 3.0 epsFact_viscosity = epsFact_curvature = epsFact_vof = epsFact_consrv_heaviside = epsFact_consrv_dirac = epsFact_density - epsFact_redistance = 0.33 - epsFact_consrv_diffusion = 0.1 + epsFact_redistance = 1.5 + epsFact_consrv_diffusion = 10.0 redist_Newton = False kappa_shockCapturingFactor = 0.1 kappa_lag_shockCapturing = True#False @@ -377,7 +357,7 @@ epsFact_density = 1.5 epsFact_viscosity = epsFact_curvature = epsFact_vof = epsFact_consrv_heaviside = epsFact_consrv_dirac = epsFact_density epsFact_redistance = 0.33 - epsFact_consrv_diffusion = 1.0 + epsFact_consrv_diffusion = 10.0 redist_Newton = False kappa_shockCapturingFactor = 0.9 kappa_lag_shockCapturing = True#False @@ -388,16 +368,16 @@ dissipation_sc_uref = 1.0 dissipation_sc_beta = 1.0 -ns_nl_atol_res = max(1.0e-10,0.001*he**2) -vof_nl_atol_res = max(1.0e-10,0.001*he**2) -ls_nl_atol_res = max(1.0e-10,0.001*he**2) +ns_nl_atol_res = max(1.0e-10,0.0001*he**2) +vof_nl_atol_res = max(1.0e-10,0.0001*he**2) +ls_nl_atol_res = max(1.0e-10,0.0001*he**2) rd_nl_atol_res = max(1.0e-10,0.005*he) -mcorr_nl_atol_res = max(1.0e-10,0.001*he**2) +mcorr_nl_atol_res = max(1.0e-10,0.0001*he**2) kappa_nl_atol_res = max(1.0e-10,0.001*he**2) dissipation_nl_atol_res = max(1.0e-10,0.001*he**2) #turbulence -ns_closure=2 #1-classic smagorinsky, 2-dynamic smagorinsky, 3 -- k-epsilon, 4 -- k-omega +ns_closure=0 #1-classic smagorinsky, 2-dynamic smagorinsky, 3 -- k-epsilon, 4 -- k-omega if useRANS == 1: ns_closure = 3 elif useRANS == 2: @@ -408,48 +388,54 @@ # Air rho_1 = 1.205 -nu_1 = 1.500e-5 +nu_1 = 1.500e-5 # Surface tension sigma_01 = 0.0 - + +# Gravity +g = [0.0,0.0,-9.8] # Initial condition -waterLine_x = 2*L[0] -waterLine_z = inflowHeightMean -waterLine_y = 2*L[1] +waterLine_x = 2*L[0] +waterLine_z = inflowHeightMean + def signedDistance(x): - phi_z = x[2]-waterLine_z - return phi_z + phi_x = x[0]-waterLine_x + phi_z = x[2]-waterLine_z + if phi_x < 0.0: + if phi_z < 0.0: + return max(phi_x,phi_z) + else: + return phi_z + else: + if phi_z < 0.0: + return phi_x + else: + return sqrt(phi_x**2 + phi_z**2) + def theta(x,t): - return k*x[0] - omega*t + math.pi/2.0 + return k*x[0] - omega*t + pi/2.0 def z(x): return x[2] - inflowHeightMean -def ramp(t): - t0=10 #ramptime - if tinflowHeightMean: @@ -486,16 +472,64 @@ def outflowPressure(x,t): else: return (L[2]-inflowHeightMean)*rho_1*abs(g[2])+(inflowHeightMean-x[2])*rho_0*abs(g[2]) -def waterVelocity(x,t): - if x[2]>inflowHeightMean: - return 0.0 - else: - ic=inflowVelocityMean[0] - return ic + + #p_L = L[1]*rho_1*g[1] + #phi_L = L[1] - outflowHeight + #phi = x[1] - outflowHeight + #return p_L -g[1]*(rho_0*(phi_L - phi)+(rho_1 -rho_0)*(smoothedHeaviside_integral(epsFact_consrv_heaviside*he,phi_L) + # -smoothedHeaviside_integral(epsFact_consrv_heaviside*he,phi))) + +def twpflowVelocity_w(x,t): + return 0.0 + +def zeroVel(x,t): + return 0.0 + +from collections import namedtuple + def zeroVel(x,t): return 0.0 +from collections import namedtuple + +RelaxationZone = namedtuple("RelaxationZone","center_x sign u v w") + +class RelaxationZoneWaveGenerator(AV_base): + """ Prescribe a velocity penalty scaling in a material zone via a Darcy-Forchheimer penalty + + :param zones: A dictionary mapping integer material types to Zones, where a Zone is a named tuple + specifying the x coordinate of the zone center and the velocity components + """ + def __init__(self,zones): + assert isinstance(zones,dict) + self.zones = zones + def calculate(self): + for l,m in enumerate(self.model.levelModelList): + for eN in range(m.coefficients.q_phi.shape[0]): + mType = m.mesh.elementMaterialTypes[eN] + if self.zones.has_key(mType): + for k in range(m.coefficients.q_phi.shape[1]): + t = m.timeIntegration.t + x = m.q['x'][eN,k] + m.coefficients.q_phi_solid[eN,k] = self.zones[mType].sign*(self.zones[mType].center_x - x[0]) + m.coefficients.q_velocity_solid[eN,k,0] = self.zones[mType].u(x,t) + m.coefficients.q_velocity_solid[eN,k,1] = self.zones[mType].v(x,t) + #m.coefficients.q_velocity_solid[eN,k,2] = self.zones[mType].w(x,t) + m.q['phi_solid'] = m.coefficients.q_phi_solid + m.q['velocity_solid'] = m.coefficients.q_velocity_solid + +rzWaveGenerator = RelaxationZoneWaveGenerator(zones={ + # 1:RelaxationZone(xRelaxCenter, + # 1.0, + # twpflowVelocity_u, + # twpflowVelocity_v, + # twpflowVelocity_w), + 1:RelaxationZone(xRelaxCenter_2, + -1.0, #currently Hs=1-exp_function + zeroVel, + zeroVel, + zeroVel)}) beam_quadOrder=3 beam_useSparse=False @@ -508,7 +542,7 @@ def zeroVel(x,t): beamRadius=[] EI=[] GJ=[] -lam = 0.05 #3.0*2.54/100.0 #57.4e-3 +lam = 0.25 #0.05 #3.0*2.54/100.0 #57.4e-3 lamx = 3.0**0.5*lam xs = 1.2 ys = 0.0 diff --git a/3d/waves_vegetation/wavetank_vegetation_from_2d/vegZoneVelocityInterp.py b/3d/waves_vegetation/wavetank_vegetation_from_2d/vegZoneVelocityInterp.py index d3d763a1..6880b430 100644 --- a/3d/waves_vegetation/wavetank_vegetation_from_2d/vegZoneVelocityInterp.py +++ b/3d/waves_vegetation/wavetank_vegetation_from_2d/vegZoneVelocityInterp.py @@ -20,8 +20,8 @@ zListW.append(float(h[3])) time = vals[:,0] -zU = np.array(zListU) -zW = np.array(zListW) +zU = np.array(zListU)-zListU[0] +zW = np.array(zListW)-zListW[0] Uarray = vals[:,1:len(zListU)+1] Warray = vals[:,len(zListU)+1::] diff --git a/3d/waves_vegetation/wavetank_vegetation_from_2d/vof_n.py b/3d/waves_vegetation/wavetank_vegetation_from_2d/vof_n.py index de2fdd09..db0de251 100644 --- a/3d/waves_vegetation/wavetank_vegetation_from_2d/vof_n.py +++ b/3d/waves_vegetation/wavetank_vegetation_from_2d/vof_n.py @@ -61,5 +61,5 @@ maxNonlinearIts = 50 maxLineSearches = 0 -auxiliaryVariables = [columnGauge] +#auxiliaryVariables = [columnGauge] From 3ec05b53dea1249fdaa03cf6c2456eab72a9b3e4 Mon Sep 17 00:00:00 2001 From: Steve Mattis Date: Thu, 8 Oct 2015 18:06:06 -0500 Subject: [PATCH 14/20] cleans up tank3D setups and allows contexts --- .../wavetank_vegetation_from_2d/tank3D.py | 2 +- .../wavetank_vegetation_time_series/tank3D.py | 284 ++++++++++-------- 2 files changed, 162 insertions(+), 124 deletions(-) diff --git a/3d/waves_vegetation/wavetank_vegetation_from_2d/tank3D.py b/3d/waves_vegetation/wavetank_vegetation_from_2d/tank3D.py index 05d83822..bd12a064 100644 --- a/3d/waves_vegetation/wavetank_vegetation_from_2d/tank3D.py +++ b/3d/waves_vegetation/wavetank_vegetation_from_2d/tank3D.py @@ -93,7 +93,7 @@ #for debugging, make the tank short he = float(wavelength)/30.0#0.0#100 -L = (15.0, he, 1.0) +L = (15.0, 1.5, 1.0) GenerationZoneLength = 1.2 AbsorptionZoneLength= 2.8 diff --git a/3d/waves_vegetation/wavetank_vegetation_time_series/tank3D.py b/3d/waves_vegetation/wavetank_vegetation_time_series/tank3D.py index 5637ec5a..c744e92f 100644 --- a/3d/waves_vegetation/wavetank_vegetation_time_series/tank3D.py +++ b/3d/waves_vegetation/wavetank_vegetation_time_series/tank3D.py @@ -1,7 +1,7 @@ from math import * import proteus.MeshTools from proteus import Domain -from proteus.default_n import * +from proteus.default_n import * from proteus.Profiling import logEvent from proteus.ctransportCoefficients import smoothedHeaviside from proteus.ctransportCoefficients import smoothedHeaviside_integral @@ -9,22 +9,35 @@ from proteus.Gauges import PointGauges,LineGauges,LineIntegralGauges from proteus.WaveTools import timeSeries -# Domain and mesh -L = (15.0, 0.5, 1.0) -he = 1.0/20.0 + +from proteus import Context +opts=Context.Options([ + ("wave_type", 'linear', "type of waves generated: 'linear', 'Nonlinear', 'single-peaked', 'double-peaked'"), + ("depth", 0.457, "water depth at leading edge of vegetation (not at wave generator)[m]"), + ("wave_height", 0.192, "wave height at leading edget of vegetation [m]"), + ("peak_period", 2.0, "Peak period [s]"), + ("peak_period2", 1.5, "Second peak period (only used in double-peaked case)[s]"), + ("peak_wavelength",3.91,"Peak wavelength in [m]"), + ("parallel", False, "Run in parallel")]) #wave generator windVelocity = (0.0,0.0,0.0) -inflowHeightMean = 0.5 -inflowVelocityMean = (0.0,0.0,0.0) -period = 1.0 -g = [0.0,0.0,-9.8] +#veg_platform_height = 17.2/44.0 + 6.1/20.0 +depth = opts.depth +inflowHeightMean = depth +inflowVelocityMean = (0.0,0.0,0,0) +period = opts.peak_period +omega = 2.0*math.pi/period +waveheight = opts.wave_height +amplitude = waveheight/ 2.0 +wavelength = opts.peak_wavelength +k = 2.0*math.pi/wavelength +waveDir = numpy.array([1,0,0]) +g = numpy.array([0.0,0.0,-9.81]) -# Wave Conditions -Nf = 10 tS = timeSeries(timeSeriesFile = "monochromatic_linear_time_series.txt", - d = L[2], + d = depth, Npeaks = 1, #m depth bandFactor = [2.0], #controls width of band around fp peakFrequencies = [1.0], @@ -33,15 +46,16 @@ mwl = inflowHeightMean, #mean water level waveDir = np.array([1,0,0]), g = np.array(g)) - -# Discretization -- input options + + +# Discretization -- input options genMesh=True movingDomain=False applyRedistancing=True useOldPETSc=False -useSuperlu=False -timeDiscretization='be'#'vbdf'#'be','flcbdf' +useSuperlu=not opts.parallel +timeDiscretization='be'#'be','vbdf','flcbdf' spaceOrder = 1 useHex = False useRBLES = 0.0 @@ -55,95 +69,63 @@ # Input checks if spaceOrder not in [1,2]: print "INVALID: spaceOrder" + spaceOrder - sys.exit() - + sys.exit() + if useRBLES not in [0.0, 1.0]: - print "INVALID: useRBLES" + useRBLES + print "INVALID: useRBLES" + useRBLES sys.exit() if useMetrics not in [0.0, 1.0]: print "INVALID: useMetrics" sys.exit() - -# Discretization + +# Discretization nd = 3 if spaceOrder == 1: hFactor=1.0 if useHex: basis=C0_AffineLinearOnCubeWithNodalBasis elementQuadrature = CubeGaussQuadrature(nd,2) - elementBoundaryQuadrature = CubeGaussQuadrature(nd-1,2) + elementBoundaryQuadrature = CubeGaussQuadrature(nd-1,2) else: basis=C0_AffineLinearOnSimplexWithNodalBasis elementQuadrature = SimplexGaussQuadrature(nd,3) - elementBoundaryQuadrature = SimplexGaussQuadrature(nd-1,3) + elementBoundaryQuadrature = SimplexGaussQuadrature(nd-1,3) elif spaceOrder == 2: hFactor=0.5 - if useHex: + if useHex: basis=C0_AffineLagrangeOnCubeWithNodalBasis elementQuadrature = CubeGaussQuadrature(nd,4) - elementBoundaryQuadrature = CubeGaussQuadrature(nd-1,4) - else: - basis=C0_AffineQuadraticOnSimplexWithNodalBasis + elementBoundaryQuadrature = CubeGaussQuadrature(nd-1,4) + else: + basis=C0_AffineQuadraticOnSimplexWithNodalBasis elementQuadrature = SimplexGaussQuadrature(nd,4) elementBoundaryQuadrature = SimplexGaussQuadrature(nd-1,4) - + +# Domain and mesh + +#for debugging, make the tank short + +he = float(wavelength)/30.0#0.0#100 +L = (15.0, 1.5, 1.0) GenerationZoneLength = 1.2 AbsorptionZoneLength= 2.8 -spongeLayer = True #False -levee=spongeLayer -slopingSpongeLayer=spongeLayer +spongeLayer = True xSponge = GenerationZoneLength -ySponge = 0.5 xRelaxCenter = xSponge/2.0 epsFact_solid = xSponge/2.0 #zone 2 -xSponge_2 = L[0]-AbsorptionZoneLength -ySponge_3= L[1]- ySponge +xSponge_2 = L[0] - AbsorptionZoneLength xRelaxCenter_2 = 0.5*(xSponge_2+L[0]) epsFact_solid_2 = AbsorptionZoneLength/2.0 -nLevels = 1 weak_bc_penalty_constant = 100.0 -quasi2D=False -if quasi2D:#make tank one element wide - L = (L[0],he,L[2]) - +nLevels = 1 #parallelPartitioningType = proteus.MeshTools.MeshParallelPartitioningTypes.element parallelPartitioningType = proteus.MeshTools.MeshParallelPartitioningTypes.node nLayersOfOverlapForParallel = 0 - -structured=False - -gauge_dx=5.0 -PGL=[] -LGL=[] -for i in range(0,int(L[0]/gauge_dx+1)): #+1 only if gauge_dx is an exact - PGL.append([gauge_dx*i,L[1]/2.0,0.5]) - LGL.append([(gauge_dx*i,L[1]/2.0,0),(gauge_dx*i,L[1]/2.0,L[2])]) - - -gaugeLocations=tuple(map(tuple,PGL)) -columnLines=tuple(map(tuple,LGL)) - - -pointGauges = PointGauges(gauges=((('u','v'), gaugeLocations), - (('p',), gaugeLocations)), - activeTime = (0, 1000.0), - sampleRate = 0, - fileName = 'combined_gauge_0_0.5_sample_all.txt') - - -fields = ('vof',) - -columnGauge = LineIntegralGauges(gauges=((fields, columnLines),), - fileName='column_gauge.csv') - -#lineGauges = LineGauges(gaugeEndpoints={'lineGauge_y=0':((0.0,0.0,0.0),(L[0],0.0,0.0))},linePoints=24) - -#lineGauges_phi = LineGauges_phi(lineGauges.endpoints,linePoints=20) - +structured=False if useHex: nnx=4*Refinement+1 @@ -256,13 +238,13 @@ 1.0, 1.0]) dragAlphaTypes = numpy.array([0.0, - 0.5/1.004e-6, - 0.5/1.004e-6, - 0.0]) + 0.0, + 0.0, + 0.5/1.004e-6]) dragBetaTypes = numpy.array([0.0,0.0,0.0,0.0]) - epsFact_solidTypes = np.array([0.0,epsFact_solid,epsFact_solid_2,0.0]) + epsFact_solidTypes = np.array([0.0,0.0,0.0,0.0]) else: vertices=[[0.0,0.0,0.0],#0 @@ -333,16 +315,18 @@ logEvent("""Mesh generated using: tetgen -%s %s""" % (triangleOptions,domain.polyfile+".poly")) + + # Time stepping -T=2.0*period -dt_fixed = period/20.0 -dt_init = min(0.1*dt_fixed,0.1*he) +T=40*period +dt_fixed = period/11.0#2.0*0.5/20.0#T/2.0#period/21.0 +dt_init = min(0.001*dt_fixed,0.001) runCFL=0.90 nDTout = int(round(T/dt_fixed)) # Numerical parameters -ns_forceStrongDirichlet = True #False#True -backgroundDiffusionFactor=0.01 +ns_forceStrongDirichlet = False#True +backgroundDiffusionFactor=0.0 if useMetrics: ns_shockCapturingFactor = 0.25 ns_lag_shockCapturing = True @@ -359,8 +343,8 @@ rd_lag_shockCapturing = False epsFact_density = 3.0 epsFact_viscosity = epsFact_curvature = epsFact_vof = epsFact_consrv_heaviside = epsFact_consrv_dirac = epsFact_density - epsFact_redistance = 0.33 - epsFact_consrv_diffusion = 0.1 + epsFact_redistance = 1.5 + epsFact_consrv_diffusion = 10.0 redist_Newton = False kappa_shockCapturingFactor = 0.1 kappa_lag_shockCapturing = True#False @@ -387,7 +371,7 @@ epsFact_density = 1.5 epsFact_viscosity = epsFact_curvature = epsFact_vof = epsFact_consrv_heaviside = epsFact_consrv_dirac = epsFact_density epsFact_redistance = 0.33 - epsFact_consrv_diffusion = 1.0 + epsFact_consrv_diffusion = 10.0 redist_Newton = False kappa_shockCapturingFactor = 0.9 kappa_lag_shockCapturing = True#False @@ -398,16 +382,16 @@ dissipation_sc_uref = 1.0 dissipation_sc_beta = 1.0 -ns_nl_atol_res = max(1.0e-10,0.001*he**2) -vof_nl_atol_res = max(1.0e-10,0.001*he**2) -ls_nl_atol_res = max(1.0e-10,0.001*he**2) +ns_nl_atol_res = max(1.0e-10,0.0001*he**2) +vof_nl_atol_res = max(1.0e-10,0.0001*he**2) +ls_nl_atol_res = max(1.0e-10,0.0001*he**2) rd_nl_atol_res = max(1.0e-10,0.005*he) -mcorr_nl_atol_res = max(1.0e-10,0.001*he**2) +mcorr_nl_atol_res = max(1.0e-10,0.0001*he**2) kappa_nl_atol_res = max(1.0e-10,0.001*he**2) dissipation_nl_atol_res = max(1.0e-10,0.001*he**2) #turbulence -ns_closure=2 #1-classic smagorinsky, 2-dynamic smagorinsky, 3 -- k-epsilon, 4 -- k-omega +ns_closure=0 #1-classic smagorinsky, 2-dynamic smagorinsky, 3 -- k-epsilon, 4 -- k-omega if useRANS == 1: ns_closure = 3 elif useRANS == 2: @@ -418,48 +402,54 @@ # Air rho_1 = 1.205 -nu_1 = 1.500e-5 +nu_1 = 1.500e-5 # Surface tension sigma_01 = 0.0 - + +# Gravity +g = [0.0,0.0,-9.8] # Initial condition -waterLine_x = 2*L[0] -waterLine_z = inflowHeightMean -waterLine_y = 2*L[1] +waterLine_x = 2*L[0] +waterLine_z = inflowHeightMean + def signedDistance(x): - phi_z = x[2]-waterLine_z - return phi_z + phi_x = x[0]-waterLine_x + phi_z = x[2]-waterLine_z + if phi_x < 0.0: + if phi_z < 0.0: + return max(phi_x,phi_z) + else: + return phi_z + else: + if phi_z < 0.0: + return phi_x + else: + return sqrt(phi_x**2 + phi_z**2) + def theta(x,t): - return k*x[0] - omega*t + math.pi/2.0 + return k*x[0] - omega*t + pi/2.0 def z(x): return x[2] - inflowHeightMean -def ramp(t): - t0=10 #ramptime - if tinflowHeightMean: @@ -496,16 +486,64 @@ def outflowPressure(x,t): else: return (L[2]-inflowHeightMean)*rho_1*abs(g[2])+(inflowHeightMean-x[2])*rho_0*abs(g[2]) -def waterVelocity(x,t): - if x[2]>inflowHeightMean: - return 0.0 - else: - ic=inflowVelocityMean[0] - return ic + + #p_L = L[1]*rho_1*g[1] + #phi_L = L[1] - outflowHeight + #phi = x[1] - outflowHeight + #return p_L -g[1]*(rho_0*(phi_L - phi)+(rho_1 -rho_0)*(smoothedHeaviside_integral(epsFact_consrv_heaviside*he,phi_L) + # -smoothedHeaviside_integral(epsFact_consrv_heaviside*he,phi))) + +def twpflowVelocity_w(x,t): + return 0.0 + +def zeroVel(x,t): + return 0.0 + +from collections import namedtuple + def zeroVel(x,t): return 0.0 +from collections import namedtuple + +RelaxationZone = namedtuple("RelaxationZone","center_x sign u v w") + +class RelaxationZoneWaveGenerator(AV_base): + """ Prescribe a velocity penalty scaling in a material zone via a Darcy-Forchheimer penalty + + :param zones: A dictionary mapping integer material types to Zones, where a Zone is a named tuple + specifying the x coordinate of the zone center and the velocity components + """ + def __init__(self,zones): + assert isinstance(zones,dict) + self.zones = zones + def calculate(self): + for l,m in enumerate(self.model.levelModelList): + for eN in range(m.coefficients.q_phi.shape[0]): + mType = m.mesh.elementMaterialTypes[eN] + if self.zones.has_key(mType): + for k in range(m.coefficients.q_phi.shape[1]): + t = m.timeIntegration.t + x = m.q['x'][eN,k] + m.coefficients.q_phi_solid[eN,k] = self.zones[mType].sign*(self.zones[mType].center_x - x[0]) + m.coefficients.q_velocity_solid[eN,k,0] = self.zones[mType].u(x,t) + m.coefficients.q_velocity_solid[eN,k,1] = self.zones[mType].v(x,t) + #m.coefficients.q_velocity_solid[eN,k,2] = self.zones[mType].w(x,t) + m.q['phi_solid'] = m.coefficients.q_phi_solid + m.q['velocity_solid'] = m.coefficients.q_velocity_solid + +rzWaveGenerator = RelaxationZoneWaveGenerator(zones={ + # 1:RelaxationZone(xRelaxCenter, + # 1.0, + # twpflowVelocity_u, + # twpflowVelocity_v, + # twpflowVelocity_w), + 1:RelaxationZone(xRelaxCenter_2, + -1.0, #currently Hs=1-exp_function + zeroVel, + zeroVel, + zeroVel)}) beam_quadOrder=3 beam_useSparse=False @@ -518,7 +556,7 @@ def zeroVel(x,t): beamRadius=[] EI=[] GJ=[] -lam = 0.05 #3.0*2.54/100.0 #57.4e-3 +lam = 0.25 #0.05 #3.0*2.54/100.0 #57.4e-3 lamx = 3.0**0.5*lam xs = 1.2 ys = 0.0 From 6e00419371a16692be68404a07d916f7e7f9dc44 Mon Sep 17 00:00:00 2001 From: cekees Date: Thu, 8 Oct 2015 18:15:52 -0500 Subject: [PATCH 15/20] updated geometry and tweaked solver options --- 2d/waves_vegetation/tank.py | 60 +++++++++------------- 2d/waves_vegetation/tank_so.py | 3 ++ 2d/waves_vegetation/twp_navier_stokes_n.py | 19 ++++--- 2d/waves_vegetation/twp_navier_stokes_p.py | 6 +-- 2d/waves_vegetation/vof_n.py | 6 ++- 5 files changed, 45 insertions(+), 49 deletions(-) diff --git a/2d/waves_vegetation/tank.py b/2d/waves_vegetation/tank.py index 675a36e9..5558e2b6 100644 --- a/2d/waves_vegetation/tank.py +++ b/2d/waves_vegetation/tank.py @@ -17,7 +17,8 @@ ("peak_period", 2.0, "Peak period [s]"), ("peak_period2", 1.5, "Second peak period (only used in double-peaked case)[s]"), ("peak_wavelength",3.91,"Peak wavelength in [m]"), - ("parallel", False, "Run in parallel")]) + ("parallel", False, "Run in parallel"), + ("gauges", True, "Enable gauges")]) #wave generator windVelocity = (0.0,0.0) @@ -92,6 +93,7 @@ spec_fun = WT.JONSWAP, Tp_2 = opts.peak_period2) +gauges=opts.gauges # Discretization -- input options genMesh=True movingDomain=False @@ -242,13 +244,10 @@ [5.4 + 17.2 + 6.1 + 1.2, 17.2/44.0 + 6.1/20.0 ],#4 [5.4 + 17.2 + 6.1 + 1.2 + 9.8, 17.2/44.0 + 6.1/20.0 ],#5 [5.4 + 17.2 + 6.1 + 1.2 + 9.8 + 1.2, 17.2/44.0 + 6.1/20.0 ],#6 -- sponge - [5.4 + 17.2 + 6.1 + 1.2 + 9.8 + 1.2 + 7.5, 17.2/44.0 + 6.1/20.0 + 7.5/20.0],#7 - [5.4 + 17.2 + 6.1 + 1.2 + 9.8 + 1.2 + 7.5 + 3.0, 17.2/44.0 + 6.1/20.0 + 7.5/20.0],#8 - [5.4 + 17.2 + 6.1 + 1.2 + 9.8 + 1.2 + 7.5 + 3.0, 19.5/44.0],#9 - [5.4 + 17.2 + 6.1 + 1.2 + 9.8 + 1.2 + 7.5 + 3.0 + 12.0, 19.5/44.0],#10 - [5.4 + 17.2 + 6.1 + 1.2 + 9.8 + 1.2 + 7.5 + 3.0 + 12.0, 19.5/44.0 + 1.5],#11 - [5.4 + 17.2 + 6.1 + 1.2 + 9.8 + 1.2, 19.5/44.0 + 1.5],#12 -- sponge - [0.0, 19.5/44.0 + 1.5]]#13 + [5.4 + 17.2 + 6.1 + 1.2 + 9.8 + 1.2 + 20.95, 17.2/44.0 + 6.1/20.0 + 20.95/20.0],#7 + [5.4 + 17.2 + 6.1 + 1.2 + 9.8 + 1.2 + 20.95, 17.2/44.0 + 6.1/20.0 + 20.95/20.0+0.2],#8 + [5.4 + 17.2 + 6.1 + 1.2 + 9.8 + 1.2, 19.5/44.0 + 1.5],#9 -- sponge + [0.0, 19.5/44.0 + 1.5]]#10 vertexFlags=[boundaryTags['bottom'],#0 boundaryTags['bottom'],#1 @@ -258,12 +257,9 @@ boundaryTags['bottom'],#5 boundaryTags['bottom'],#6 boundaryTags['bottom'],#7 - boundaryTags['bottom'],#8 - boundaryTags['bottom'],#9 - boundaryTags['bottom'],#10 - boundaryTags['top'],#11 - boundaryTags['top'],#12 - boundaryTags['top']]#13 + boundaryTags['top'],#8 + boundaryTags['top'],#9 + boundaryTags['top']]#10 segments=[[0,1],#0 [1,2],#1 [2,3],#2 @@ -273,12 +269,9 @@ [6,7],#6 [7,8],#7 [8,9],#8 - [9,10],#9 - [10,11],#10 - [11,12],#11 - [12,13],#12 - [13,0],#13 - [6,12]]#14 + [9,10],#8 + [10,0],#9 + [6,9]]#10 segmentFlags=[boundaryTags['bottom'],#0 boundaryTags['bottom'],#1 @@ -287,17 +280,14 @@ boundaryTags['bottom'],#4 boundaryTags['bottom'],#5 boundaryTags['bottom'],#6 - boundaryTags['bottom'],#7 - boundaryTags['bottom'],#8 - boundaryTags['bottom'],#9 - boundaryTags['right'],#10 - boundaryTags['top'],#11 - boundaryTags['top'],#12 - boundaryTags['left'],#13 - 0]#14 + boundaryTags['right'],#7 + boundaryTags['top'],#8 + boundaryTags['top'],#9 + boundaryTags['left'],#10 + 0]#11 regions=[[0.5,0.5], - [5.4 + 17.2 + 6.1 + 1.2 + 9.8 + 1.2 + 7.5 + 3.0 + 12.0 -0.5, 19.5/44.0 + 1.5 - 0.5]] + [5.4 + 17.2 + 6.1 + 1.2 + 9.8 + 1.2+1.0, 17.2/44.0 + 6.1/20.0 + 1.0]] regionFlags=[1,2] domain = Domain.PlanarStraightLineGraphDomain(vertices=vertices, vertexFlags=vertexFlags, @@ -368,7 +358,7 @@ nDTout = int(round(T/dt_fixed)) # Numerical parameters -ns_forceStrongDirichlet = False#True +ns_forceStrongDirichlet = False backgroundDiffusionFactor=0.0 if useMetrics: ns_shockCapturingFactor = 0.25 @@ -425,11 +415,11 @@ dissipation_sc_uref = 1.0 dissipation_sc_beta = 1.0 -ns_nl_atol_res = max(1.0e-10,0.0001*he**2) -vof_nl_atol_res = max(1.0e-10,0.0001*he**2) -ls_nl_atol_res = max(1.0e-10,0.0001*he**2) -rd_nl_atol_res = max(1.0e-10,0.005*he) -mcorr_nl_atol_res = max(1.0e-10,0.0001*he**2) +ns_nl_atol_res = max(1.0e-10,0.001*he**2) +vof_nl_atol_res = max(1.0e-10,0.001*he**2) +ls_nl_atol_res = max(1.0e-10,0.001*he**2) +rd_nl_atol_res = max(1.0e-10,0.05*he) +mcorr_nl_atol_res = max(1.0e-10,0.001*he**2) kappa_nl_atol_res = max(1.0e-10,0.001*he**2) dissipation_nl_atol_res = max(1.0e-10,0.001*he**2) diff --git a/2d/waves_vegetation/tank_so.py b/2d/waves_vegetation/tank_so.py index bf9f914f..d06f6ffa 100644 --- a/2d/waves_vegetation/tank_so.py +++ b/2d/waves_vegetation/tank_so.py @@ -1,5 +1,8 @@ from proteus.default_so import * import tank +from proteus import Context +Context.setFromModule(tank) +ctx = Context.get() if tank.useOnlyVF: pnList = [("twp_navier_stokes_p", "twp_navier_stokes_n"), diff --git a/2d/waves_vegetation/twp_navier_stokes_n.py b/2d/waves_vegetation/twp_navier_stokes_n.py index 197b241f..fe79dd36 100644 --- a/2d/waves_vegetation/twp_navier_stokes_n.py +++ b/2d/waves_vegetation/twp_navier_stokes_n.py @@ -1,6 +1,8 @@ from proteus import * from twp_navier_stokes_p import * from tank import * +from proteus import Context +ctx = Context.get() if timeDiscretization=='vbdf': timeIntegration = VBDF @@ -26,8 +28,8 @@ conservativeFlux = None numericalFluxType = RANS2P.NumericalFlux -subgridError = RANS2P.SubgridError(coefficients,nd,lag=ns_lag_subgridError,hFactor=hFactor) -shockCapturing = RANS2P.ShockCapturing(coefficients,nd,ns_shockCapturingFactor,lag=ns_lag_shockCapturing) +subgridError = RANS2P.SubgridError(coefficients,nd,lag=ns_lag_subgridError,hFactor=hFactor,nStepsToDelay=1) +shockCapturing = RANS2P.ShockCapturing(coefficients,nd,ns_shockCapturingFactor,lag=ns_lag_shockCapturing,nStepsToDelay=1) fullNewtonFlag = True multilevelNonlinearSolver = Newton @@ -39,12 +41,8 @@ matrix = SparseMatrix -if useOldPETSc: - multilevelLinearSolver = PETSc - levelLinearSolver = PETSc -else: - multilevelLinearSolver = KSP_petsc4py - levelLinearSolver = KSP_petsc4py +multilevelLinearSolver = KSP_petsc4py +levelLinearSolver = KSP_petsc4py if useSuperlu: multilevelLinearSolver = LU @@ -60,9 +58,10 @@ l_atol_res = 0.01*ns_nl_atol_res nl_atol_res = ns_nl_atol_res useEisenstatWalker = False -maxNonlinearIts = 50 +maxNonlinearIts = 100 maxLineSearches = 0 conservativeFlux = {0:'pwl-bdm-opt'} -auxiliaryVariables=[lineGauges] +if ctx.gauges: + auxiliaryVariables=[lineGauges] #auxiliaryVariables=[pointGauges,rzWaveGenerator] diff --git a/2d/waves_vegetation/twp_navier_stokes_p.py b/2d/waves_vegetation/twp_navier_stokes_p.py index 76cb66ad..10a8a9dc 100644 --- a/2d/waves_vegetation/twp_navier_stokes_p.py +++ b/2d/waves_vegetation/twp_navier_stokes_p.py @@ -94,15 +94,15 @@ def getDBC_v(x,flag): def getAFBC_p(x,flag): if flag == boundaryTags['left']: return twpflowFlux - elif flag == boundaryTags['bottom'] or flag == boundaryTags['right']: + elif flag == boundaryTags['bottom'] or flag == boundaryTags['right'] or flag == 0: return lambda x,t: 0.0 def getAFBC_u(x,flag): - if flag == boundaryTags['bottom'] or flag == boundaryTags['right']: + if flag == boundaryTags['bottom'] or flag == boundaryTags['right'] or flag == 0: return lambda x,t: 0.0 def getAFBC_v(x,flag): - if flag == boundaryTags['bottom'] or flag == boundaryTags['right']: + if flag == boundaryTags['bottom'] or flag == boundaryTags['right'] or flag == 0: return lambda x,t: 0.0 def getDFBC_u(x,flag): diff --git a/2d/waves_vegetation/vof_n.py b/2d/waves_vegetation/vof_n.py index 8862cd13..5a15d474 100644 --- a/2d/waves_vegetation/vof_n.py +++ b/2d/waves_vegetation/vof_n.py @@ -1,6 +1,8 @@ from proteus import * from tank import * from vof_p import * +from proteus import Context +ctx = Context.get() if timeDiscretization=='vbdf': timeIntegration = VBDF @@ -61,4 +63,6 @@ maxNonlinearIts = 50 maxLineSearches = 0 -auxiliaryVariables = [columnGauge] + +if ctx.gauges: + auxiliaryVariables = [columnGauge] From 9014a824d842fd8c3a097b4e6a8aca092a57467d Mon Sep 17 00:00:00 2001 From: smattis Date: Mon, 11 Jan 2016 14:20:52 -0600 Subject: [PATCH 16/20] adds readme describing problem --- 2d/waves_vegetation/README.rst | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 2d/waves_vegetation/README.rst diff --git a/2d/waves_vegetation/README.rst b/2d/waves_vegetation/README.rst new file mode 100644 index 00000000..f85367ca --- /dev/null +++ b/2d/waves_vegetation/README.rst @@ -0,0 +1,21 @@ +Flow Through Vegetation (Anderson and Smith, 2014) +================================================== + +The problem's domain is a 63.4m long, 1.5m wide flume of varying depth. A +wave is generated at the far edge of the flume, which is at a depth of +1.95m. +The deep section is 5.4m-long, followed by a 1:44 slope for 19.5m +that connects to a 12.2-m long, 1.5m-deep flat testing area. +Within the testing area there are rods simulating idealized vegetation placed in a diamond formation. +After the testing area there is a 11.3m, 1:20 slope with damping properties (to reduce reflected waves). + +.. figure:: ./image_here.bmp + :width: 100% + :align: center + +This study uses PROTEUS to model wave attenuation in shallow-water vegetated areas. + +References +---------- + +- Anderson, M.E. and Smith, J.M. (2013), Wave attenuation by flexible, idealized salt marsh vegetation. Coastal Engineering, Volume 83 p.82-92. From d840fdae62f0bb3316a990343af91b0865f6ac12 Mon Sep 17 00:00:00 2001 From: Steve Mattis Date: Wed, 20 Jan 2016 17:40:01 -0600 Subject: [PATCH 17/20] adds files for runs on Lonestar --- .../lonestar-runs/ls_consrv_n.py | 48 ++ .../lonestar-runs/ls_consrv_p.py | 26 + 2d/waves_vegetation/lonestar-runs/ls_n.py | 62 ++ 2d/waves_vegetation/lonestar-runs/ls_p.py | 29 + .../lonestar-runs/petsc.options.asm | 7 + 2d/waves_vegetation/lonestar-runs/redist_n.py | 67 ++ 2d/waves_vegetation/lonestar-runs/redist_p.py | 32 + 2d/waves_vegetation/lonestar-runs/tank.py | 582 ++++++++++++++++++ .../lonestar-runs/tank.stampede.slurm | 17 + .../lonestar-runs/tank_batch.py | 4 + .../lonestar-runs/tank_parameters.csv | 16 + 2d/waves_vegetation/lonestar-runs/tank_so.py | 35 ++ .../lonestar-runs/twp_navier_stokes_n.py | 68 ++ .../lonestar-runs/twp_navier_stokes_p.py | 141 +++++ 2d/waves_vegetation/lonestar-runs/vof_n.py | 68 ++ 2d/waves_vegetation/lonestar-runs/vof_p.py | 46 ++ 16 files changed, 1248 insertions(+) create mode 100644 2d/waves_vegetation/lonestar-runs/ls_consrv_n.py create mode 100644 2d/waves_vegetation/lonestar-runs/ls_consrv_p.py create mode 100644 2d/waves_vegetation/lonestar-runs/ls_n.py create mode 100644 2d/waves_vegetation/lonestar-runs/ls_p.py create mode 100644 2d/waves_vegetation/lonestar-runs/petsc.options.asm create mode 100644 2d/waves_vegetation/lonestar-runs/redist_n.py create mode 100644 2d/waves_vegetation/lonestar-runs/redist_p.py create mode 100644 2d/waves_vegetation/lonestar-runs/tank.py create mode 100644 2d/waves_vegetation/lonestar-runs/tank.stampede.slurm create mode 100644 2d/waves_vegetation/lonestar-runs/tank_batch.py create mode 100644 2d/waves_vegetation/lonestar-runs/tank_parameters.csv create mode 100644 2d/waves_vegetation/lonestar-runs/tank_so.py create mode 100644 2d/waves_vegetation/lonestar-runs/twp_navier_stokes_n.py create mode 100644 2d/waves_vegetation/lonestar-runs/twp_navier_stokes_p.py create mode 100644 2d/waves_vegetation/lonestar-runs/vof_n.py create mode 100644 2d/waves_vegetation/lonestar-runs/vof_p.py diff --git a/2d/waves_vegetation/lonestar-runs/ls_consrv_n.py b/2d/waves_vegetation/lonestar-runs/ls_consrv_n.py new file mode 100644 index 00000000..498ecfd6 --- /dev/null +++ b/2d/waves_vegetation/lonestar-runs/ls_consrv_n.py @@ -0,0 +1,48 @@ +from proteus import * +from tank import * +from ls_consrv_p import * + +timeIntegrator = ForwardIntegrator +timeIntegration = NoIntegration + +femSpaces = {0:basis} + +subgridError = None +massLumping = False +numericalFluxType = DoNothing +conservativeFlux = None +shockCapturing = None + +fullNewtonFlag = True +multilevelNonlinearSolver = Newton +levelNonlinearSolver = Newton + +nonlinearSmoother = None +linearSmoother = None + +matrix = SparseMatrix + +if useOldPETSc: + multilevelLinearSolver = PETSc + levelLinearSolver = PETSc +else: + multilevelLinearSolver = KSP_petsc4py + levelLinearSolver = KSP_petsc4py + +if useSuperlu: + multilevelLinearSolver = LU + levelLinearSolver = LU + +linear_solver_options_prefix = 'mcorr_' +nonlinearSolverConvergenceTest = 'r' +levelNonlinearSolverConvergenceTest = 'r' +linearSolverConvergenceTest = 'r-true' + +tolFac = 0.0 +linTolFac = 0.01 +l_atol_res = 0.01*mcorr_nl_atol_res +nl_atol_res = mcorr_nl_atol_res +useEisenstatWalker = False + +maxNonlinearIts = 50 +maxLineSearches = 0 diff --git a/2d/waves_vegetation/lonestar-runs/ls_consrv_p.py b/2d/waves_vegetation/lonestar-runs/ls_consrv_p.py new file mode 100644 index 00000000..84f85ac9 --- /dev/null +++ b/2d/waves_vegetation/lonestar-runs/ls_consrv_p.py @@ -0,0 +1,26 @@ +from proteus import * +from proteus.default_p import * +from tank import * +from proteus.mprans import MCorr + +LevelModelType = MCorr.LevelModel + +coefficients = MCorr.Coefficients(LSModel_index=2,V_model=0,me_model=4,VOFModel_index=1, + applyCorrection=applyCorrection,nd=nd,checkMass=False,useMetrics=useMetrics, + epsFactHeaviside=epsFact_consrv_heaviside, + epsFactDirac=epsFact_consrv_dirac, + epsFactDiffusion=epsFact_consrv_diffusion) + +class zero_phi: + def __init__(self): + pass + def uOfX(self,X): + return 0.0 + def uOfXT(self,X,t): + return 0.0 + +initialConditions = {0:zero_phi()} + + + + diff --git a/2d/waves_vegetation/lonestar-runs/ls_n.py b/2d/waves_vegetation/lonestar-runs/ls_n.py new file mode 100644 index 00000000..4cfc1db3 --- /dev/null +++ b/2d/waves_vegetation/lonestar-runs/ls_n.py @@ -0,0 +1,62 @@ +from proteus import * +from ls_p import * + +if timeDiscretization=='vbdf': + timeIntegration = VBDF + timeOrder=2 + stepController = Min_dt_cfl_controller +elif timeDiscretization=='flcbdf': + timeIntegration = FLCBDF + #stepController = FLCBDF_controller + stepController = Min_dt_cfl_controller + time_tol = 10.0*ls_nl_atol_res + atol_u = {0:time_tol} + rtol_u = {0:time_tol} +else: + timeIntegration = BackwardEuler_cfl + stepController = Min_dt_cfl_controller + +femSpaces = {0:basis} + +massLumping = False +conservativeFlux = None +numericalFluxType = NCLS.NumericalFlux +subgridError = NCLS.SubgridError(coefficients,nd) +shockCapturing = NCLS.ShockCapturing(coefficients,nd,shockCapturingFactor=ls_shockCapturingFactor,lag=ls_lag_shockCapturing) + +fullNewtonFlag = True +multilevelNonlinearSolver = Newton +levelNonlinearSolver = Newton + +nonlinearSmoother = None +linearSmoother = None + +matrix = SparseMatrix + +if useOldPETSc: + multilevelLinearSolver = PETSc + levelLinearSolver = PETSc +else: + multilevelLinearSolver = KSP_petsc4py + levelLinearSolver = KSP_petsc4py + +if useSuperlu: + multilevelLinearSolver = LU + levelLinearSolver = LU + +linear_solver_options_prefix = 'ncls_' +nonlinearSolverConvergenceTest = 'r' +levelNonlinearSolverConvergenceTest = 'r' +linearSolverConvergenceTest = 'r-true' + +tolFac = 0.0 +nl_atol_res = ls_nl_atol_res + +linTolFac = 0.0 +l_atol_res = 0.1*ls_nl_atol_res + +useEisenstatWalker = False + +maxNonlinearIts = 50 +maxLineSearches = 0 + diff --git a/2d/waves_vegetation/lonestar-runs/ls_p.py b/2d/waves_vegetation/lonestar-runs/ls_p.py new file mode 100644 index 00000000..fad3ff3a --- /dev/null +++ b/2d/waves_vegetation/lonestar-runs/ls_p.py @@ -0,0 +1,29 @@ +from proteus import * +from proteus.default_p import * +from tank import * +from proteus.mprans import NCLS + +LevelModelType = NCLS.LevelModel + +coefficients = NCLS.Coefficients(V_model=0,RD_model=3,ME_model=2, + checkMass=False, useMetrics=useMetrics, + epsFact=epsFact_consrv_heaviside,sc_uref=ls_sc_uref,sc_beta=ls_sc_beta,movingDomain=movingDomain) + +def getDBC_ls(x,flag): + if flag == boundaryTags['left']: + return wavePhi +# elif flag == boundaryTags['right']: +# return outflowPhi + else: + return None + +dirichletConditions = {0:getDBC_ls} + +advectiveFluxBoundaryConditions = {} +diffusiveFluxBoundaryConditions = {0:{}} + +class PerturbedSurface_phi: + def uOfXT(self,x,t): + return signedDistance(x) + +initialConditions = {0:PerturbedSurface_phi()} diff --git a/2d/waves_vegetation/lonestar-runs/petsc.options.asm b/2d/waves_vegetation/lonestar-runs/petsc.options.asm new file mode 100644 index 00000000..3c331794 --- /dev/null +++ b/2d/waves_vegetation/lonestar-runs/petsc.options.asm @@ -0,0 +1,7 @@ +-rans2p_ksp_type gmres -rans2p_pc_type asm -rans2p_pc_asm_type basic -rans2p_ksp_max_it 2000 +-rans2p_ksp_gmres_modifiedgramschmidt -rans2p_ksp_gmres_restart 300 -rans2p_sub_ksp_type preonly -rans2p_sub_pc_factor_mat_solver_package superlu -rans2p_ksp_knoll -rans2p_sub_pc_type lu +-ncls_ksp_type gmres -ncls_pc_type hypre -ncls_pc_hypre_type boomeramg -ncls_ksp_gmres_restart 300 -ncls_ksp_knoll -ncls_ksp_max_it 2000 +-vof_ksp_type gmres -vof_pc_type hypre -vof_pc_hypre_type boomeramg -vof_ksp_gmres_restart 300 -vof_ksp_knoll -vof_ksp_max_it 2000 +-rdls_ksp_type gmres -rdls_pc_type asm -rdls_pc_asm_type basic -rdls_ksp_gmres_modifiedgramschmidt -rdls_ksp_gmres_restart 300 -rdls_ksp_knoll -rdls_sub_ksp_type preonly -rdls_sub_pc_factor_mat_solver_package superlu -rdls_sub_pc_type lu -rdls_ksp_max_it 2000 +-mcorr_ksp_type cg -mcorr_pc_type hypre -mcorr_pc_hypre_type boomeramg -mcorr_ksp_max_it 2000 +-log_summary diff --git a/2d/waves_vegetation/lonestar-runs/redist_n.py b/2d/waves_vegetation/lonestar-runs/redist_n.py new file mode 100644 index 00000000..237f5e17 --- /dev/null +++ b/2d/waves_vegetation/lonestar-runs/redist_n.py @@ -0,0 +1,67 @@ +from proteus import * +from redist_p import * +from tank import * + +nl_atol_res = rd_nl_atol_res +tolFac = 0.0 +nl_atol_res = rd_nl_atol_res + +linTolFac = 0.01 +l_atol_res = 0.01*rd_nl_atol_res + +if redist_Newton: + timeIntegration = NoIntegration + stepController = Newton_controller + maxNonlinearIts = 50 + maxLineSearches = 0 + nonlinearSolverConvergenceTest = 'r' + levelNonlinearSolverConvergenceTest = 'r' + linearSolverConvergenceTest = 'r-true' + useEisenstatWalker = False +else: + timeIntegration = BackwardEuler_cfl + stepController = RDLS.PsiTC + runCFL=2.0 + psitc['nStepsForce']=3 + psitc['nStepsMax']=50 + psitc['reduceRatio']=2.0 + psitc['startRatio']=1.0 + rtol_res[0] = 0.0 + atol_res[0] = rd_nl_atol_res + useEisenstatWalker = False + maxNonlinearIts = 1 + maxLineSearches = 0 + nonlinearSolverConvergenceTest = 'rits' + levelNonlinearSolverConvergenceTest = 'rits' + linearSolverConvergenceTest = 'r-true' + +femSpaces = {0:basis} + +massLumping = False +numericalFluxType = DoNothing +conservativeFlux = None +subgridError = RDLS.SubgridError(coefficients,nd) +shockCapturing = RDLS.ShockCapturing(coefficients,nd,shockCapturingFactor=rd_shockCapturingFactor,lag=rd_lag_shockCapturing) + +fullNewtonFlag = True +multilevelNonlinearSolver = Newton +levelNonlinearSolver = Newton + +nonlinearSmoother = NLGaussSeidel +linearSmoother = None + +matrix = SparseMatrix + +if useOldPETSc: + multilevelLinearSolver = PETSc + levelLinearSolver = PETSc +else: + multilevelLinearSolver = KSP_petsc4py + levelLinearSolver = KSP_petsc4py + +if useSuperlu: + multilevelLinearSolver = LU + levelLinearSolver = LU + +linear_solver_options_prefix = 'rdls_' + diff --git a/2d/waves_vegetation/lonestar-runs/redist_p.py b/2d/waves_vegetation/lonestar-runs/redist_p.py new file mode 100644 index 00000000..5700202e --- /dev/null +++ b/2d/waves_vegetation/lonestar-runs/redist_p.py @@ -0,0 +1,32 @@ +from proteus import * +from proteus.default_p import * +from math import * +from tank import * +from proteus.mprans import RDLS +""" +The redistancing equation in the sloshbox test problem. +""" + +LevelModelType = RDLS.LevelModel + +coefficients = RDLS.Coefficients(applyRedistancing=applyRedistancing, + epsFact=epsFact_redistance, + nModelId=2, + rdModelId=3, + useMetrics=useMetrics, + backgroundDiffusionFactor=backgroundDiffusionFactor) + +def getDBC_rd(x,flag): + pass + +dirichletConditions = {0:getDBC_rd} +weakDirichletConditions = {0:RDLS.setZeroLSweakDirichletBCsSimple} + +advectiveFluxBoundaryConditions = {} +diffusiveFluxBoundaryConditions = {0:{}} + +class PerturbedSurface_phi: + def uOfXT(self,x,t): + return signedDistance(x) + +initialConditions = {0:PerturbedSurface_phi()} diff --git a/2d/waves_vegetation/lonestar-runs/tank.py b/2d/waves_vegetation/lonestar-runs/tank.py new file mode 100644 index 00000000..7219edb1 --- /dev/null +++ b/2d/waves_vegetation/lonestar-runs/tank.py @@ -0,0 +1,582 @@ +from math import * +import proteus.MeshTools +from proteus import Domain +from proteus.default_n import * +from proteus.Profiling import logEvent +from proteus.ctransportCoefficients import smoothedHeaviside +from proteus.ctransportCoefficients import smoothedHeaviside_integral +from proteus import Gauges +from proteus.Gauges import PointGauges,LineGauges,LineIntegralGauges +from proteus import WaveTools as WT + +from proteus import Context +opts=Context.Options([ + ("wave_type", 'linear', "type of waves generated: 'linear', 'Nonlinear', 'single-peaked', 'double-peaked'"), + ("depth", 0.457, "water depth at leading edge of vegetation (not at wave generator)[m]"), + ("wave_height", 0.192, "wave height at leading edget of vegetation [m]"), + ("peak_period", 2.0, "Peak period [s]"), + ("peak_period2", 1.5, "Second peak period (only used in double-peaked case)[s]"), + ("peak_wavelength",3.91,"Peak wavelength in [m]"), + ("parallel", False, "Run in parallel"), + ("gauges", True, "Enable gauges"), + ("tank_height", 1.0, "height of wave tank"]) + +#wave generator +windVelocity = (0.0,0.0) +veg_platform_height = 17.2/44.0 + 6.1/20.0 +depth = veg_platform_height + opts.depth +inflowHeightMean = depth +inflowVelocityMean = (0.0,0.0) +period = opts.peak_period +omega = 2.0*math.pi/period +waveheight = opts.wave_height +amplitude = waveheight/ 2.0 +wavelength = opts.peak_wavelength +k = 2.0*math.pi/wavelength +waveDir = numpy.array([1,0,0]) +g = numpy.array([0,-9.81,0]) +if opts.wave_type == 'linear': + waves = WT.MonochromaticWaves(period = period, # Peak period + waveHeight = waveheight, # Height + depth = depth, # Depth + mwl = inflowHeightMean, # Sea water level + waveDir = waveDir, # waveDirection + g = g, # Gravity vector, defines the vertical + waveType="Linear") +elif opts.wave_type == 'Nonlinear': + waves = WT.MonochromaticWaves(period = period, # Peak period + waveHeight = waveheight, # Height + wavelength = wavelength, + depth = depth, # Depth + mwl = inflowHeightMean, # Sea water level + waveDir = waveDir, # waveDirection + g = g, # Gravity vector, defines the vertical + waveType="Fenton", + Ycoeff = [0.04160592, #Surface elevation Fourier coefficients for non-dimensionalised solution + 0.00555874, + 0.00065892, + 0.00008144, + 0.00001078, + 0.00000151, + 0.00000023, + 0.00000007], + Bcoeff = [0.05395079, + 0.00357780, + 0.00020506, + 0.00000719, + -0.00000016, + -0.00000005, + 0.00000000, + 0.00000000]) +elif opts.wave_type == 'single-peaked': + waves = WT.RandomWaves( Tp = period, # Peak period + Hs = waveheight, # Height + mwl = inflowHeightMean, # Sea water level + depth = depth, # Depth + #fp = 1./period, #peak Frequency + bandFactor = 2.0, #fmin=fp/Bandfactor, fmax = Bandfactor * fp + N = 101, #No of frequencies for signal reconstruction + #mwl = inflowHeightMean, # Sea water level + waveDir = waveDir, # waveDirection + g = g, + spectName = "JONSWAP") # Gravity vector, defines the vertical + #gamma=3.3, + #spec_fun = JONSWAP) +elif opts.wave_type == 'double-peaked': + waves = WT.DoublePeakedRandomWaves( #Tp = period, # Peak period + Hs = waveheight, # Height + d = depth, # Depth + fp = 1./period, #peak Frequency + bandFactor = 2.0, #fmin=fp/Bandfactor, fmax = Bandfactor * fp + N = 101, #No of frequencies for signal reconstruction + mwl = inflowHeightMean, # Sea water level + waveDir = waveDir, # waveDirection + g = g, # Gravity vector, defines the vertical + gamma=10.0, + spec_fun = WT.JONSWAP, + Tp_2 = opts.peak_period2) + +gauges=opts.gauges +# Discretization -- input options +genMesh=True +movingDomain=False +applyRedistancing=True +useOldPETSc=False +useSuperlu=not opts.parallel +timeDiscretization='be'#'be','vbdf','flcbdf' +spaceOrder = 1 +useHex = False +useRBLES = 0.0 +useMetrics = 1.0 +applyCorrection=True +useVF = 1.0 +useOnlyVF = False +useRANS = 0 # 0 -- None + # 1 -- K-Epsilon + # 2 -- K-Omega +# Input checks +if spaceOrder not in [1,2]: + print "INVALID: spaceOrder" + spaceOrder + sys.exit() + +if useRBLES not in [0.0, 1.0]: + print "INVALID: useRBLES" + useRBLES + sys.exit() + +if useMetrics not in [0.0, 1.0]: + print "INVALID: useMetrics" + sys.exit() + +# Discretization +nd = 2 +if spaceOrder == 1: + hFactor=1.0 + if useHex: + basis=C0_AffineLinearOnCubeWithNodalBasis + elementQuadrature = CubeGaussQuadrature(nd,2) + elementBoundaryQuadrature = CubeGaussQuadrature(nd-1,2) + else: + basis=C0_AffineLinearOnSimplexWithNodalBasis + elementQuadrature = SimplexGaussQuadrature(nd,3) + elementBoundaryQuadrature = SimplexGaussQuadrature(nd-1,3) +elif spaceOrder == 2: + hFactor=0.5 + if useHex: + basis=C0_AffineLagrangeOnCubeWithNodalBasis + elementQuadrature = CubeGaussQuadrature(nd,4) + elementBoundaryQuadrature = CubeGaussQuadrature(nd-1,4) + else: + basis=C0_AffineQuadraticOnSimplexWithNodalBasis + elementQuadrature = SimplexGaussQuadrature(nd,4) + elementBoundaryQuadrature = SimplexGaussQuadrature(nd-1,4) + +# Domain and mesh + +#for debugging, make the tank short +L = (45.4,opts.tank_height) +he = float(wavelength)/130.0 #100.0 #50.0#0.0#100 + +GenerationZoneLength = wavelength +AbsorptionZoneLength= 45.4-37.9 +spongeLayer = True +xSponge = GenerationZoneLength +xRelaxCenter = xSponge/2.0 +epsFact_solid = xSponge/2.0 +#zone 2 +xSponge_2 = 37.9 +xRelaxCenter_2 = 0.5*(37.9+45.4) +epsFact_solid_2 = AbsorptionZoneLength/2.0 + +weak_bc_penalty_constant = 100.0 +nLevels = 1 +#parallelPartitioningType = proteus.MeshTools.MeshParallelPartitioningTypes.element +parallelPartitioningType = proteus.MeshTools.MeshParallelPartitioningTypes.node +nLayersOfOverlapForParallel = 0 +structured=False + + +gauge_dx=0.075 +PGL=[] +gauge_top = 19.5/44.0 + 1.5 +veg_gauge_bottom_y = 17.2/44.0 + 6.1/20.0 +LGL=[[(6.1, (6.1 - 5.4)/44.0, 0.0), (6.1,gauge_top,0.0)],#1 Goda + [(6.4, (6.4 - 5.4)/44.0, 0.0), (6.4,gauge_top,0.0)],#2 Goda + [(7.0, (7.0 - 5.4)/44.0, 0.0), (7.0,gauge_top,0.0)],#3 Goda + [(26.0, veg_gauge_bottom_y, 0.0), (26.0,gauge_top,0.0)],#4 veg + [(26.9, veg_gauge_bottom_y, 0.0), (26.9,gauge_top,0.0)],#5 + [(27.4, veg_gauge_bottom_y, 0.0), (27.4,gauge_top,0.0)],#6 + [(27.9, veg_gauge_bottom_y, 0.0), (27.9,gauge_top,0.0)],#7 + [(28.5, veg_gauge_bottom_y, 0.0), (28.5,gauge_top,0.0)],#8 + [(29.5, veg_gauge_bottom_y, 0.0), (29.5,gauge_top,0.0)],#9 + [(31.0, veg_gauge_bottom_y, 0.0), (31.0,gauge_top,0.0)],#10 + [(32.7, veg_gauge_bottom_y, 0.0), (32.7,gauge_top,0.0)],#11 + [(34.4, veg_gauge_bottom_y, 0.0), (34.4,gauge_top,0.0)],#12 + [(36.2, veg_gauge_bottom_y, 0.0), (36.2,gauge_top,0.0)]]#13 +#for i in range(0,int(L[0]/gauge_dx+1)): #+1 only if gauge_dx is an exact +# PGL.append([gauge_dx*i,0.5,0]) +# LGL.append([(gauge_dx*i,0.0,0),(gauge_dx*i,L[1],0)]) + + +gaugeLocations=tuple(map(tuple,PGL)) +columnLines=tuple(map(tuple,LGL)) + + +#pointGauges = PointGauges(gauges=((('u','v'), gaugeLocations), +# (('p',), gaugeLocations)), +# activeTime = (0, 1000.0), +# sampleRate = 0, +# fileName = 'combined_gauge_0_0.5_sample_all.txt') + +#print gaugeLocations +#print columnLines + +fields = ('vof',) + +columnGauge = LineIntegralGauges(gauges=((fields, columnLines),), + fileName='column_gauge.csv') + +#v_resolution = max(he,0.05) +#linePoints = int((gauge_top - veg_gauge_bottom_y)/v_resolution) +lineGauges = LineGauges(gauges=((('u','v'),#fields in gauge set + (#lines for these fields + ((26.0, veg_gauge_bottom_y, 0.0),(26.0, gauge_top, 0.0)), + ),#end lines + ),#end gauge set + ),#end gauges + fileName="vegZoneVelocity.csv") + +#lineGauges_phi = LineGauges_phi(lineGauges.endpoints,linePoints=20) + + +if useHex: + nnx=ceil(L[0]/he)+1 + nny=ceil(L[1]/he)+1 + hex=True + domain = Domain.RectangularDomain(L) +else: + boundaries=['left','right','bottom','top','front','back'] + boundaryTags=dict([(key,i+1) for (i,key) in enumerate(boundaries)]) + if structured: + nnx=ceil(L[0]/he)+1 + nny=ceil(L[1]/he)+1 + elif spongeLayer: + vertices=[[0.0, 0.0 ],#0 + [5.4, 0.0 ],#1 + [5.4 + 17.2, 17.2/44.0 ],#2 + [5.4 + 17.2 + 6.1, 17.2/44.0 + 6.1/20.0 ],#3 + [5.4 + 17.2 + 6.1 + 1.2, 17.2/44.0 + 6.1/20.0 ],#4 + [5.4 + 17.2 + 6.1 + 1.2 + 9.8, 17.2/44.0 + 6.1/20.0 ],#5 + [5.4 + 17.2 + 6.1 + 1.2 + 9.8 + 1.2, 17.2/44.0 + 6.1/20.0 ],#6 -- sponge + [5.4 + 17.2 + 6.1 + 1.2 + 9.8 + 1.2 + 20.95, 17.2/44.0 + 6.1/20.0 + 20.95/20.0],#7 + [5.4 + 17.2 + 6.1 + 1.2 + 9.8 + 1.2 + 20.95, 17.2/44.0 + 6.1/20.0 + 20.95/20.0+0.2],#8 + [5.4 + 17.2 + 6.1 + 1.2 + 9.8 + 1.2, 19.5/44.0 + 1.5],#9 -- sponge + [0.0, 19.5/44.0 + 1.5]]#10 + + vertexFlags=[boundaryTags['bottom'],#0 + boundaryTags['bottom'],#1 + boundaryTags['bottom'],#2 + boundaryTags['bottom'],#3 + boundaryTags['bottom'],#4 + boundaryTags['bottom'],#5 + boundaryTags['bottom'],#6 + boundaryTags['bottom'],#7 + boundaryTags['top'],#8 + boundaryTags['top'],#9 + boundaryTags['top']]#10 + segments=[[0,1],#0 + [1,2],#1 + [2,3],#2 + [3,4],#3 + [4,5],#4 + [5,6],#5 + [6,7],#6 + [7,8],#7 + [8,9],#8 + [9,10],#8 + [10,0],#9 + [6,9]]#10 + + segmentFlags=[boundaryTags['bottom'],#0 + boundaryTags['bottom'],#1 + boundaryTags['bottom'],#2 + boundaryTags['bottom'],#3 + boundaryTags['bottom'],#4 + boundaryTags['bottom'],#5 + boundaryTags['bottom'],#6 + boundaryTags['right'],#7 + boundaryTags['top'],#8 + boundaryTags['top'],#9 + boundaryTags['left'],#10 + 0]#11 + + regions=[[0.5,0.5], + [5.4 + 17.2 + 6.1 + 1.2 + 9.8 + 1.2+1.0, 17.2/44.0 + 6.1/20.0 + 1.0]] + regionFlags=[1,2] + domain = Domain.PlanarStraightLineGraphDomain(vertices=vertices, + vertexFlags=vertexFlags, + segments=segments, + segmentFlags=segmentFlags, + regions=regions, + regionFlags=regionFlags) + #go ahead and add a boundary tags member + domain.boundaryTags = boundaryTags + domain.writePoly("mesh") + domain.writePLY("mesh") + domain.writeAsymptote("mesh") + triangleOptions="VApq30Dena%8.8f" % ((he**2)/2.0,) + + logEvent("""Mesh generated using: triangle -%s %s""" % (triangleOptions,domain.polyfile+".poly")) + porosityTypes = numpy.array([1.0, + 1.0, + 1.0]) + dragAlphaTypes = numpy.array([0.0, + 0.0, + 0.5/1.004e-6]) + dragBetaTypes = numpy.array([0.0,0.0,0.0]) + + epsFact_solidTypes = np.array([0.0,0.0,epsFact_solid_2]) + + else: + vertices=[[0.0,0.0],#0 + [L[0],0.0],#1 + [L[0],L[1]],#2 + [0.0,L[1]]]#3 + + vertexFlags=[boundaryTags['bottom'], + boundaryTags['bottom'], + boundaryTags['top'], + boundaryTags['top']] + segments=[[0,1], + [1,2], + [2,3], + [3,0] + ] + segmentFlags=[boundaryTags['bottom'], + boundaryTags['right'], + boundaryTags['top'], + boundaryTags['left']] + + regions=[ [ 0.1*L[0] , 0.1*L[1] ], + [0.95*L[0] , 0.95*L[1] ] ] + regionFlags=[1,2] + domain = Domain.PlanarStraightLineGraphDomain(vertices=vertices, + vertexFlags=vertexFlags, + segments=segments, + segmentFlags=segmentFlags, + regions=regions, + regionFlags=regionFlags) + #go ahead and add a boundary tags member + domain.boundaryTags = boundaryTags + domain.writePoly("mesh") + domain.writePLY("mesh") + domain.writeAsymptote("mesh") + triangleOptions="VApq30Dena%8.8f" % ((he**2)/2.0,) + + logEvent("""Mesh generated using: triangle -%s %s""" % (triangleOptions,domain.polyfile+".poly")) +# Time stepping +T=1.0 #480.0 #40*period +dt_fixed = period/100.0#2.0*0.5/20.0#T/2.0#period/21.0 +dt_init = min(0.001*dt_fixed,0.001) +runCFL=0.90 +nDTout = int(round(T/dt_fixed)) + +# Numerical parameters +ns_forceStrongDirichlet = False +backgroundDiffusionFactor=0.0 +if useMetrics: + ns_shockCapturingFactor = 0.25 + ns_lag_shockCapturing = True + ns_lag_subgridError = True + ls_shockCapturingFactor = 0.25 + ls_lag_shockCapturing = True + ls_sc_uref = 1.0 + ls_sc_beta = 1.0 + vof_shockCapturingFactor = 0.25 + vof_lag_shockCapturing = True + vof_sc_uref = 1.0 + vof_sc_beta = 1.0 + rd_shockCapturingFactor = 0.25 + rd_lag_shockCapturing = False + epsFact_density = 3.0 + epsFact_viscosity = epsFact_curvature = epsFact_vof = epsFact_consrv_heaviside = epsFact_consrv_dirac = epsFact_density + epsFact_redistance = 1.5 + epsFact_consrv_diffusion = 10.0 + redist_Newton = False + kappa_shockCapturingFactor = 0.1 + kappa_lag_shockCapturing = True#False + kappa_sc_uref = 1.0 + kappa_sc_beta = 1.0 + dissipation_shockCapturingFactor = 0.1 + dissipation_lag_shockCapturing = True#False + dissipation_sc_uref = 1.0 + dissipation_sc_beta = 1.0 +else: + ns_shockCapturingFactor = 0.9 + ns_lag_shockCapturing = True + ns_lag_subgridError = True + ls_shockCapturingFactor = 0.9 + ls_lag_shockCapturing = True + ls_sc_uref = 1.0 + ls_sc_beta = 1.0 + vof_shockCapturingFactor = 0.9 + vof_lag_shockCapturing = True + vof_sc_uref = 1.0 + vof_sc_beta = 1.0 + rd_shockCapturingFactor = 0.9 + rd_lag_shockCapturing = False + epsFact_density = 1.5 + epsFact_viscosity = epsFact_curvature = epsFact_vof = epsFact_consrv_heaviside = epsFact_consrv_dirac = epsFact_density + epsFact_redistance = 0.33 + epsFact_consrv_diffusion = 10.0 + redist_Newton = False + kappa_shockCapturingFactor = 0.9 + kappa_lag_shockCapturing = True#False + kappa_sc_uref = 1.0 + kappa_sc_beta = 1.0 + dissipation_shockCapturingFactor = 0.9 + dissipation_lag_shockCapturing = True#False + dissipation_sc_uref = 1.0 + dissipation_sc_beta = 1.0 + +ns_nl_atol_res = max(1.0e-10,0.001*he**2) +vof_nl_atol_res = max(1.0e-10,0.001*he**2) +ls_nl_atol_res = max(1.0e-10,0.001*he**2) +rd_nl_atol_res = max(1.0e-10,0.05*he) +mcorr_nl_atol_res = max(1.0e-10,0.001*he**2) +kappa_nl_atol_res = max(1.0e-10,0.001*he**2) +dissipation_nl_atol_res = max(1.0e-10,0.001*he**2) + +#turbulence +ns_closure=0 #1-classic smagorinsky, 2-dynamic smagorinsky, 3 -- k-epsilon, 4 -- k-omega +if useRANS == 1: + ns_closure = 3 +elif useRANS == 2: + ns_closure == 4 +# Water +rho_0 = 998.2 +nu_0 = 1.004e-6 + +# Air +rho_1 = 1.205 +nu_1 = 1.500e-5 + +# Surface tension +sigma_01 = 0.0 + +# Gravity +g = [0.0,-9.8] + +# Initial condition +waterLine_x = 2*L[0] +waterLine_z = inflowHeightMean + + +def signedDistance(x): + phi_x = x[0]-waterLine_x + phi_z = x[1]-waterLine_z + if phi_x < 0.0: + if phi_z < 0.0: + return max(phi_x,phi_z) + else: + return phi_z + else: + if phi_z < 0.0: + return phi_x + else: + return sqrt(phi_x**2 + phi_z**2) + + +def theta(x,t): + return k*x[0] - omega*t + pi/2.0 + +def z(x): + return x[1] - inflowHeightMean + +#sigma = omega - k*inflowVelocityMean[0] +h = inflowHeightMean # - transect[0][1] if lower left hand corner is not at z=0 + +#waveData + +def waveHeight(x,t): + return inflowHeightMean + waves.eta(x[0],x[1],x[2],t) +def waveVelocity_u(x,t): + return waves.u(x[0],x[1],x[2],t,"x") +def waveVelocity_v(x,t): + return waves.u(x[0],x[1],x[2],t,"y") +def waveVelocity_w(x,t): + return waves.u(x[0],x[1],x[2],t,"z") + +#solution variables + +def wavePhi(x,t): + return x[1] - waveHeight(x,t) + +def waveVF(x,t): + return smoothedHeaviside(epsFact_consrv_heaviside*he,wavePhi(x,t)) + +def twpflowVelocity_u(x,t): + waterspeed = waveVelocity_u(x,t) + H = smoothedHeaviside(epsFact_consrv_heaviside*he,wavePhi(x,t)-epsFact_consrv_heaviside*he) + u = H*windVelocity[0] + (1.0-H)*waterspeed + return u + +def twpflowVelocity_v(x,t): + waterspeed = waveVelocity_v(x,t) + H = smoothedHeaviside(epsFact_consrv_heaviside*he,wavePhi(x,t)-epsFact_consrv_heaviside*he) + return H*windVelocity[1]+(1.0-H)*waterspeed + +def twpflowFlux(x,t): + return -twpflowVelocity_u(x,t) + +outflowHeight=inflowHeightMean + +def outflowVF(x,t): + return smoothedHeaviside(epsFact_consrv_heaviside*he,x[1] - outflowHeight) + +def outflowPhi(x,t): + return x[1] - outflowHeight + +def outflowPressure(x,t): + if x[1]>inflowHeightMean: + return (L[1]-x[1])*rho_1*abs(g[1]) + else: + return (L[1]-inflowHeightMean)*rho_1*abs(g[1])+(inflowHeightMean-x[1])*rho_0*abs(g[1]) + + + #p_L = L[1]*rho_1*g[1] + #phi_L = L[1] - outflowHeight + #phi = x[1] - outflowHeight + #return p_L -g[1]*(rho_0*(phi_L - phi)+(rho_1 -rho_0)*(smoothedHeaviside_integral(epsFact_consrv_heaviside*he,phi_L) + # -smoothedHeaviside_integral(epsFact_consrv_heaviside*he,phi))) + +def twpflowVelocity_w(x,t): + return 0.0 + +def zeroVel(x,t): + return 0.0 + +from collections import namedtuple + + +def zeroVel(x,t): + return 0.0 + +from collections import namedtuple + +RelaxationZone = namedtuple("RelaxationZone","center_x sign u v w") + +class RelaxationZoneWaveGenerator(AV_base): + """ Prescribe a velocity penalty scaling in a material zone via a Darcy-Forchheimer penalty + + :param zones: A dictionary mapping integer material types to Zones, where a Zone is a named tuple + specifying the x coordinate of the zone center and the velocity components + """ + def __init__(self,zones): + assert isinstance(zones,dict) + self.zones = zones + def calculate(self): + for l,m in enumerate(self.model.levelModelList): + for eN in range(m.coefficients.q_phi.shape[0]): + mType = m.mesh.elementMaterialTypes[eN] + if self.zones.has_key(mType): + for k in range(m.coefficients.q_phi.shape[1]): + t = m.timeIntegration.t + x = m.q['x'][eN,k] + m.coefficients.q_phi_solid[eN,k] = self.zones[mType].sign*(self.zones[mType].center_x - x[0]) + m.coefficients.q_velocity_solid[eN,k,0] = self.zones[mType].u(x,t) + m.coefficients.q_velocity_solid[eN,k,1] = self.zones[mType].v(x,t) + #m.coefficients.q_velocity_solid[eN,k,2] = self.zones[mType].w(x,t) + m.q['phi_solid'] = m.coefficients.q_phi_solid + m.q['velocity_solid'] = m.coefficients.q_velocity_solid + +rzWaveGenerator = RelaxationZoneWaveGenerator(zones={ + # 1:RelaxationZone(xRelaxCenter, + # 1.0, + # twpflowVelocity_u, + # twpflowVelocity_v, + # twpflowVelocity_w), + 2:RelaxationZone(xRelaxCenter_2, + -1.0, #currently Hs=1-exp_function + zeroVel, + zeroVel, + zeroVel)}) diff --git a/2d/waves_vegetation/lonestar-runs/tank.stampede.slurm b/2d/waves_vegetation/lonestar-runs/tank.stampede.slurm new file mode 100644 index 00000000..d8d5eedb --- /dev/null +++ b/2d/waves_vegetation/lonestar-runs/tank.stampede.slurm @@ -0,0 +1,17 @@ +#!/bin/bash +#SBATCH -J wavetank #Job Name +#SBATCH -o oe.wavetank.asm.o%j #Output and Error File +#SBATCH -n 12 #Number of mpi asks +#SBATCH -p development #Queue +#SBATCH -t 00:25:00 #Run Time +#SBATCH --mail-user=steve.a.mattis@gmail.com #email +#SBATCH --mail-type=begin #when to email +#SBATCH --mail-type=end #when to email +#SBATCH -A ADCIRC #account +set -x +#source ${WORK}/src/proteus-hashstack8/envConfig +#source /scratch/01082/smattis/src/proteus-hashdist-11-2015/envConfig +source /home1/01082/smattis/src/proteus/envConfig +mkdir $SLURM_JOB_NAME.$SLURM_JOB_ID +#/usr/local/bin/ibrun /scratch/01082/smattis/src/proteus-hashdist-11-2015/proteus/stampede.gnu/bin/python /scratch/01082/smattis/src/proteus-hashdist-11-2015/proteus/stampede.gnu/bin/parun tank_so.py -l 3 -v -D $SLURM_JOB_NAME.$SLURM_JOB_ID -O ../../../inputTemplates/petsc.options.asm -o context.options -p +ibrun parun tank_so.py -l 3 -v -D $SLURM_JOB_NAME.$SLURM_JOB_ID -O petsc.options.asm -o context.options #-p \ No newline at end of file diff --git a/2d/waves_vegetation/lonestar-runs/tank_batch.py b/2d/waves_vegetation/lonestar-runs/tank_batch.py new file mode 100644 index 00000000..38fabd1d --- /dev/null +++ b/2d/waves_vegetation/lonestar-runs/tank_batch.py @@ -0,0 +1,4 @@ +simFlagsList[0]['storeQuantities']= ["q:'phi_solid'","q:'velocity_solid'"] +#simFlagsList[0]['storeQuantities']= ["q:velocity_solid"] +start +quit diff --git a/2d/waves_vegetation/lonestar-runs/tank_parameters.csv b/2d/waves_vegetation/lonestar-runs/tank_parameters.csv new file mode 100644 index 00000000..61fbe859 --- /dev/null +++ b/2d/waves_vegetation/lonestar-runs/tank_parameters.csv @@ -0,0 +1,16 @@ +depth,wave_height,peak_period,peak_wavelength,tank_height +0.533,0.111,1.5,2.89,0.9 +0.533,0.11,1.75,3.53,0.9 +0.533,0.112,2,4.16,0.9 +0.457,0.081,1.5,2.74,0.8 +0.457,0.109,1.5,2.74,0.8 +0.457,0.139,1.5,2.74,0.8 +0.457,0.05,2,3.91,0.8 +0.457,0.107,2,3.91,0.8 +0.457,0.153,2,3.91,0.8 +0.457,0.192,2,3.91,0.8 +0.305,0.113,1.25,1.88,0.7 +0.305,0.11,1.5,2.36,0.7 +0.305,0.112,1.75,2.82,0.7 +0.305,0.111,2,3.28,0.7 +0.305,0.112,2.25,3.73,0.7 diff --git a/2d/waves_vegetation/lonestar-runs/tank_so.py b/2d/waves_vegetation/lonestar-runs/tank_so.py new file mode 100644 index 00000000..d06f6ffa --- /dev/null +++ b/2d/waves_vegetation/lonestar-runs/tank_so.py @@ -0,0 +1,35 @@ +from proteus.default_so import * +import tank +from proteus import Context +Context.setFromModule(tank) +ctx = Context.get() + +if tank.useOnlyVF: + pnList = [("twp_navier_stokes_p", "twp_navier_stokes_n"), + ("vof_p", "vof_n")] +else: + pnList = [("twp_navier_stokes_p", "twp_navier_stokes_n"), + ("vof_p", "vof_n"), + ("ls_p", "ls_n"), + ("redist_p", "redist_n"), + ("ls_consrv_p", "ls_consrv_n")] + + +if tank.useRANS > 0: + pnList.append(("kappa_p", + "kappa_n")) + pnList.append(("dissipation_p", + "dissipation_n")) +name = "tank_p" + +if tank.timeDiscretization == 'flcbdf': + systemStepControllerType = Sequential_MinFLCBDFModelStep + systemStepControllerType = Sequential_MinAdaptiveModelStep +else: + systemStepControllerType = Sequential_MinAdaptiveModelStep + +needEBQ_GLOBAL = False +needEBQ = False + +tnList = [0.0,tank.dt_init]+[i*tank.dt_fixed for i in range(1,tank.nDTout+1)] +archiveFlag = ArchiveFlags.EVERY_USER_STEP diff --git a/2d/waves_vegetation/lonestar-runs/twp_navier_stokes_n.py b/2d/waves_vegetation/lonestar-runs/twp_navier_stokes_n.py new file mode 100644 index 00000000..49d4d062 --- /dev/null +++ b/2d/waves_vegetation/lonestar-runs/twp_navier_stokes_n.py @@ -0,0 +1,68 @@ +from proteus import * +from twp_navier_stokes_p import * +from tank import * +from proteus import Context +ctx = Context.get() + +if timeDiscretization=='vbdf': + timeIntegration = VBDF + timeOrder=2 + stepController = Min_dt_cfl_controller +elif timeDiscretization=='flcbdf': + timeIntegration = FLCBDF + #stepController = FLCBDF_controller_sys + stepController = Min_dt_cfl_controller + time_tol = 10.0*ns_nl_atol_res + atol_u = {1:time_tol,2:time_tol} + rtol_u = {1:time_tol,2:time_tol} +else: + timeIntegration = BackwardEuler_cfl + stepController = Min_dt_cfl_controller + +femSpaces = {0:basis, + 1:basis, + 2:basis} + +massLumping = False +numericalFluxType = None +conservativeFlux = None + +numericalFluxType = RANS2P.NumericalFlux +subgridError = RANS2P.SubgridError(coefficients,nd,lag=ns_lag_subgridError,hFactor=hFactor,nStepsToDelay=1) +shockCapturing = RANS2P.ShockCapturing(coefficients,nd,ns_shockCapturingFactor,lag=ns_lag_shockCapturing,nStepsToDelay=1) + +fullNewtonFlag = True +multilevelNonlinearSolver = Newton +levelNonlinearSolver = Newton + +nonlinearSmoother = None + +#linearSmoother = SimpleNavierStokes2D +linearSmoother = None + +matrix = SparseMatrix + +multilevelLinearSolver = KSP_petsc4py +levelLinearSolver = KSP_petsc4py + +if useSuperlu: + multilevelLinearSolver = LU + levelLinearSolver = LU + +linear_solver_options_prefix = 'rans2p_' +nonlinearSolverConvergenceTest = 'r' +levelNonlinearSolverConvergenceTest = 'r' +linearSolverConvergenceTest = 'r-true' + +tolFac = 0.0 +linTolFac = 0.01 +l_atol_res = 0.01*ns_nl_atol_res +nl_atol_res = ns_nl_atol_res +useEisenstatWalker = False +maxNonlinearIts = 100 +maxLineSearches = 0 +conservativeFlux = {0:'pwl-bdm-opt'} + +if ctx.gauges: + auxiliaryVariables=[lineGauges] +#auxiliaryVariables=[pointGauges,rzWaveGenerator] diff --git a/2d/waves_vegetation/lonestar-runs/twp_navier_stokes_p.py b/2d/waves_vegetation/lonestar-runs/twp_navier_stokes_p.py new file mode 100644 index 00000000..10a8a9dc --- /dev/null +++ b/2d/waves_vegetation/lonestar-runs/twp_navier_stokes_p.py @@ -0,0 +1,141 @@ +from proteus import * +from proteus.default_p import * +from tank import * +from proteus.mprans import RANS2P + +LevelModelType = RANS2P.LevelModel +if useOnlyVF: + LS_model = None +else: + LS_model = 2 +if useRANS >= 1: + Closure_0_model = 5; Closure_1_model=6 + if useOnlyVF: + Closure_0_model=2; Closure_1_model=3 + if movingDomain: + Closure_0_model += 1; Closure_1_model += 1 +else: + Closure_0_model = None + Closure_1_model = None + +if spongeLayer or levee or slopingSpongeLayer: + coefficients = RANS2P.Coefficients(epsFact=epsFact_viscosity, + sigma=0.0, + rho_0 = rho_0, + nu_0 = nu_0, + rho_1 = rho_1, + nu_1 = nu_1, + g=g, + nd=nd, + VF_model=1, + LS_model=LS_model, + Closure_0_model=Closure_0_model, + Closure_1_model=Closure_1_model, + epsFact_density=epsFact_density, + stokes=False, + useVF=useVF, + useRBLES=useRBLES, + useMetrics=useMetrics, + eb_adjoint_sigma=1.0, + eb_penalty_constant=weak_bc_penalty_constant, + forceStrongDirichlet=ns_forceStrongDirichlet, + turbulenceClosureModel=ns_closure, + movingDomain=movingDomain, + porosityTypes=porosityTypes, + dragAlphaTypes=dragAlphaTypes, + dragBetaTypes=dragBetaTypes, + epsFact_solid = epsFact_solidTypes) +else: + coefficients = RANS2P.Coefficients(epsFact=epsFact_viscosity, + sigma=0.0, + rho_0 = rho_0, + nu_0 = nu_0, + rho_1 = rho_1, + nu_1 = nu_1, + g=g, + nd=nd, + VF_model=1, + LS_model=LS_model, + Closure_0_model=Closure_0_model, + Closure_1_model=Closure_1_model, + epsFact_density=epsFact_density, + stokes=False, + useVF=useVF, + useRBLES=useRBLES, + useMetrics=useMetrics, + eb_adjoint_sigma=1.0, + eb_penalty_constant=weak_bc_penalty_constant, + forceStrongDirichlet=ns_forceStrongDirichlet, + turbulenceClosureModel=ns_closure, + movingDomain=movingDomain) + +def getDBC_p(x,flag): + if flag == boundaryTags['top']: + return lambda x,t: 0.0 +# elif flag == boundaryTags['right']: +# return outflowPressure + +def getDBC_u(x,flag): + if flag == boundaryTags['left']: + return twpflowVelocity_u +# elif flag == boundaryTags['right']: +# return lambda x,t: 0.0 + +def getDBC_v(x,flag): + if flag == boundaryTags['left']: + return twpflowVelocity_v +# elif flag == boundaryTags['right']: +# return lambda x,t: 0.0 + +dirichletConditions = {0:getDBC_p, + 1:getDBC_u, + 2:getDBC_v} + +def getAFBC_p(x,flag): + if flag == boundaryTags['left']: + return twpflowFlux + elif flag == boundaryTags['bottom'] or flag == boundaryTags['right'] or flag == 0: + return lambda x,t: 0.0 + +def getAFBC_u(x,flag): + if flag == boundaryTags['bottom'] or flag == boundaryTags['right'] or flag == 0: + return lambda x,t: 0.0 + +def getAFBC_v(x,flag): + if flag == boundaryTags['bottom'] or flag == boundaryTags['right'] or flag == 0: + return lambda x,t: 0.0 + +def getDFBC_u(x,flag): + if flag != boundaryTags['left']: + return lambda x,t: 0.0 + +def getDFBC_v(x,flag): + if flag != boundaryTags['left']: + return lambda x,t: 0.0 + +advectiveFluxBoundaryConditions = {0:getAFBC_p, + 1:getAFBC_u, + 2:getAFBC_v} + +diffusiveFluxBoundaryConditions = {0:{}, + 1:{1:getDFBC_u}, + 2:{2:getDFBC_v}} + +class PerturbedSurface_p: + def __init__(self,waterLevel): + self.waterLevel=waterLevel + def uOfXT(self,x,t): + if signedDistance(x) < 0: + return -(L[1] - self.waterLevel)*rho_1*g[1] - (self.waterLevel - x[1])*rho_0*g[1] + else: + return -(L[1] - self.waterLevel)*rho_1*g[1] + +class AtRest: + def __init__(self): + pass + def uOfXT(self,x,t): + return 0.0 + +initialConditions = {0:PerturbedSurface_p(waterLine_z), + 1:AtRest(), + 2:AtRest()} diff --git a/2d/waves_vegetation/lonestar-runs/vof_n.py b/2d/waves_vegetation/lonestar-runs/vof_n.py new file mode 100644 index 00000000..5a15d474 --- /dev/null +++ b/2d/waves_vegetation/lonestar-runs/vof_n.py @@ -0,0 +1,68 @@ +from proteus import * +from tank import * +from vof_p import * +from proteus import Context +ctx = Context.get() + +if timeDiscretization=='vbdf': + timeIntegration = VBDF + timeOrder=2 + stepController = Min_dt_cfl_controller +elif timeDiscretization=='flcbdf': + timeIntegration = FLCBDF + #stepController = FLCBDF_controller + stepController = Min_dt_cfl_controller + time_tol = 10.0*vof_nl_atol_res + atol_u = {0:time_tol} + rtol_u = {0:time_tol} +else: + timeIntegration = BackwardEuler_cfl + stepController = Min_dt_cfl_controller + +femSpaces = {0:basis} + +massLumping = False +numericalFluxType = VOF.NumericalFlux +conservativeFlux = None +subgridError = VOF.SubgridError(coefficients=coefficients,nd=nd) +shockCapturing = VOF.ShockCapturing(coefficients,nd,shockCapturingFactor=vof_shockCapturingFactor,lag=vof_lag_shockCapturing) + +fullNewtonFlag = True +multilevelNonlinearSolver = Newton +levelNonlinearSolver = Newton + +nonlinearSmoother = None +linearSmoother = None + +matrix = SparseMatrix + +if useOldPETSc: + multilevelLinearSolver = PETSc + levelLinearSolver = PETSc +else: + multilevelLinearSolver = KSP_petsc4py + levelLinearSolver = KSP_petsc4py + +if useSuperlu: + multilevelLinearSolver = LU + levelLinearSolver = LU + +linear_solver_options_prefix = 'vof_' +nonlinearSolverConvergenceTest = 'r' +levelNonlinearSolverConvergenceTest = 'r' +linearSolverConvergenceTest = 'r-true' + +tolFac = 0.0 +nl_atol_res = vof_nl_atol_res + +linTolFac = 0.0 +l_atol_res = 0.1*vof_nl_atol_res + +useEisenstatWalker = False + +maxNonlinearIts = 50 +maxLineSearches = 0 + + +if ctx.gauges: + auxiliaryVariables = [columnGauge] diff --git a/2d/waves_vegetation/lonestar-runs/vof_p.py b/2d/waves_vegetation/lonestar-runs/vof_p.py new file mode 100644 index 00000000..94965ec8 --- /dev/null +++ b/2d/waves_vegetation/lonestar-runs/vof_p.py @@ -0,0 +1,46 @@ +from proteus import * +from proteus.default_p import * +from proteus.ctransportCoefficients import smoothedHeaviside +from tank import * +from proteus.mprans import VOF + +LevelModelType = VOF.LevelModel +if useOnlyVF: + RD_model = None + LS_model = None +else: + RD_model = 3 + LS_model = 2 + +coefficients = VOF.Coefficients(LS_model=LS_model,V_model=0,RD_model=RD_model,ME_model=1, + checkMass=False,useMetrics=useMetrics, + epsFact=epsFact_vof,sc_uref=vof_sc_uref,sc_beta=vof_sc_beta,movingDomain=movingDomain) + +def getDBC_vof(x,flag): + if flag == boundaryTags['left']: + return waveVF + elif flag == boundaryTags['top']:# or x[1] >= L[1] - 1.0e-12: + return lambda x,t: 1.0 +# elif flag == boundaryTags['right']: +# return outflowVF + +dirichletConditions = {0:getDBC_vof} + +def getAFBC_vof(x,flag): + if flag == boundaryTags['left']: + return None + elif flag == boundaryTags['top']:# or x[1] >= L[1] - 1.0e-12: + return None + # elif flag == boundaryTags['right']: + # return None + else: + return lambda x,t: 0.0 + +advectiveFluxBoundaryConditions = {0:getAFBC_vof} +diffusiveFluxBoundaryConditions = {0:{}} + +class PerturbedSurface_H: + def uOfXT(self,x,t): + return smoothedHeaviside(epsFact_consrv_heaviside*he,signedDistance(x)) + +initialConditions = {0:PerturbedSurface_H()} From b978bcad4da47eb805a1293147c418acf7ee78b8 Mon Sep 17 00:00:00 2001 From: Steve Mattis Date: Wed, 20 Jan 2016 17:55:47 -0600 Subject: [PATCH 18/20] adds file to setup runs --- 2d/waves_vegetation/lonestar-runs/makeRuns.py | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 2d/waves_vegetation/lonestar-runs/makeRuns.py diff --git a/2d/waves_vegetation/lonestar-runs/makeRuns.py b/2d/waves_vegetation/lonestar-runs/makeRuns.py new file mode 100644 index 00000000..bdac58af --- /dev/null +++ b/2d/waves_vegetation/lonestar-runs/makeRuns.py @@ -0,0 +1,22 @@ +import numpy as np +import os +import shutil + +params = np.loadtxt("tank_parameters.csv", delimiter=',', skiprows=1) +os.system("mkdir runs") +for i in range(params.shape[0]): + filepath = "runs/"+ "run" + `i` + os.system("mkdir " + filepath) + os.system("cp *.py " + filepath) + os.system("cp tank.stampede.slurm " + filepath) + f = open(filepath + "/context.options",'w') + f.write("parallel=True ") + f.write("wave_type='single-peaked' ") + f.write("gauges=True ") + f.write("depth=" + `params[i][0]` + " ") + f.write("wave_height=" + `params[i][1]` + " ") + f.write("peak_period=" + `params[i][2]` + " ") + f.write("peak_wavelength=" + `params[i][3]` + " ") + f.write("tank_height=" + `params[i][4]`) + f.close() + From 8cf050290d877ff6a7ae892e131ee55f11824fa3 Mon Sep 17 00:00:00 2001 From: Steve Mattis Date: Sun, 24 Jan 2016 19:35:54 -0600 Subject: [PATCH 19/20] modifies lonestar 2d runs --- 2d/waves_vegetation/lonestar-runs/tank.py | 36 ++++++++++--------- .../lonestar-runs/tank.stampede.slurm | 6 ++-- .../lonestar-runs/tank_parameters.csv | 10 +++--- 3 files changed, 27 insertions(+), 25 deletions(-) diff --git a/2d/waves_vegetation/lonestar-runs/tank.py b/2d/waves_vegetation/lonestar-runs/tank.py index 7219edb1..7ecfe840 100644 --- a/2d/waves_vegetation/lonestar-runs/tank.py +++ b/2d/waves_vegetation/lonestar-runs/tank.py @@ -19,7 +19,7 @@ ("peak_wavelength",3.91,"Peak wavelength in [m]"), ("parallel", False, "Run in parallel"), ("gauges", True, "Enable gauges"), - ("tank_height", 1.0, "height of wave tank"]) + ("tank_height", 1.0, "height of wave tank")]) #wave generator windVelocity = (0.0,0.0) @@ -154,7 +154,7 @@ #for debugging, make the tank short L = (45.4,opts.tank_height) -he = float(wavelength)/130.0 #100.0 #50.0#0.0#100 +he = 0.025 #float(wavelength)/130.0 #100.0 #50.0#0.0#100 GenerationZoneLength = wavelength AbsorptionZoneLength= 45.4-37.9 @@ -240,17 +240,19 @@ nnx=ceil(L[0]/he)+1 nny=ceil(L[1]/he)+1 elif spongeLayer: - vertices=[[0.0, 0.0 ],#0 - [5.4, 0.0 ],#1 - [5.4 + 17.2, 17.2/44.0 ],#2 - [5.4 + 17.2 + 6.1, 17.2/44.0 + 6.1/20.0 ],#3 - [5.4 + 17.2 + 6.1 + 1.2, 17.2/44.0 + 6.1/20.0 ],#4 - [5.4 + 17.2 + 6.1 + 1.2 + 9.8, 17.2/44.0 + 6.1/20.0 ],#5 - [5.4 + 17.2 + 6.1 + 1.2 + 9.8 + 1.2, 17.2/44.0 + 6.1/20.0 ],#6 -- sponge - [5.4 + 17.2 + 6.1 + 1.2 + 9.8 + 1.2 + 20.95, 17.2/44.0 + 6.1/20.0 + 20.95/20.0],#7 - [5.4 + 17.2 + 6.1 + 1.2 + 9.8 + 1.2 + 20.95, 17.2/44.0 + 6.1/20.0 + 20.95/20.0+0.2],#8 - [5.4 + 17.2 + 6.1 + 1.2 + 9.8 + 1.2, 19.5/44.0 + 1.5],#9 -- sponge - [0.0, 19.5/44.0 + 1.5]]#10 + #tp = opts.tank_height + bp = 20.0*(opts.tank_height-0.2) + vertices=[[0.0, 0.0 ],#0 begin wave paddle bottom + [5.4, 0.0 ],#1 end wave paddle bottom, begin incline 1 + [5.4 + 17.2, 17.2/44.0 ],#2 end incline 1, begin incline 2 + [5.4 + 17.2 + 6.1, 17.2/44.0 + 6.1/20.0 ],#3 end incline 2, begin pre veg platform + [5.4 + 17.2 + 6.1 + 1.2, 17.2/44.0 + 6.1/20.0 ],#4 end pre veg platform, begin veg zone + [5.4 + 17.2 + 6.1 + 1.2 + 9.8, 17.2/44.0 + 6.1/20.0 ],#5 end veg zone, begin post veg platform + [5.4 + 17.2 + 6.1 + 1.2 + 9.8 + 1.2, 17.2/44.0 + 6.1/20.0 ],#6 -- sponge, end post veg platorm, begin slope bottom + [5.4 + 17.2 + 6.1 + 1.2 + 9.8 + 1.2 + bp, 17.2/44.0 + 6.1/20.0 + bp/20.0],#7 end slope bottom + [5.4 + 17.2 + 6.1 + 1.2 + 9.8 + 1.2 + bp, 17.2/44.0 + 6.1/20.0 + bp/20.0+0.2],#8 end slope top + [5.4 + 17.2 + 6.1 + 1.2 + 9.8 + 1.2, 19.5/44.0 + 1.5],#9 -- sponge begin sponge top + [0.0, 19.5/44.0 + 1.5]]#10 begin wave paddle top vertexFlags=[boundaryTags['bottom'],#0 boundaryTags['bottom'],#1 @@ -304,7 +306,7 @@ domain.writePLY("mesh") domain.writeAsymptote("mesh") triangleOptions="VApq30Dena%8.8f" % ((he**2)/2.0,) - + print triangleOptions logEvent("""Mesh generated using: triangle -%s %s""" % (triangleOptions,domain.polyfile+".poly")) porosityTypes = numpy.array([1.0, 1.0, @@ -354,10 +356,10 @@ logEvent("""Mesh generated using: triangle -%s %s""" % (triangleOptions,domain.polyfile+".poly")) # Time stepping -T=1.0 #480.0 #40*period -dt_fixed = period/100.0#2.0*0.5/20.0#T/2.0#period/21.0 +T=200.0 #480.0 #480.0 #40*period +dt_fixed = period/30.0#2.0*0.5/20.0#T/2.0#period/21.0 dt_init = min(0.001*dt_fixed,0.001) -runCFL=0.90 +runCFL=10.90 nDTout = int(round(T/dt_fixed)) # Numerical parameters diff --git a/2d/waves_vegetation/lonestar-runs/tank.stampede.slurm b/2d/waves_vegetation/lonestar-runs/tank.stampede.slurm index d8d5eedb..e90581f5 100644 --- a/2d/waves_vegetation/lonestar-runs/tank.stampede.slurm +++ b/2d/waves_vegetation/lonestar-runs/tank.stampede.slurm @@ -2,8 +2,8 @@ #SBATCH -J wavetank #Job Name #SBATCH -o oe.wavetank.asm.o%j #Output and Error File #SBATCH -n 12 #Number of mpi asks -#SBATCH -p development #Queue -#SBATCH -t 00:25:00 #Run Time +#SBATCH -p normal #Queue +#SBATCH -t 48:00:00 #Run Time #SBATCH --mail-user=steve.a.mattis@gmail.com #email #SBATCH --mail-type=begin #when to email #SBATCH --mail-type=end #when to email @@ -14,4 +14,4 @@ set -x source /home1/01082/smattis/src/proteus/envConfig mkdir $SLURM_JOB_NAME.$SLURM_JOB_ID #/usr/local/bin/ibrun /scratch/01082/smattis/src/proteus-hashdist-11-2015/proteus/stampede.gnu/bin/python /scratch/01082/smattis/src/proteus-hashdist-11-2015/proteus/stampede.gnu/bin/parun tank_so.py -l 3 -v -D $SLURM_JOB_NAME.$SLURM_JOB_ID -O ../../../inputTemplates/petsc.options.asm -o context.options -p -ibrun parun tank_so.py -l 3 -v -D $SLURM_JOB_NAME.$SLURM_JOB_ID -O petsc.options.asm -o context.options #-p \ No newline at end of file +ibrun parun tank_so.py -l 3 -v -D $SLURM_JOB_NAME.$SLURM_JOB_ID -O ../../petsc.options.asm -o context.options #-p \ No newline at end of file diff --git a/2d/waves_vegetation/lonestar-runs/tank_parameters.csv b/2d/waves_vegetation/lonestar-runs/tank_parameters.csv index 61fbe859..657f2e9f 100644 --- a/2d/waves_vegetation/lonestar-runs/tank_parameters.csv +++ b/2d/waves_vegetation/lonestar-runs/tank_parameters.csv @@ -9,8 +9,8 @@ depth,wave_height,peak_period,peak_wavelength,tank_height 0.457,0.107,2,3.91,0.8 0.457,0.153,2,3.91,0.8 0.457,0.192,2,3.91,0.8 -0.305,0.113,1.25,1.88,0.7 -0.305,0.11,1.5,2.36,0.7 -0.305,0.112,1.75,2.82,0.7 -0.305,0.111,2,3.28,0.7 -0.305,0.112,2.25,3.73,0.7 +0.305,0.113,1.25,1.88,0.8 +0.305,0.11,1.5,2.36,0.8 +0.305,0.112,1.75,2.82,0.8 +0.305,0.111,2,3.28,0.8 +0.305,0.112,2.25,3.73,0.8 From 861a4e9459164a40dfa91b9519258a8764b5f74e Mon Sep 17 00:00:00 2001 From: Chase Hamilton Date: Thu, 11 Aug 2022 13:46:15 -0500 Subject: [PATCH 20/20] 'all references to "erdc-cm" changed to "erdc"' --- OpenFOAM_Benchmarks/README.rst | 8 ++++---- README.rst | 4 ++-- private/proteus-mprans.yaml | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/OpenFOAM_Benchmarks/README.rst b/OpenFOAM_Benchmarks/README.rst index 39b88474..a9ca2965 100644 --- a/OpenFOAM_Benchmarks/README.rst +++ b/OpenFOAM_Benchmarks/README.rst @@ -2,18 +2,18 @@ OpenFOAM Benchmarks ===================================================== -https://github.com/erdc-cm/air-water-vv/OpenFOAM_Benchmarks/ +https://github.com/erdc/air-water-vv/OpenFOAM_Benchmarks/ Case descritpion ---------------------------- -- dambreakColagrossi, see https://github.com/erdc-cm/air-water-vv/2d/dambreak_Colagrossi/README.rst +- dambreakColagrossi, see https://github.com/erdc/air-water-vv/2d/dambreak_Colagrossi/README.rst -- dambreakWithObstacle, see http://foam.sourceforge.net/docs/Guides-a4/UserGuide.pdf (section 2.3) and https://github.com/erdc-cm/air-water-vv/2d/dambreak_Ubbink/README.rst +- dambreakWithObstacle, see http://foam.sourceforge.net/docs/Guides-a4/UserGuide.pdf (section 2.3) and https://github.com/erdc/air-water-vv/2d/dambreak_Ubbink/README.rst - lidDrivenCavity, see http://foam.sourceforge.net/docs/Guides-a4/UserGuide.pdf (Section 2.1) -- dambreakGomez, see https://github.com/erdc-cm/air-water-vv/blob/master/3d/dambreak_Gomez/README.rst +- dambreakGomez, see https://github.com/erdc/air-water-vv/blob/master/3d/dambreak_Gomez/README.rst How to set up and run OpenFOAM cases ------------------------ diff --git a/README.rst b/README.rst index 33fef22c..dc1b0021 100644 --- a/README.rst +++ b/README.rst @@ -2,7 +2,7 @@ Verification and validation for air/water flow models ===================================================== -https://github.com/erdc-cm/air-water-vv +https://github.com/erdc/air-water-vv Organization of the test set ---------------------------- @@ -16,7 +16,7 @@ test consists of a single directory including - All data files describing the geometry and physical parameters of the problem - A set of input files for a code - (e.g. https://github.com/erdc-cm/proteus) + (e.g. https://github.com/erdc/proteus) Adding new test problems ------------------------ diff --git a/private/proteus-mprans.yaml b/private/proteus-mprans.yaml index 8e1a4d58..f7cea748 100644 --- a/private/proteus-mprans.yaml +++ b/private/proteus-mprans.yaml @@ -4,7 +4,7 @@ dependencies: run: [proteus, numpy] sources: - - url: https://github.com/erdc-cm/proteus-mprans + - url: https://github.com/erdc/proteus-mprans key: git:fc5a90c2a50bb9716460876ad1ee91da598ff8f3 profile_links: