|
| 1 | +# %% [markdown] |
| 2 | +# # Navier Stokes benchmark: Couette flow |
| 3 | +# By: Juan Carlos Graciosa |
| 4 | +# |
| 5 | + |
| 6 | +# %% |
| 7 | +import os |
| 8 | + |
| 9 | +import petsc4py |
| 10 | +import underworld3 as uw |
| 11 | + |
| 12 | +import numpy as np |
| 13 | +import sympy |
| 14 | +import argparse |
| 15 | +import pickle |
| 16 | + |
| 17 | +#parser = argparse.ArgumentParser() |
| 18 | +#parser.add_argument('-i', "--idx", type=int, required=True) |
| 19 | +#parser.add_argument('-p', "--prev", type=int, required=True) # set to 0 if no prev_res, 1 if there is |
| 20 | +#args = parser.parse_args() |
| 21 | + |
| 22 | +#idx = args.idx |
| 23 | +#prev = args.prev |
| 24 | + |
| 25 | +idx = 0 |
| 26 | +prev = 0 |
| 27 | + |
| 28 | +# %% |
| 29 | +resolution = 16 |
| 30 | +refinement = 0 |
| 31 | +save_every = 200 |
| 32 | +maxsteps = 1 |
| 33 | +Cmax = 1 # target Courant number |
| 34 | + |
| 35 | +order = 1 # solver order |
| 36 | +tol = 1e-12 # solver tolerance (sets atol and rtol) |
| 37 | + |
| 38 | +mesh_type = "Pirr" # or Preg, Pirr, Quad |
| 39 | +qdeg = 3 |
| 40 | +Vdeg = 3 |
| 41 | +Pdeg = Vdeg - 1 |
| 42 | +Pcont = False |
| 43 | + |
| 44 | +# %% |
| 45 | +expt_name = f"Couette-res{resolution}-order{order}-{mesh_type}" |
| 46 | + |
| 47 | +outfile = f"{expt_name}_run{idx}" |
| 48 | +outdir = f"./{expt_name}" |
| 49 | + |
| 50 | +# %% |
| 51 | +if prev == 0: |
| 52 | + prev_idx = 0 |
| 53 | + infile = None |
| 54 | +else: |
| 55 | + prev_idx = int(idx) - 1 |
| 56 | + infile = f"{expt_name}_run{prev_idx}" |
| 57 | + |
| 58 | +if uw.mpi.rank == 0 and uw.mpi.size > 1: |
| 59 | + os.makedirs(f"{outdir}", exist_ok=True) |
| 60 | + |
| 61 | +# %% |
| 62 | +width = 4. |
| 63 | +height = 1. |
| 64 | +vel = 1. |
| 65 | + |
| 66 | +fluid_rho = 1. |
| 67 | +kin_visc = 1. |
| 68 | +dyn_visc = fluid_rho * kin_visc |
| 69 | + |
| 70 | +# %% |
| 71 | +minX, maxX = -0.5 * width, 0.5 * width |
| 72 | +minY, maxY = -0.5 * height, 0.5 * height |
| 73 | + |
| 74 | +if uw.mpi.rank == 0: |
| 75 | + print("min X, max X:", minX, maxX) |
| 76 | + print("min Y, max Y:", minY, maxY) |
| 77 | + print("kinematic viscosity: ", kin_visc) |
| 78 | + print("fluid density: ", fluid_rho) |
| 79 | + print("dynamic viscosity: ", kin_visc * fluid_rho) |
| 80 | + |
| 81 | +# %% |
| 82 | +# cell size calculation |
| 83 | +if mesh_type == "Preg": |
| 84 | + meshbox = uw.meshing.UnstructuredSimplexBox( minCoords=(minX, minY), maxCoords=(maxX, maxY), cellSize = 1 / resolution, qdegree = qdeg, regular = True) |
| 85 | +elif mesh_type == "Pirr": |
| 86 | + meshbox = uw.meshing.UnstructuredSimplexBox( minCoords=(minX, minY), maxCoords=(maxX, maxY), cellSize = 1 / resolution, qdegree = qdeg, regular = False) |
| 87 | +elif mesh_type == "Quad": |
| 88 | + meshbox = uw.meshing.StructuredQuadBox( minCoords=(minX, minY), maxCoords=(maxX, maxY), elementRes = (width * resolution, height * resolution), qdegree = qdeg, regular = False) |
| 89 | + |
| 90 | +# %% |
| 91 | +meshbox.dm.view() |
| 92 | + |
| 93 | +# %% |
| 94 | +v_soln = uw.discretisation.MeshVariable("U", meshbox, meshbox.dim, degree = Vdeg) |
| 95 | +p_soln = uw.discretisation.MeshVariable("P", meshbox, 1, degree = Pdeg, continuous = Pcont) |
| 96 | + |
| 97 | +# %% |
| 98 | +if infile is None: |
| 99 | + pass |
| 100 | +else: |
| 101 | + if uw.mpi.rank == 0: |
| 102 | + print(f"Reading: {infile}") |
| 103 | + |
| 104 | + v_soln.read_timestep(data_filename = infile, data_name = "U", index = maxsteps, outputPath = outdir) |
| 105 | + p_soln.read_timestep(data_filename = infile, data_name = "P", index = maxsteps, outputPath = outdir) |
| 106 | + |
| 107 | +# %% |
| 108 | +# Set solve options here (or remove default values |
| 109 | +# stokes.petsc_options.getAll() |
| 110 | + |
| 111 | +navier_stokes = uw.systems.NavierStokesSLCN( |
| 112 | + meshbox, |
| 113 | + velocityField = v_soln, |
| 114 | + pressureField = p_soln, |
| 115 | + rho = fluid_rho, |
| 116 | + verbose = False, |
| 117 | + order = order, |
| 118 | +) |
| 119 | + |
| 120 | +navier_stokes.constitutive_model = uw.constitutive_models.ViscousFlowModel |
| 121 | +# Constant visc |
| 122 | +navier_stokes.constitutive_model.Parameters.viscosity = dyn_visc |
| 123 | + |
| 124 | +navier_stokes.penalty = 0 |
| 125 | +navier_stokes.bodyforce = sympy.Matrix([0, 0]) |
| 126 | + |
| 127 | +# Velocity boundary conditions |
| 128 | +navier_stokes.add_dirichlet_bc((vel, 0.0), "Top") |
| 129 | +navier_stokes.add_dirichlet_bc((0.0, 0.0), "Bottom") |
| 130 | +# left and right are open |
| 131 | + |
| 132 | +navier_stokes.tolerance = tol |
| 133 | + |
| 134 | +# %% |
| 135 | +# navier_stokes.petsc_options["snes_monitor"] = None |
| 136 | +# navier_stokes.petsc_options["snes_converged_reason"] = None |
| 137 | +# navier_stokes.petsc_options["snes_monitor_short"] = None |
| 138 | +# navier_stokes.petsc_options["ksp_monitor"] = None |
| 139 | + |
| 140 | +# navier_stokes.petsc_options["snes_type"] = "newtonls" |
| 141 | +# navier_stokes.petsc_options["ksp_type"] = "fgmres" |
| 142 | + |
| 143 | +# navier_stokes.petsc_options["snes_max_it"] = 50 |
| 144 | +# navier_stokes.petsc_options["ksp_max_it"] = 50 |
| 145 | + |
| 146 | +navier_stokes.petsc_options["snes_monitor"] = None |
| 147 | +navier_stokes.petsc_options["ksp_monitor"] = None |
| 148 | + |
| 149 | +navier_stokes.petsc_options["snes_type"] = "newtonls" |
| 150 | +navier_stokes.petsc_options["ksp_type"] = "fgmres" |
| 151 | + |
| 152 | +navier_stokes.petsc_options.setValue("fieldsplit_velocity_pc_type", "mg") |
| 153 | +navier_stokes.petsc_options.setValue("fieldsplit_velocity_pc_mg_type", "kaskade") |
| 154 | +navier_stokes.petsc_options.setValue("fieldsplit_velocity_pc_mg_cycle_type", "w") |
| 155 | + |
| 156 | +navier_stokes.petsc_options["fieldsplit_velocity_mg_coarse_pc_type"] = "svd" |
| 157 | +navier_stokes.petsc_options["fieldsplit_velocity_ksp_type"] = "fcg" |
| 158 | +navier_stokes.petsc_options["fieldsplit_velocity_mg_levels_ksp_type"] = "chebyshev" |
| 159 | +navier_stokes.petsc_options["fieldsplit_velocity_mg_levels_ksp_max_it"] = 5 |
| 160 | +navier_stokes.petsc_options["fieldsplit_velocity_mg_levels_ksp_converged_maxits"] = None |
| 161 | + |
| 162 | +# # gasm is super-fast ... but mg seems to be bulletproof |
| 163 | +# # gamg is toughest wrt viscosity |
| 164 | + |
| 165 | +# navier_stokes.petsc_options.setValue("fieldsplit_pressure_pc_type", "gamg") |
| 166 | +# navier_stokes.petsc_options.setValue("fieldsplit_pressure_pc_mg_type", "additive") |
| 167 | +# navier_stokes.petsc_options.setValue("fieldsplit_pressure_pc_mg_cycle_type", "v") |
| 168 | + |
| 169 | +# # # mg, multiplicative - very robust ... similar to gamg, additive |
| 170 | + |
| 171 | +navier_stokes.petsc_options.setValue("fieldsplit_pressure_pc_type", "mg") |
| 172 | +navier_stokes.petsc_options.setValue("fieldsplit_pressure_pc_mg_type", "multiplicative") |
| 173 | +navier_stokes.petsc_options.setValue("fieldsplit_pressure_pc_mg_cycle_type", "v") |
| 174 | + |
| 175 | +# %% |
| 176 | +# set the timestep |
| 177 | +# for now, set it to be constant |
| 178 | +delta_x = meshbox.get_min_radius() |
| 179 | +max_vel = vel |
| 180 | + |
| 181 | +delta_t = Cmax*delta_x/max_vel |
| 182 | + |
| 183 | +if uw.mpi.rank == 0: |
| 184 | + print(f"Min radius: {delta_x}") |
| 185 | + print("Timestep used:", delta_t) |
| 186 | + |
| 187 | +# %% |
| 188 | +ts = 0 |
| 189 | +timeVal = np.zeros(maxsteps + 1) * np.nan # time values |
| 190 | +elapsed_time = 0.0 |
| 191 | + |
| 192 | +# %% |
| 193 | +for step in range(0, maxsteps): |
| 194 | + |
| 195 | + if uw.mpi.rank == 0: |
| 196 | + print(f"Timestep: {step}") |
| 197 | + |
| 198 | + navier_stokes.solve(timestep = delta_t, zero_init_guess=True) |
| 199 | + |
| 200 | + elapsed_time += delta_t |
| 201 | + timeVal[step] = elapsed_time |
| 202 | + |
| 203 | + if uw.mpi.rank == 0: |
| 204 | + print("Timestep {}, t {}, dt {}".format(ts, elapsed_time, delta_t)) |
| 205 | + |
| 206 | + if ts % save_every == 0 and ts > 0: |
| 207 | + meshbox.write_timestep( |
| 208 | + outfile, |
| 209 | + meshUpdates=True, |
| 210 | + meshVars=[p_soln, v_soln], |
| 211 | + outputPath=outdir, |
| 212 | + index =ts, |
| 213 | + ) |
| 214 | + |
| 215 | + with open(outdir + f"/{outfile}.pkl", "wb") as f: |
| 216 | + pickle.dump([timeVal], f) |
| 217 | + |
| 218 | + # update timestep |
| 219 | + ts += 1 |
| 220 | + |
| 221 | +# save after all iterations |
| 222 | +meshbox.write_timestep( |
| 223 | + outfile, |
| 224 | + meshUpdates=True, |
| 225 | + meshVars=[p_soln, v_soln], |
| 226 | + outputPath=outdir, |
| 227 | + index =maxsteps, |
| 228 | +) |
| 229 | + |
| 230 | +with open(outdir + f"/{outfile}.pkl", "wb") as f: |
| 231 | + pickle.dump([timeVal], f) |
| 232 | + |
| 233 | + |
0 commit comments