From f9b7bcb6dbd2aa6d6ed932deeb0204542ef813e4 Mon Sep 17 00:00:00 2001 From: eric Date: Thu, 6 Nov 2025 23:38:25 +0800 Subject: [PATCH] add eno example --- .../analytical_solution/01/theory.py | 54 ++ .../01/test_periodic_mapping.py | 18 + .../eno/eno_coef/01/crj.py | 46 + .../eno/rusanov/calc_coef/rk1/eno1/01/eno.py | 466 ++++++++++ .../eno/rusanov/rk1/eno1-10/01/eno.py | 476 ++++++++++ .../eno/rusanov/rk1/eno1-7/01/eno.py | 360 ++++++++ .../eno/rusanov/rk1/eno1-7/01/plot.py | 53 ++ .../eno/rusanov/rk1/eno1/01/eno.py | 271 ++++++ .../eno/rusanov/rk1/eno1/01/plot.py | 53 ++ .../eno/rusanov/rk1/eno2/01/eno.py | 238 +++++ .../eno/rusanov/rk1/eno2/01/plot.py | 53 ++ .../eno/rusanov/rk1/eno2/01a/eno.py | 272 ++++++ .../eno/rusanov/rk1/eno2/01a/plot.py | 53 ++ .../eno/rusanov/rk1/eno3/01/eno.py | 239 +++++ .../eno/rusanov/rk1/eno3/01/plot.py | 53 ++ .../eno/rusanov/rk1/eno3/01a/eno.py | 273 ++++++ .../eno/rusanov/rk1/eno3/01a/plot.py | 53 ++ .../eno/rusanov/rk1/eno4/01/eno.py | 240 +++++ .../eno/rusanov/rk1/eno4/01/plot.py | 53 ++ .../eno/rusanov/rk1/eno4/01a/eno.py | 274 ++++++ .../eno/rusanov/rk1/eno4/01a/plot.py | 53 ++ .../eno/rusanov/rk1/eno5/01/eno.py | 241 ++++++ .../eno/rusanov/rk1/eno5/01/plot.py | 53 ++ .../eno/rusanov/rk1/eno5/01a/eno.py | 275 ++++++ .../eno/rusanov/rk1/eno5/01a/plot.py | 53 ++ .../eno/rusanov/rk1/eno6/01/eno.py | 242 ++++++ .../eno/rusanov/rk1/eno6/01/plot.py | 53 ++ .../eno/rusanov/rk1/eno6/01a/eno.py | 276 ++++++ .../eno/rusanov/rk1/eno6/01a/plot.py | 53 ++ .../eno/rusanov/rk1/eno7/01/eno.py | 279 ++++++ .../eno/rusanov/rk1/eno7/01/plot.py | 53 ++ .../eno/rusanov/rk1/eno7/01a/eno.py | 277 ++++++ .../eno/rusanov/rk1/eno7/01a/plot.py | 53 ++ .../eno/rusanov/rk2/compare/01/plot.py | 21 + .../eno/rusanov/rk2/compare/01a/plot.py | 41 + .../eno/rusanov/rk2/compare/01b/plot.py | 63 ++ .../eno/rusanov/rk2/compare/01c/plot.py | 81 ++ .../eno/rusanov/rk2/compare/01d/plot.py | 101 +++ .../eno/rusanov/rk2/compare/01e/plot.py | 101 +++ .../eno/rusanov/rk2/compare/solution_eno1.plt | 40 + .../eno/rusanov/rk2/compare/solution_eno2.plt | 40 + .../eno/rusanov/rk2/compare/solution_eno3.plt | 40 + .../eno/rusanov/rk2/compare/solution_eno4.plt | 40 + .../eno/rusanov/rk2/compare/solution_eno5.plt | 40 + .../eno/rusanov/rk2/compare/solution_eno6.plt | 40 + .../eno/rusanov/rk2/compare/solution_eno7.plt | 40 + .../eno/rusanov/rk2/eno1-7/01/eno.py | 360 ++++++++ .../eno/rusanov/rk2/eno1-7/01/plot.py | 53 ++ .../eno/rusanov/rk2/eno1/01/eno.py | 311 +++++++ .../eno/rusanov/rk2/eno1/01/plot.py | 53 ++ .../eno/rusanov/rk2/eno2/01/eno.py | 311 +++++++ .../eno/rusanov/rk2/eno2/01/plot.py | 53 ++ .../eno/rusanov/rk2/eno3/01/eno.py | 311 +++++++ .../eno/rusanov/rk2/eno3/01/plot.py | 53 ++ .../eno/rusanov/rk2/eno4/01/eno.py | 311 +++++++ .../eno/rusanov/rk2/eno4/01/plot.py | 53 ++ .../eno/rusanov/rk2/eno5/01/eno.py | 311 +++++++ .../eno/rusanov/rk2/eno5/01/plot.py | 53 ++ .../eno/rusanov/rk2/eno6/01/eno.py | 311 +++++++ .../eno/rusanov/rk2/eno6/01/plot.py | 53 ++ .../eno/rusanov/rk2/eno7/01/eno.py | 311 +++++++ .../eno/rusanov/rk2/eno7/01/plot.py | 53 ++ .../eno/rusanov/rk3/eno1-7/01/eno.py | 302 +++++++ .../eno/rusanov/rk3/eno1-7/01/plot.py | 53 ++ .../eno/rusanov/rk3/eno1-7/01a/eno.py | 306 +++++++ .../eno/rusanov/rk3/eno1-7/01a/plot.py | 53 ++ .../eno/rusanov/rk3/eno1-7/01b/eno.py | 307 +++++++ .../eno/rusanov/rk3/eno1-7/01b/plot.py | 53 ++ .../eno/rusanov/rk3/eno1-7/01c/eno.py | 313 +++++++ .../eno/rusanov/rk3/eno1-7/01c/plot.py | 53 ++ .../eno/rusanov/rk3/eno1-7/01d/eno.py | 328 +++++++ .../eno/rusanov/rk3/eno1-7/01d/plot.py | 53 ++ .../eno/rusanov/rk3/eno1-7/01e/eno.py | 359 ++++++++ .../eno/rusanov/rk3/eno1-7/01e/plot.py | 53 ++ .../eno/rusanov/rk3/eno1-7/01f/eno.py | 344 ++++++++ .../eno/rusanov/rk3/eno1-7/01f/plot.py | 53 ++ .../eno/rusanov/rk3/eno1-7/01g/eno.py | 354 ++++++++ .../eno/rusanov/rk3/eno1-7/01g/plot.py | 53 ++ .../eno/rusanov/rk3/eno1-7/01h/eno.py | 352 ++++++++ .../eno/rusanov/rk3/eno1-7/01h/plot.py | 53 ++ .../eno/rusanov/rk3/eno1-7/02/eno.py | 357 ++++++++ .../eno/rusanov/rk3/eno1-7/02/plot.py | 53 ++ .../rusanov/timestep/rk1-eno/eno1/01/eno.py | 426 +++++++++ .../rusanov/timestep/rk1-eno/eno1/01/plot.py | 53 ++ .../rusanov/timestep/rk1-eno/eno2/01/eno.py | 426 +++++++++ .../rusanov/timestep/rk1-eno/eno2/01/plot.py | 53 ++ .../rusanov/timestep/rk1-eno/eno3/01/eno.py | 426 +++++++++ .../rusanov/timestep/rk1-eno/eno3/01/plot.py | 53 ++ .../rusanov/timestep/rk1-eno/eno4/01/eno.py | 426 +++++++++ .../rusanov/timestep/rk1-eno/eno4/01/plot.py | 53 ++ .../rusanov/timestep/rk1-eno/eno5/01/eno.py | 426 +++++++++ .../rusanov/timestep/rk1-eno/eno5/01/plot.py | 53 ++ .../rusanov/timestep/rk1-eno/eno6/01/eno.py | 426 +++++++++ .../rusanov/timestep/rk1-eno/eno6/01/plot.py | 53 ++ .../rusanov/timestep/rk1-eno/eno7/01/eno.py | 426 +++++++++ .../rusanov/timestep/rk1-eno/eno7/01/plot.py | 53 ++ .../eno/rusanov/timestep/rk1-eno1/01/eno.py | 360 ++++++++ .../eno/rusanov/timestep/rk1-eno1/01/plot.py | 53 ++ .../eno/rusanov/timestep/rk1-eno1/01a/eno.py | 415 +++++++++ .../eno/rusanov/timestep/rk1-eno1/01a/plot.py | 53 ++ .../eno/rusanov/timestep/rk1-eno2/01/eno.py | 426 +++++++++ .../eno/rusanov/timestep/rk1-eno2/01/plot.py | 53 ++ .../rusanov/timestep/rk2-eno/eno1/01/eno.py | 426 +++++++++ .../rusanov/timestep/rk2-eno/eno1/01/plot.py | 53 ++ .../rusanov/timestep/rk2-eno/eno2/01/eno.py | 426 +++++++++ .../rusanov/timestep/rk2-eno/eno2/01/plot.py | 53 ++ .../rusanov/timestep/rk2-eno/eno3/01/eno.py | 426 +++++++++ .../rusanov/timestep/rk2-eno/eno3/01/plot.py | 53 ++ .../rusanov/timestep/rk2-eno/eno4/01/eno.py | 426 +++++++++ .../rusanov/timestep/rk2-eno/eno4/01/plot.py | 53 ++ .../rusanov/timestep/rk2-eno/eno5/01/eno.py | 426 +++++++++ .../rusanov/timestep/rk2-eno/eno5/01/plot.py | 53 ++ .../rusanov/timestep/rk2-eno/eno6/01/eno.py | 426 +++++++++ .../rusanov/timestep/rk2-eno/eno6/01/plot.py | 53 ++ .../rusanov/timestep/rk2-eno/eno7/01/eno.py | 426 +++++++++ .../rusanov/timestep/rk2-eno/eno7/01/plot.py | 53 ++ .../eno/rusanov/timestep/rk2-eno1/01/eno.py | 425 +++++++++ .../eno/rusanov/timestep/rk2-eno1/01/plot.py | 53 ++ .../rusanov/timestep/rk3-eno/eno1/01/eno.py | 426 +++++++++ .../rusanov/timestep/rk3-eno/eno1/01/plot.py | 53 ++ .../rusanov/timestep/rk3-eno/eno2/01/eno.py | 426 +++++++++ .../rusanov/timestep/rk3-eno/eno2/01/plot.py | 53 ++ .../rusanov/timestep/rk3-eno/eno3/01/eno.py | 426 +++++++++ .../rusanov/timestep/rk3-eno/eno3/01/plot.py | 53 ++ .../rusanov/timestep/rk3-eno/eno4/01/eno.py | 426 +++++++++ .../rusanov/timestep/rk3-eno/eno4/01/plot.py | 53 ++ .../rusanov/timestep/rk3-eno/eno5/01/eno.py | 426 +++++++++ .../rusanov/timestep/rk3-eno/eno5/01/plot.py | 53 ++ .../rusanov/timestep/rk3-eno/eno6/01/eno.py | 426 +++++++++ .../rusanov/timestep/rk3-eno/eno6/01/plot.py | 53 ++ .../rusanov/timestep/rk3-eno/eno7/01/eno.py | 426 +++++++++ .../rusanov/timestep/rk3-eno/eno7/01/plot.py | 53 ++ .../eno/rusanov/timestep/rk3-eno1/01/eno.py | 425 +++++++++ .../eno/rusanov/timestep/rk3-eno1/01/plot.py | 53 ++ .../eno2/fortran/01/CMakeLists.txt | 28 - .../eno2/fortran/01/README.txt | 1 - .../eno2/fortran/01/enoburgers.f90 | 267 ------ .../eno3/cpp/01/BurgersField.cpp | 366 -------- .../eno3/cpp/01/BurgersField.h | 31 - .../eno3/cpp/01/CMakeLists.txt | 106 --- .../eno3/cpp/01/CgnsUtil.cpp | 584 ------------- .../eno3/cpp/01/CgnsUtil.h | 50 -- .../eno3/cpp/01/ConvectionField.cpp | 287 ------ .../eno3/cpp/01/ConvectionField.h | 33 - .../1d-linear-convection/eno3/cpp/01/Eno.cpp | 135 --- .../1d-linear-convection/eno3/cpp/01/Eno.h | 7 - .../eno3/cpp/01/EulerField.cpp | 818 ------------------ .../eno3/cpp/01/EulerField.h | 45 - .../eno3/cpp/01/Field.cpp | 342 -------- .../1d-linear-convection/eno3/cpp/01/Field.h | 54 -- .../eno3/cpp/01/Global.cpp | 465 ---------- .../1d-linear-convection/eno3/cpp/01/Global.h | 180 ---- .../1d-linear-convection/eno3/cpp/01/Grid.cpp | 290 ------- .../1d-linear-convection/eno3/cpp/01/Grid.h | 115 --- .../eno3/cpp/01/HeatField.cpp | 228 ----- .../eno3/cpp/01/HeatField.h | 28 - .../eno3/cpp/01/Linear Convection_plot.py | 70 -- .../eno3/cpp/01/Linear Convection_plotBAK.py | 69 -- .../eno3/cpp/01/LogFile.cpp | 138 --- .../eno3/cpp/01/LogFile.h | 27 - .../eno3/cpp/01/MyCRWenoPlot.py | 64 -- .../eno3/cpp/01/MyWenoPlot.py | 53 -- .../eno3/cpp/01/Parallel.cpp | 100 --- .../eno3/cpp/01/Parallel.h | 85 -- .../1d-linear-convection/eno3/cpp/01/Post.cpp | 38 - .../1d-linear-convection/eno3/cpp/01/Post.h | 6 - .../eno3/cpp/01/README.txt | 3 - .../eno3/cpp/01/Solver.cpp | 795 ----------------- .../1d-linear-convection/eno3/cpp/01/Solver.h | 50 -- .../eno3/cpp/01/Vec1d.cpp | 10 - .../1d-linear-convection/eno3/cpp/01/Vec1d.h | 72 -- .../1d-linear-convection/eno3/cpp/01/Weno.cpp | 399 --------- .../1d-linear-convection/eno3/cpp/01/Weno.h | 36 - .../eno3/cpp/01/ZoneState.cpp | 20 - .../eno3/cpp/01/ZoneState.h | 21 - .../eno3/cpp/01/burgers.json | 17 - .../eno3/cpp/01/burgers_ftcs.json | 15 - .../eno3/cpp/01/burgers_plot.py | 64 -- .../1d-linear-convection/eno3/cpp/01/cfd.json | 12 - .../eno3/cpp/01/heat.json | 17 - .../eno3/cpp/01/heat_plot.py | 116 --- .../eno3/cpp/01/heaticp.json | 13 - .../eno3/cpp/01/hxmath.cpp | 30 - .../1d-linear-convection/eno3/cpp/01/hxmath.h | 16 - .../eno3/cpp/01/linearconvection.json | 19 - .../eno3/cpp/01/linearconvection1d.cgns | Bin 10746 -> 0 bytes .../eno3/cpp/01/linearconvectionBAK.json | 19 - .../1d-linear-convection/eno3/cpp/01/main.cpp | 8 - .../1d-linear-convection/eno3/cpp/01/plot.py | 58 -- .../eno3/cpp/01/plotting2.jl | 49 -- .../1d-linear-convection/eno3/cpp/01/sod.json | 19 - .../eno3/cpp/01/sod_plot.py | 173 ---- .../eno3/cpp/01/sod_sort.py | 68 -- .../eno3/cpp/01/sod_sort_on_xcoor.py | 85 -- .../eno3/cpp/01/sod_theory.plt | 29 - .../1d-linear-convection/lax/python/01/lax.py | 77 ++ .../lax/python/01a/lax.py | 87 ++ .../1d-linear-convection/lax/python/02/lax.py | 44 + .../lax/python/02a/lax.py | 45 + .../lax/python/02b/lax.py | 46 + .../1d-linear-convection/lax/python/03/lax.py | 33 + .../lax/python/03a/lax.py | 45 + .../lax/python/03b/lax.py | 61 ++ .../lax/python/03c/lax.py | 46 + .../lax/python/03d/lax.py | 50 ++ .../rusanov/python/01/rusanov.py | 71 ++ .../rusanov/python/02/rusanov.py | 78 ++ .../rusanov/python/02a/rusanov.py | 83 ++ .../rusanov/python/02b/rusanov.py | 84 ++ .../rusanov/python/02c/rusanov.py | 84 ++ .../rusanov/python/02d/rusanov.py | 103 +++ .../rusanov/python/02e/rusanov.py | 98 +++ .../weno3/python/01/weno.py | 372 ++++++++ .../weno3/python/01/weno3.py | 68 -- .../weno3/python/01a/weno.py | 492 +++++++++++ .../weno3/python/01b/weno.py | 570 ++++++++++++ .../weno3/python/01c/weno.py | 581 +++++++++++++ .../weno5/python/01/weno.py | 682 +++++++++++++++ example/weno-coef/eno/eno2_coef/01/testprj.py | 14 + .../weno-coef/eno/eno2_coef/01a/testprj.py | 21 + example/weno-coef/eno/eno2_coef/02/testprj.py | 21 + example/weno-coef/eno/eno2_coef/03/testprj.py | 20 + example/weno-coef/eno/eno2_coef/04/testprj.py | 20 + 223 files changed, 29363 insertions(+), 7411 deletions(-) create mode 100644 example/1d-linear-convection/analytical_solution/01/theory.py create mode 100644 example/1d-linear-convection/analytical_solution/test_periodic_mapping/01/test_periodic_mapping.py create mode 100644 example/1d-linear-convection/eno/eno_coef/01/crj.py create mode 100644 example/1d-linear-convection/eno/rusanov/calc_coef/rk1/eno1/01/eno.py create mode 100644 example/1d-linear-convection/eno/rusanov/rk1/eno1-10/01/eno.py create mode 100644 example/1d-linear-convection/eno/rusanov/rk1/eno1-7/01/eno.py create mode 100644 example/1d-linear-convection/eno/rusanov/rk1/eno1-7/01/plot.py create mode 100644 example/1d-linear-convection/eno/rusanov/rk1/eno1/01/eno.py create mode 100644 example/1d-linear-convection/eno/rusanov/rk1/eno1/01/plot.py create mode 100644 example/1d-linear-convection/eno/rusanov/rk1/eno2/01/eno.py create mode 100644 example/1d-linear-convection/eno/rusanov/rk1/eno2/01/plot.py create mode 100644 example/1d-linear-convection/eno/rusanov/rk1/eno2/01a/eno.py create mode 100644 example/1d-linear-convection/eno/rusanov/rk1/eno2/01a/plot.py create mode 100644 example/1d-linear-convection/eno/rusanov/rk1/eno3/01/eno.py create mode 100644 example/1d-linear-convection/eno/rusanov/rk1/eno3/01/plot.py create mode 100644 example/1d-linear-convection/eno/rusanov/rk1/eno3/01a/eno.py create mode 100644 example/1d-linear-convection/eno/rusanov/rk1/eno3/01a/plot.py create mode 100644 example/1d-linear-convection/eno/rusanov/rk1/eno4/01/eno.py create mode 100644 example/1d-linear-convection/eno/rusanov/rk1/eno4/01/plot.py create mode 100644 example/1d-linear-convection/eno/rusanov/rk1/eno4/01a/eno.py create mode 100644 example/1d-linear-convection/eno/rusanov/rk1/eno4/01a/plot.py create mode 100644 example/1d-linear-convection/eno/rusanov/rk1/eno5/01/eno.py create mode 100644 example/1d-linear-convection/eno/rusanov/rk1/eno5/01/plot.py create mode 100644 example/1d-linear-convection/eno/rusanov/rk1/eno5/01a/eno.py create mode 100644 example/1d-linear-convection/eno/rusanov/rk1/eno5/01a/plot.py create mode 100644 example/1d-linear-convection/eno/rusanov/rk1/eno6/01/eno.py create mode 100644 example/1d-linear-convection/eno/rusanov/rk1/eno6/01/plot.py create mode 100644 example/1d-linear-convection/eno/rusanov/rk1/eno6/01a/eno.py create mode 100644 example/1d-linear-convection/eno/rusanov/rk1/eno6/01a/plot.py create mode 100644 example/1d-linear-convection/eno/rusanov/rk1/eno7/01/eno.py create mode 100644 example/1d-linear-convection/eno/rusanov/rk1/eno7/01/plot.py create mode 100644 example/1d-linear-convection/eno/rusanov/rk1/eno7/01a/eno.py create mode 100644 example/1d-linear-convection/eno/rusanov/rk1/eno7/01a/plot.py create mode 100644 example/1d-linear-convection/eno/rusanov/rk2/compare/01/plot.py create mode 100644 example/1d-linear-convection/eno/rusanov/rk2/compare/01a/plot.py create mode 100644 example/1d-linear-convection/eno/rusanov/rk2/compare/01b/plot.py create mode 100644 example/1d-linear-convection/eno/rusanov/rk2/compare/01c/plot.py create mode 100644 example/1d-linear-convection/eno/rusanov/rk2/compare/01d/plot.py create mode 100644 example/1d-linear-convection/eno/rusanov/rk2/compare/01e/plot.py create mode 100644 example/1d-linear-convection/eno/rusanov/rk2/compare/solution_eno1.plt create mode 100644 example/1d-linear-convection/eno/rusanov/rk2/compare/solution_eno2.plt create mode 100644 example/1d-linear-convection/eno/rusanov/rk2/compare/solution_eno3.plt create mode 100644 example/1d-linear-convection/eno/rusanov/rk2/compare/solution_eno4.plt create mode 100644 example/1d-linear-convection/eno/rusanov/rk2/compare/solution_eno5.plt create mode 100644 example/1d-linear-convection/eno/rusanov/rk2/compare/solution_eno6.plt create mode 100644 example/1d-linear-convection/eno/rusanov/rk2/compare/solution_eno7.plt create mode 100644 example/1d-linear-convection/eno/rusanov/rk2/eno1-7/01/eno.py create mode 100644 example/1d-linear-convection/eno/rusanov/rk2/eno1-7/01/plot.py create mode 100644 example/1d-linear-convection/eno/rusanov/rk2/eno1/01/eno.py create mode 100644 example/1d-linear-convection/eno/rusanov/rk2/eno1/01/plot.py create mode 100644 example/1d-linear-convection/eno/rusanov/rk2/eno2/01/eno.py create mode 100644 example/1d-linear-convection/eno/rusanov/rk2/eno2/01/plot.py create mode 100644 example/1d-linear-convection/eno/rusanov/rk2/eno3/01/eno.py create mode 100644 example/1d-linear-convection/eno/rusanov/rk2/eno3/01/plot.py create mode 100644 example/1d-linear-convection/eno/rusanov/rk2/eno4/01/eno.py create mode 100644 example/1d-linear-convection/eno/rusanov/rk2/eno4/01/plot.py create mode 100644 example/1d-linear-convection/eno/rusanov/rk2/eno5/01/eno.py create mode 100644 example/1d-linear-convection/eno/rusanov/rk2/eno5/01/plot.py create mode 100644 example/1d-linear-convection/eno/rusanov/rk2/eno6/01/eno.py create mode 100644 example/1d-linear-convection/eno/rusanov/rk2/eno6/01/plot.py create mode 100644 example/1d-linear-convection/eno/rusanov/rk2/eno7/01/eno.py create mode 100644 example/1d-linear-convection/eno/rusanov/rk2/eno7/01/plot.py create mode 100644 example/1d-linear-convection/eno/rusanov/rk3/eno1-7/01/eno.py create mode 100644 example/1d-linear-convection/eno/rusanov/rk3/eno1-7/01/plot.py create mode 100644 example/1d-linear-convection/eno/rusanov/rk3/eno1-7/01a/eno.py create mode 100644 example/1d-linear-convection/eno/rusanov/rk3/eno1-7/01a/plot.py create mode 100644 example/1d-linear-convection/eno/rusanov/rk3/eno1-7/01b/eno.py create mode 100644 example/1d-linear-convection/eno/rusanov/rk3/eno1-7/01b/plot.py create mode 100644 example/1d-linear-convection/eno/rusanov/rk3/eno1-7/01c/eno.py create mode 100644 example/1d-linear-convection/eno/rusanov/rk3/eno1-7/01c/plot.py create mode 100644 example/1d-linear-convection/eno/rusanov/rk3/eno1-7/01d/eno.py create mode 100644 example/1d-linear-convection/eno/rusanov/rk3/eno1-7/01d/plot.py create mode 100644 example/1d-linear-convection/eno/rusanov/rk3/eno1-7/01e/eno.py create mode 100644 example/1d-linear-convection/eno/rusanov/rk3/eno1-7/01e/plot.py create mode 100644 example/1d-linear-convection/eno/rusanov/rk3/eno1-7/01f/eno.py create mode 100644 example/1d-linear-convection/eno/rusanov/rk3/eno1-7/01f/plot.py create mode 100644 example/1d-linear-convection/eno/rusanov/rk3/eno1-7/01g/eno.py create mode 100644 example/1d-linear-convection/eno/rusanov/rk3/eno1-7/01g/plot.py create mode 100644 example/1d-linear-convection/eno/rusanov/rk3/eno1-7/01h/eno.py create mode 100644 example/1d-linear-convection/eno/rusanov/rk3/eno1-7/01h/plot.py create mode 100644 example/1d-linear-convection/eno/rusanov/rk3/eno1-7/02/eno.py create mode 100644 example/1d-linear-convection/eno/rusanov/rk3/eno1-7/02/plot.py create mode 100644 example/1d-linear-convection/eno/rusanov/timestep/rk1-eno/eno1/01/eno.py create mode 100644 example/1d-linear-convection/eno/rusanov/timestep/rk1-eno/eno1/01/plot.py create mode 100644 example/1d-linear-convection/eno/rusanov/timestep/rk1-eno/eno2/01/eno.py create mode 100644 example/1d-linear-convection/eno/rusanov/timestep/rk1-eno/eno2/01/plot.py create mode 100644 example/1d-linear-convection/eno/rusanov/timestep/rk1-eno/eno3/01/eno.py create mode 100644 example/1d-linear-convection/eno/rusanov/timestep/rk1-eno/eno3/01/plot.py create mode 100644 example/1d-linear-convection/eno/rusanov/timestep/rk1-eno/eno4/01/eno.py create mode 100644 example/1d-linear-convection/eno/rusanov/timestep/rk1-eno/eno4/01/plot.py create mode 100644 example/1d-linear-convection/eno/rusanov/timestep/rk1-eno/eno5/01/eno.py create mode 100644 example/1d-linear-convection/eno/rusanov/timestep/rk1-eno/eno5/01/plot.py create mode 100644 example/1d-linear-convection/eno/rusanov/timestep/rk1-eno/eno6/01/eno.py create mode 100644 example/1d-linear-convection/eno/rusanov/timestep/rk1-eno/eno6/01/plot.py create mode 100644 example/1d-linear-convection/eno/rusanov/timestep/rk1-eno/eno7/01/eno.py create mode 100644 example/1d-linear-convection/eno/rusanov/timestep/rk1-eno/eno7/01/plot.py create mode 100644 example/1d-linear-convection/eno/rusanov/timestep/rk1-eno1/01/eno.py create mode 100644 example/1d-linear-convection/eno/rusanov/timestep/rk1-eno1/01/plot.py create mode 100644 example/1d-linear-convection/eno/rusanov/timestep/rk1-eno1/01a/eno.py create mode 100644 example/1d-linear-convection/eno/rusanov/timestep/rk1-eno1/01a/plot.py create mode 100644 example/1d-linear-convection/eno/rusanov/timestep/rk1-eno2/01/eno.py create mode 100644 example/1d-linear-convection/eno/rusanov/timestep/rk1-eno2/01/plot.py create mode 100644 example/1d-linear-convection/eno/rusanov/timestep/rk2-eno/eno1/01/eno.py create mode 100644 example/1d-linear-convection/eno/rusanov/timestep/rk2-eno/eno1/01/plot.py create mode 100644 example/1d-linear-convection/eno/rusanov/timestep/rk2-eno/eno2/01/eno.py create mode 100644 example/1d-linear-convection/eno/rusanov/timestep/rk2-eno/eno2/01/plot.py create mode 100644 example/1d-linear-convection/eno/rusanov/timestep/rk2-eno/eno3/01/eno.py create mode 100644 example/1d-linear-convection/eno/rusanov/timestep/rk2-eno/eno3/01/plot.py create mode 100644 example/1d-linear-convection/eno/rusanov/timestep/rk2-eno/eno4/01/eno.py create mode 100644 example/1d-linear-convection/eno/rusanov/timestep/rk2-eno/eno4/01/plot.py create mode 100644 example/1d-linear-convection/eno/rusanov/timestep/rk2-eno/eno5/01/eno.py create mode 100644 example/1d-linear-convection/eno/rusanov/timestep/rk2-eno/eno5/01/plot.py create mode 100644 example/1d-linear-convection/eno/rusanov/timestep/rk2-eno/eno6/01/eno.py create mode 100644 example/1d-linear-convection/eno/rusanov/timestep/rk2-eno/eno6/01/plot.py create mode 100644 example/1d-linear-convection/eno/rusanov/timestep/rk2-eno/eno7/01/eno.py create mode 100644 example/1d-linear-convection/eno/rusanov/timestep/rk2-eno/eno7/01/plot.py create mode 100644 example/1d-linear-convection/eno/rusanov/timestep/rk2-eno1/01/eno.py create mode 100644 example/1d-linear-convection/eno/rusanov/timestep/rk2-eno1/01/plot.py create mode 100644 example/1d-linear-convection/eno/rusanov/timestep/rk3-eno/eno1/01/eno.py create mode 100644 example/1d-linear-convection/eno/rusanov/timestep/rk3-eno/eno1/01/plot.py create mode 100644 example/1d-linear-convection/eno/rusanov/timestep/rk3-eno/eno2/01/eno.py create mode 100644 example/1d-linear-convection/eno/rusanov/timestep/rk3-eno/eno2/01/plot.py create mode 100644 example/1d-linear-convection/eno/rusanov/timestep/rk3-eno/eno3/01/eno.py create mode 100644 example/1d-linear-convection/eno/rusanov/timestep/rk3-eno/eno3/01/plot.py create mode 100644 example/1d-linear-convection/eno/rusanov/timestep/rk3-eno/eno4/01/eno.py create mode 100644 example/1d-linear-convection/eno/rusanov/timestep/rk3-eno/eno4/01/plot.py create mode 100644 example/1d-linear-convection/eno/rusanov/timestep/rk3-eno/eno5/01/eno.py create mode 100644 example/1d-linear-convection/eno/rusanov/timestep/rk3-eno/eno5/01/plot.py create mode 100644 example/1d-linear-convection/eno/rusanov/timestep/rk3-eno/eno6/01/eno.py create mode 100644 example/1d-linear-convection/eno/rusanov/timestep/rk3-eno/eno6/01/plot.py create mode 100644 example/1d-linear-convection/eno/rusanov/timestep/rk3-eno/eno7/01/eno.py create mode 100644 example/1d-linear-convection/eno/rusanov/timestep/rk3-eno/eno7/01/plot.py create mode 100644 example/1d-linear-convection/eno/rusanov/timestep/rk3-eno1/01/eno.py create mode 100644 example/1d-linear-convection/eno/rusanov/timestep/rk3-eno1/01/plot.py delete mode 100644 example/1d-linear-convection/eno2/fortran/01/CMakeLists.txt delete mode 100644 example/1d-linear-convection/eno2/fortran/01/README.txt delete mode 100644 example/1d-linear-convection/eno2/fortran/01/enoburgers.f90 delete mode 100644 example/1d-linear-convection/eno3/cpp/01/BurgersField.cpp delete mode 100644 example/1d-linear-convection/eno3/cpp/01/BurgersField.h delete mode 100644 example/1d-linear-convection/eno3/cpp/01/CMakeLists.txt delete mode 100644 example/1d-linear-convection/eno3/cpp/01/CgnsUtil.cpp delete mode 100644 example/1d-linear-convection/eno3/cpp/01/CgnsUtil.h delete mode 100644 example/1d-linear-convection/eno3/cpp/01/ConvectionField.cpp delete mode 100644 example/1d-linear-convection/eno3/cpp/01/ConvectionField.h delete mode 100644 example/1d-linear-convection/eno3/cpp/01/Eno.cpp delete mode 100644 example/1d-linear-convection/eno3/cpp/01/Eno.h delete mode 100644 example/1d-linear-convection/eno3/cpp/01/EulerField.cpp delete mode 100644 example/1d-linear-convection/eno3/cpp/01/EulerField.h delete mode 100644 example/1d-linear-convection/eno3/cpp/01/Field.cpp delete mode 100644 example/1d-linear-convection/eno3/cpp/01/Field.h delete mode 100644 example/1d-linear-convection/eno3/cpp/01/Global.cpp delete mode 100644 example/1d-linear-convection/eno3/cpp/01/Global.h delete mode 100644 example/1d-linear-convection/eno3/cpp/01/Grid.cpp delete mode 100644 example/1d-linear-convection/eno3/cpp/01/Grid.h delete mode 100644 example/1d-linear-convection/eno3/cpp/01/HeatField.cpp delete mode 100644 example/1d-linear-convection/eno3/cpp/01/HeatField.h delete mode 100644 example/1d-linear-convection/eno3/cpp/01/Linear Convection_plot.py delete mode 100644 example/1d-linear-convection/eno3/cpp/01/Linear Convection_plotBAK.py delete mode 100644 example/1d-linear-convection/eno3/cpp/01/LogFile.cpp delete mode 100644 example/1d-linear-convection/eno3/cpp/01/LogFile.h delete mode 100644 example/1d-linear-convection/eno3/cpp/01/MyCRWenoPlot.py delete mode 100644 example/1d-linear-convection/eno3/cpp/01/MyWenoPlot.py delete mode 100644 example/1d-linear-convection/eno3/cpp/01/Parallel.cpp delete mode 100644 example/1d-linear-convection/eno3/cpp/01/Parallel.h delete mode 100644 example/1d-linear-convection/eno3/cpp/01/Post.cpp delete mode 100644 example/1d-linear-convection/eno3/cpp/01/Post.h delete mode 100644 example/1d-linear-convection/eno3/cpp/01/README.txt delete mode 100644 example/1d-linear-convection/eno3/cpp/01/Solver.cpp delete mode 100644 example/1d-linear-convection/eno3/cpp/01/Solver.h delete mode 100644 example/1d-linear-convection/eno3/cpp/01/Vec1d.cpp delete mode 100644 example/1d-linear-convection/eno3/cpp/01/Vec1d.h delete mode 100644 example/1d-linear-convection/eno3/cpp/01/Weno.cpp delete mode 100644 example/1d-linear-convection/eno3/cpp/01/Weno.h delete mode 100644 example/1d-linear-convection/eno3/cpp/01/ZoneState.cpp delete mode 100644 example/1d-linear-convection/eno3/cpp/01/ZoneState.h delete mode 100644 example/1d-linear-convection/eno3/cpp/01/burgers.json delete mode 100644 example/1d-linear-convection/eno3/cpp/01/burgers_ftcs.json delete mode 100644 example/1d-linear-convection/eno3/cpp/01/burgers_plot.py delete mode 100644 example/1d-linear-convection/eno3/cpp/01/cfd.json delete mode 100644 example/1d-linear-convection/eno3/cpp/01/heat.json delete mode 100644 example/1d-linear-convection/eno3/cpp/01/heat_plot.py delete mode 100644 example/1d-linear-convection/eno3/cpp/01/heaticp.json delete mode 100644 example/1d-linear-convection/eno3/cpp/01/hxmath.cpp delete mode 100644 example/1d-linear-convection/eno3/cpp/01/hxmath.h delete mode 100644 example/1d-linear-convection/eno3/cpp/01/linearconvection.json delete mode 100644 example/1d-linear-convection/eno3/cpp/01/linearconvection1d.cgns delete mode 100644 example/1d-linear-convection/eno3/cpp/01/linearconvectionBAK.json delete mode 100644 example/1d-linear-convection/eno3/cpp/01/main.cpp delete mode 100644 example/1d-linear-convection/eno3/cpp/01/plot.py delete mode 100644 example/1d-linear-convection/eno3/cpp/01/plotting2.jl delete mode 100644 example/1d-linear-convection/eno3/cpp/01/sod.json delete mode 100644 example/1d-linear-convection/eno3/cpp/01/sod_plot.py delete mode 100644 example/1d-linear-convection/eno3/cpp/01/sod_sort.py delete mode 100644 example/1d-linear-convection/eno3/cpp/01/sod_sort_on_xcoor.py delete mode 100644 example/1d-linear-convection/eno3/cpp/01/sod_theory.plt create mode 100644 example/1d-linear-convection/lax/python/01/lax.py create mode 100644 example/1d-linear-convection/lax/python/01a/lax.py create mode 100644 example/1d-linear-convection/lax/python/02/lax.py create mode 100644 example/1d-linear-convection/lax/python/02a/lax.py create mode 100644 example/1d-linear-convection/lax/python/02b/lax.py create mode 100644 example/1d-linear-convection/lax/python/03/lax.py create mode 100644 example/1d-linear-convection/lax/python/03a/lax.py create mode 100644 example/1d-linear-convection/lax/python/03b/lax.py create mode 100644 example/1d-linear-convection/lax/python/03c/lax.py create mode 100644 example/1d-linear-convection/lax/python/03d/lax.py create mode 100644 example/1d-linear-convection/rusanov/python/01/rusanov.py create mode 100644 example/1d-linear-convection/rusanov/python/02/rusanov.py create mode 100644 example/1d-linear-convection/rusanov/python/02a/rusanov.py create mode 100644 example/1d-linear-convection/rusanov/python/02b/rusanov.py create mode 100644 example/1d-linear-convection/rusanov/python/02c/rusanov.py create mode 100644 example/1d-linear-convection/rusanov/python/02d/rusanov.py create mode 100644 example/1d-linear-convection/rusanov/python/02e/rusanov.py create mode 100644 example/1d-linear-convection/weno3/python/01/weno.py delete mode 100644 example/1d-linear-convection/weno3/python/01/weno3.py create mode 100644 example/1d-linear-convection/weno3/python/01a/weno.py create mode 100644 example/1d-linear-convection/weno3/python/01b/weno.py create mode 100644 example/1d-linear-convection/weno3/python/01c/weno.py create mode 100644 example/1d-linear-convection/weno5/python/01/weno.py create mode 100644 example/weno-coef/eno/eno2_coef/01/testprj.py create mode 100644 example/weno-coef/eno/eno2_coef/01a/testprj.py create mode 100644 example/weno-coef/eno/eno2_coef/02/testprj.py create mode 100644 example/weno-coef/eno/eno2_coef/03/testprj.py create mode 100644 example/weno-coef/eno/eno2_coef/04/testprj.py diff --git a/example/1d-linear-convection/analytical_solution/01/theory.py b/example/1d-linear-convection/analytical_solution/01/theory.py new file mode 100644 index 00000000..74a2209a --- /dev/null +++ b/example/1d-linear-convection/analytical_solution/01/theory.py @@ -0,0 +1,54 @@ +import numpy as np + +def initial_condition(x): + """生成初始条件:在 [0.1, 0.3] 区间内为 1.0,其他位置为 0.0。 + + 参数: + x (np.ndarray): 空间坐标数组 + + 返回: + np.ndarray: 初始条件数组 + """ + return np.where((x >= 0.1) & (x <= 0.3), 1.0, 0.0) + +def analytical_solution(x, t, a, domain_length): + """计算理论解:初始波形以速度 a 平移,并应用周期边界条件。 + + 参数: + x (np.ndarray): 空间坐标数组 + t (float): 时间 + a (float): 波速 + domain_length (float): 区域的周期长度 L + + 返回: + np.ndarray: 时间 t 后的波形 + """ + # 计算平移后的坐标(无边界处理) + shifted_x = x - a * t + + # 应用周期边界条件,将坐标限制在 [0, domain_length) 范围内 + shifted_x_periodic = (shifted_x + domain_length) % domain_length + + # 返回平移后的初始条件 + return initial_condition(shifted_x_periodic) + + +import matplotlib.pyplot as plt + +# 定义参数 +L = 1.0 # 区域长度 +a = 1.0 # 波速 +t = 0.4 # 时间 +x = np.linspace(0, L, 1000) # 空间网格 + +# 计算初始条件和理论解 +u0 = initial_condition(x) +u_analytical = analytical_solution(x, t, a, L) + +# 可视化 +plt.plot(x, u0, label="Initial condition") +plt.plot(x, u_analytical, label=f"Analytical (t={t})") +plt.legend() +plt.xlabel("x") +plt.ylabel("u") +plt.show() \ No newline at end of file diff --git a/example/1d-linear-convection/analytical_solution/test_periodic_mapping/01/test_periodic_mapping.py b/example/1d-linear-convection/analytical_solution/test_periodic_mapping/01/test_periodic_mapping.py new file mode 100644 index 00000000..ac39fec2 --- /dev/null +++ b/example/1d-linear-convection/analytical_solution/test_periodic_mapping/01/test_periodic_mapping.py @@ -0,0 +1,18 @@ +import numpy as np + +def test_periodic_mapping(): + L = 1.0 + test_cases = [ + (-0.2, 0.8), + (1.3, 0.3), + (0.5, 0.5), + (-1.1, 0.9), + (2.7, 0.7), + ] + + for x, expected in test_cases: + result = (x + L) % L + assert np.isclose(result, expected), f"Failed for {x}: {result} vs {expected}" + print("所有测试通过!") + +test_periodic_mapping() \ No newline at end of file diff --git a/example/1d-linear-convection/eno/eno_coef/01/crj.py b/example/1d-linear-convection/eno/eno_coef/01/crj.py new file mode 100644 index 00000000..efbdeef1 --- /dev/null +++ b/example/1d-linear-convection/eno/eno_coef/01/crj.py @@ -0,0 +1,46 @@ +import numpy as np + +def calculate_eno_crj(r, j, k): + result = 0 + + # 外层求和:m 从 j+1 到 k + for m in range(j + 1, k + 1): + numerator = 0 + + # 内层求和:l 从 0 到 k,且 l ≠ m + for l in range(0, k + 1): + if l == m: + continue # 跳过 l = m 的情况 + + product = 1 + + # 内层连乘:q 从 0 到 k,且 q ≠ m, l + for q in range(0, k + 1): + if q == m or q == l: + continue # 跳过 q = m 或 q = l 的情况 + product *= (r - q + 1) + + numerator += product + + denominator = 1 + + # 分母连乘:l 从 0 到 k,且 l ≠ m + for l in range(0, k + 1): + if l == m: + continue # 跳过 l = m 的情况 + denominator *= (m - l) + + result += numerator / denominator + + return result + +for k in range(1,8): + print(f"=== k = {k} ===") + # 计算矩阵并存储到列表中 + eno_mat = np.zeros((k+1,k)) + for r in range(-1,k): + for j in range(k): + eno_mat[r+1, j] = calculate_eno_crj(r, j, k) + + print(f'{eno_mat=}') + print(f'{type(eno_mat)=}') \ No newline at end of file diff --git a/example/1d-linear-convection/eno/rusanov/calc_coef/rk1/eno1/01/eno.py b/example/1d-linear-convection/eno/rusanov/calc_coef/rk1/eno1/01/eno.py new file mode 100644 index 00000000..5f5da522 --- /dev/null +++ b/example/1d-linear-convection/eno/rusanov/calc_coef/rk1/eno1/01/eno.py @@ -0,0 +1,466 @@ +import numpy as np +import matplotlib.pyplot as plt + +# 初始条件 +def initial_condition(x): + u0 = np.zeros_like(x) + for i in range(len(x)): + if 0.5 <= x[i] <= 1.0: + u0[i] = 2.0 + else: + u0[i] = 1.0 + return u0 + +# 理论解 +def analytical_solution(x, t, a, L): + # 初始条件沿 x - at 平移 + x_shifted = x - a * t + return initial_condition((x_shifted + L) % L) # 周期边界条件 + +def residual(q, eno): + reconstruction(q, eno) + inviscid_flux(eno.up1_2m, eno.up1_2p, eno.flux, eno) + for i in range(eno.nx): + eno.res[i] = -(eno.flux[i + 1] - eno.flux[i]) / eno.mesh.dx + +def reconstruction(q, eno): + # Choose the stencil by ENO method + eno.dd[0, 0:eno.ntcell-1] = q[0:eno.ntcell-1] + + for m in range(1, eno.iorder): + for j in range(0, eno.ntcell-1): + eno.dd[m, j] = eno.dd[m-1, j+1] - eno.dd[m-1, j] + + for i in range(eno.nx + 1): + eno.il[i] = i - 1 + for m in range(1, eno.iorder): + if abs(eno.dd[m, eno.il[i]-1+eno.ishift]) <= abs(eno.dd[m, eno.il[i]+eno.ishift]): + eno.il[i] -= 1 + + for i in range(eno.nx + 1): + eno.ir[i] = i + for m in range(1, eno.iorder): + if abs(eno.dd[m, eno.ir[i]-1+eno.ishift]) <= abs(eno.dd[m, eno.ir[i]+eno.ishift]): + eno.ir[i] -= 1 + + # Reconstruction u(j+1/2) + for i in range(eno.nx + 1): + k1 = eno.il[i] + k2 = eno.ir[i] + l1 = i - k1 + l2 = i - k2 + eno.up1_2m[i] = 0 + eno.up1_2p[i] = 0 + for m in range(eno.iorder): + eno.up1_2m[i] += q[k1 + eno.ishift + m] * eno.coef[l1, m] + eno.up1_2p[i] += q[k2 + eno.ishift + m] * eno.coef[l2, m] + +fluxnames = [ + 'Rusanov', + 'Engquist-Osher', +] + +def inviscid_flux(up1_2m, up1_2p, flux, eno): + if eno.solver.iflux == 0: + rusanov_flux(up1_2m, up1_2p, flux, eno) + else: + engquist_osher_flux(up1_2m, up1_2p, flux, eno) + +def engquist_osher_flux(up1_2m, up1_2p, flux, eno): + for i in range(eno.nx + 1): + u_L = up1_2m[i] + u_R = up1_2p[i] + + cp = 0.5 * ( eno.solver.c + abs(eno.solver.c) ) + cm = 0.5 * ( eno.solver.c - abs(eno.solver.c) ) + + flux[i] = cp * u_L + cm * u_R + +def rusanov_flux(up1_2m, up1_2p, flux, eno): + for i in range(eno.nx + 1): + u_L = up1_2m[i] + u_R = up1_2p[i] + F_L = eno.solver.c * u_L # 左状态通量 + F_R = eno.solver.c * u_R # 右状态通量 + alpha = abs(eno.solver.c) # 最大波速 + flux[i] = 0.5 * (F_L + F_R) - 0.5 * alpha * (u_R - u_L) + + +def boundary(u, eno): + for i in range(-eno.ighost, 1): + u[eno.ist - 1 + i] = u[eno.ied + i] + for i in range(1, eno.ighost + 2): + u[eno.ied + i] = u[eno.ist - 1 + i] + +def update_oldfield(qn, q): + qn[:] = q[:] + +def calculate_eno_crj(r, j, k): + result = 0 + + # 外层求和:m 从 j+1 到 k + for m in range(j + 1, k + 1): + numerator = 0 + + # 内层求和:l 从 0 到 k,且 l ≠ m + for l in range(0, k + 1): + if l == m: + continue # 跳过 l = m 的情况 + + product = 1 + + # 内层连乘:q 从 0 到 k,且 q ≠ m, l + for q in range(0, k + 1): + if q == m or q == l: + continue # 跳过 q = m 或 q = l 的情况 + product *= (r - q + 1) + + numerator += product + + denominator = 1 + + # 分母连乘:l 从 0 到 k,且 l ≠ m + for l in range(0, k + 1): + if l == m: + continue # 跳过 l = m 的情况 + denominator *= (m - l) + + result += numerator / denominator + + return result + +def calc_eno_coef( iorder, coef ): + for r in range(-1,iorder): + for j in range(iorder): + coef[r+1, j] = calculate_eno_crj(r, j, iorder) + +def init_coef( iorder, coef ): + if iorder == 1: + coef[0] = [1.0] + coef[1] = [1.0] + elif iorder == 2: + coef[0] = [3.0/2.0, -1.0/2.0] + coef[1] = [1.0/2.0, 1.0/2.0] + coef[2] = [-1.0/2.0, 3.0/2.0] + elif iorder == 3: + coef[0] = [ 11.0/6.0, -7.0/6.0, 1.0/3.0 ] + coef[1] = [ 1.0/3.0, 5.0/6.0, -1.0/6.0 ] + coef[2] = [ -1.0/6.0, 5.0/6.0, 1.0/3.0 ] + coef[3] = [ 1.0/3.0, -7.0/6.0, 11.0/6.0 ] + elif iorder == 4: + coef[0] = [ 25.0/12.0, -23.0/12.0, 13.0/12.0, -1.0/4.0 ] + coef[1] = [ 1.0/4.0, 13.0/12.0, -5.0/12.0, 1.0/12.0 ] + coef[2] = [ -1.0/12.0, 7.0/12.0, 7.0/12.0, -1.0/12.0 ] + coef[3] = [ 1.0/12.0, -5.0/12.0, 13.0/12.0, 1.0/4.0 ] + coef[4] = [ -1.0/4.0, 13.0/12.0, -23.0/12.0, 25.0/12.0 ] + elif iorder == 5: + coef[0] = [ 137.0/60.0, -163.0/60.0, 137.0/60.0, -21.0/20.0, 1.0/5.0 ] + coef[1] = [ 1.0/5.0, 77.0/60.0, -43.0/60.0, 17.0/60.0, -1.0/20.0 ] + coef[2] = [ -1.0/20.0, 9.0/20.0, 47.0/60.0, -13.0/60.0, 1.0/30.0 ] + coef[3] = [ 1.0/30.0, -13.0/60.0, 47.0/60.0, 9.0/20.0, -1.0/20.0 ] + coef[4] = [ -1.0/20.0, 17.0/60.0, -43.0/60.0, 77.0/60.0, 1.0/5.0 ] + coef[5] = [ 1.0/5.0, -21.0/20.0, 137.0/60.0, -163.0/60.0, 137.0/60.0 ] + elif iorder == 6: + coef[0] = [ 49.0/20.0, -71.0/20.0, 79.0/20.0, -163.0/60.0, 31.0/30.0, -1.0/6.0 ] + coef[1] = [ 1.0/6.0, 29.0/20.0, -21.0/20.0, 37.0/60.0, -13.0/60.0, 1.0/30.0 ] + coef[2] = [ -1.0/30.0, 11.0/30.0, 19.0/20.0, -23.0/60.0, 7.0/60.0, -1.0/60.0 ] + coef[3] = [ 1.0/60.0, -2.0/15.0, 37.0/60.0, 37.0/60.0, -2.0/15.0, 1.0/60.0 ] + coef[4] = [ -1.0/60.0, 7.0/60.0, -23.0/60.0, 19.0/20.0, 11.0/30.0, -1.0/30.0 ] + coef[5] = [ 1.0/30.0, -13.0/60.0, 37.0/60.0, -21.0/20.0, 29.0/20.0, 1.0/6.0 ] + coef[6] = [ -1.0/6.0, 31.0/30.0, -163.0/60.0, 79.0/20.0, -71.0/20.0, 49.0/20.0 ] + elif iorder == 7: + coef[0] = [ 363.0/140.0, -617.0/140.0, 853.0/140.0, -2341.0/420.0, 667.0/210.0, -43.0/42.0, 1.0/7.0 ] + coef[1] = [ 1.0/7.0, 223.0/140.0, -197.0/140.0, 153.0/140.0, -241.0/420.0, 37.0/210.0, -1.0/42.0 ] + coef[2] = [ -1.0/42.0, 13.0/42.0, 153.0/140.0, -241.0/420.0, 109.0/420.0, -31.0/420.0, 1.0/105.0 ] + coef[3] = [ 1.0/105.0, -19.0/210.0, 107.0/210.0, 319.0/420.0, -101.0/420.0, 5.0/84.0, -1.0/140.0 ] + coef[4] = [ -1.0/140.0, 5.0/84.0, -101.0/420.0, 319.0/420.0, 107.0/210.0, -19.0/210.0, 1.0/105.0 ] + coef[5] = [ 1.0/105.0, -31.0/420.0, 109.0/420.0, -241.0/420.0, 153.0/140.0, 13.0/42.0, -1.0/42.0 ] + coef[6] = [ -1.0/42.0, 37.0/210.0, -241.0/420.0, 153.0/140.0, -197.0/140.0, 223.0/140.0, 1.0/7.0 ] + coef[7] = [ 1.0/7.0, -43.0/42.0, 667.0/210.0, -2341.0/420.0, 853.0/140.0, -617.0/140.0, 363.0/140.0 ] + +def init_field(eno): + for i in range(eno.ist, eno.ied + 1): + j = i - eno.ist + if 0.5 <= eno.mesh.xcc[j] <= 1.0: + eno.u[i] = 2.0 + else: + eno.u[i] = 1.0 + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def runge_kutta(eno): + rk = eno.solver.rk + if rk == 1: + runge_kutta_1(eno) + elif rk == 2: + runge_kutta_2(eno) + else: + runge_kutta_3(eno) + +def runge_kutta_1(eno): + dt = eno.solver.dt + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = eno.u[j] + dt * eno.res[i] + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def runge_kutta_2(eno): + dt = eno.solver.dt + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = eno.u[j] + dt * eno.res[i] + boundary(eno.u, eno) + + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = 0.5 * eno.un[j] + 0.5 * eno.u[j] + 0.5 * dt * eno.res[i] + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def runge_kutta_3(eno): + dt = eno.solver.dt + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = eno.u[j] + dt * eno.res[i] + boundary(eno.u, eno) + + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = 0.75 * eno.un[j] + 0.25 * eno.u[j] + 0.25 * dt * eno.res[i] + boundary(eno.u, eno) + + residual(eno.u, eno) + c1, c2, c3 = 1.0/3.0, 2.0/3.0, 2.0/3.0 + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = c1 * eno.un[j] + c2 * eno.u[j] + c3 * dt * eno.res[i] + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def get_ordinal_numbers(order): + if order == 1: + return 'st' + elif order == 2: + return 'nd' + elif order == 3: + return 'rd' + else: + return 'th' + +def visualize(eno): + with open('solution.plt', 'w') as f: + for i in range(eno.ist, eno.ied + 1): + j = i - eno.ist + f.write(f"{eno.xcc[j]:20.10e}{eno.u[i]:20.10e}\n") + + # 可视化 + u_numerical = np.copy(eno.u[eno.ist:eno.ied+1]) + print(f'u_numerical.size={u_numerical.size}') + print(f'eno.xcc.size={eno.xcc.size}') + #计算理论解 + u_analytical = analytical_solution(eno.mesh.xcc, eno.T, eno.c, eno.L) + print(f'u_analytical.size={u_analytical.size}') + plt.figure("OneFLOW-CFD Solver", figsize=(10, 6)) + plt.scatter(eno.xcc, u_numerical, facecolor="none", edgecolor="blue", s=20, linewidths=0.5, label=f'Numerical (Rusanov)') + plt.plot(eno.xcc, u_analytical, 'r--', label='Analytical') + plt.xlabel('x') + plt.ylabel('u') + ordinal1 = get_ordinal_numbers(eno.iorder) + ordinal2 = get_ordinal_numbers(eno.rk) + plt.title(f'1D Convection Equation at t = {eno.T:.3f} using {eno.iorder}{ordinal1}-order ENO and {eno.rk}{ordinal2}-order Runge-Kutta methods') + plt.legend() + plt.grid(True, color='gray', linestyle='--', linewidth=0.5, alpha=0.7) + plt.tight_layout() + plt.show() + +class Mesh: + def __init__(self): + self.nx = 40 + self.L = 2.0 + self.x = np.zeros(self.nx + 1) + self.xcc = np.zeros(self.nx) + self.init_mesh() + def init_mesh(self): + xstart = 0.0 + xend = self.L + self.dx = (xend - xstart) / self.nx + + for i in range(0, self.nx+1): + self.x[i] = xstart + i * self.dx + + for i in range(0, self.nx): + self.xcc[i] = 0.5 * (self.x[i] + self.x[i + 1]) + +class Solver: + def __init__(self): + self.iflux = 0 + self.rk = 1 + self.c = 1.0 + self.T = 0.625 + self.dt = .0025 + +class Eno: + def __init__(self, solver, mesh, iorder): + self.solver = solver + self.mesh = mesh + self.nx = mesh.nx + self.iorder = iorder + self.ighost = iorder + self.ishift = self.ighost + 1 + self.ist = 0 + self.ishift + self.ied = self.nx - 1 + self.ishift + self.ntcell = self.nx + 2 * self.ishift + self.isize = iorder * (iorder + 1) + + self.il = np.zeros(self.nx + 1, dtype=int) + self.ir = np.zeros(self.nx + 1, dtype=int) + self.coef = np.zeros((iorder + 1, iorder)) + self.dd = np.zeros((iorder, self.ntcell)) + self.up1_2m = np.zeros(self.nx + 1) + self.up1_2p = np.zeros(self.nx + 1) + self.flux = np.zeros(self.nx + 1) + self.res = np.zeros(self.nx) + + # Field module variables + self.u = np.zeros(self.ntcell) + self.un = np.zeros(self.ntcell) + + #self.dt = .0025 + +def plot_eno_OrderAnalysis(solver, xcc, u_list, u_analytical): + # 定义一个包含不同颜色、线形和标记的列表 + styles = [ + {'color': 'black', 'linestyle': '-', 'marker': 'o'}, + {'color': 'blue', 'linestyle': '--', 'marker': 's'}, + {'color': 'black', 'linestyle': '-', 'marker': '^'}, + {'color': 'blue', 'linestyle': '--', 'marker': 'v'}, + {'color': 'black', 'linestyle': '-', 'marker': '<'}, + {'color': 'blue', 'linestyle': '--', 'marker': '>'}, + {'color': 'black', 'linestyle': '-', 'marker': 'D'}, + ] + + n = len(u_list) + num_styles = len(styles) + ordinal = get_ordinal_numbers(solver.rk) + + plt.figure("OneFLOW-CFD Solver", figsize=(10, 6)) + plt.title(f'1D Convection Equation at t = {solver.T:.3f} using [1-7]th-order ENO and {solver.rk}{ordinal}-order Runge-Kutta methods') + for i in range(0, n): + lable = 'Numerical (Rusanov)ENO' + str(i+1) + style = styles[i % num_styles] + plt.plot(xcc, u_list[i], marker=style['marker'], markerfacecolor='none', linestyle=style['linestyle'], color=style['color'], \ + markersize=5, linewidth=0.5, alpha=1.0, label=f'{lable}') + plt.plot(xcc, u_analytical, 'r--', label='Analytical') + plt.xlabel('x') + plt.ylabel('u') + plt.legend() + plt.grid(True, color='gray', linestyle='--', linewidth=0.5, alpha=0.7) + plt.tight_layout() + plt.show() + +def plot_eno_TimestepAnalysis(solver, xcc, u_list, u_analytical, dt_list, iorder): + # 定义一个包含不同颜色、线形和标记的列表 + styles = [ + {'color': 'black', 'linestyle': '-', 'marker': 'o'}, + {'color': 'blue', 'linestyle': '--', 'marker': 's'}, + {'color': 'black', 'linestyle': '-', 'marker': '^'}, + {'color': 'blue', 'linestyle': '--', 'marker': 'v'}, + {'color': 'black', 'linestyle': '-', 'marker': '<'}, + {'color': 'blue', 'linestyle': '--', 'marker': '>'}, + {'color': 'black', 'linestyle': '-', 'marker': 'D'}, + {'color': 'blue', 'linestyle': '--', 'marker': 'o'}, + {'color': 'black', 'linestyle': '-', 'marker': 's'}, + {'color': 'blue', 'linestyle': '--', 'marker': '^'}, + {'color': 'black', 'linestyle': '-', 'marker': 'v'}, + {'color': 'blue', 'linestyle': '--', 'marker': '<'}, + {'color': 'black', 'linestyle': '-', 'marker': '>'}, + {'color': 'blue', 'linestyle': '--', 'marker': 'D'}, + ] + + n = len(u_list) + num_styles = len(styles) + + ordinalENO = get_ordinal_numbers(iorder) + ordinalRK = get_ordinal_numbers(solver.rk) + + plt.figure("OneFLOW-CFD Solver", figsize=(10, 6)) + plt.title(f'1D Convection Equation at t = {solver.T:.3f} using {iorder}{ordinalENO}-order ENO and {solver.rk}{ordinalRK}-order Runge-Kutta methods') + for i in range(0, n): + lable = 'Numerical (Rusanov)ENO' + str(iorder) + ' T='+str(dt_list[i]) + style = styles[i % num_styles] + plt.plot(xcc, u_list[i], marker=style['marker'], markerfacecolor='none', linestyle=style['linestyle'], color=style['color'], \ + markersize=5, linewidth=1.0, alpha=1.0, label=f'{lable}') + plt.plot(xcc, u_analytical, 'r--', label='Analytical') + plt.xlabel('x') + plt.ylabel('u') + plt.legend() + plt.grid(True, color='gray', linestyle='--', linewidth=0.5, alpha=0.7) + plt.tight_layout() + plt.show() + +def RunEno(solver, mesh, iorder): + eno = Eno(solver, mesh, iorder) + #init_coef(eno.iorder, eno.coef) + calc_eno_coef(eno.iorder, eno.coef) + init_field(eno) + + simu_time = solver.T + t = 0.0 + dt = solver.dt + while t < simu_time: + runge_kutta(eno) + if t + dt > simu_time: + dt = simu_time - t + t += dt + #print(f'T={t:.3f},runge_kutta{solver.rk},ENO{eno.iorder},{fluxnames[solver.iflux]} FLUX') + #visualize(eno) + return np.copy(eno.u[eno.ist:eno.ied+1]) + +def performEnoOrderAnalysis(): + iorder_max = 7 + mesh = Mesh() + solver = Solver() + #计算理论解 + u_analytical = analytical_solution(mesh.xcc, solver.T, solver.c, mesh.L) + + u_list = [] + for iorder in range(1, iorder_max+1): + u = RunEno(solver, mesh, iorder) + u_list.append(u) + + plot_eno_OrderAnalysis(solver, mesh.xcc, u_list, u_analytical) + +def performEnoTimestepAnalysis(): + mesh = Mesh() + solver = Solver() + #计算理论解 + u_analytical = analytical_solution(mesh.xcc, solver.T, solver.c, mesh.L) + + u_list = [] + dt_list = [] + solver.dt = 0.025/4 + #solver.dt = 0.025/16 + n = 12 + solver.rk = 3 + iorder = 7 + for i in range(0, n): + u = RunEno(solver, mesh, iorder) + u_list.append(u) + dt_list.append(solver.dt) + print(f'i={i+1},N={n},T={solver.T:.3f},dt={solver.dt},nt={int(solver.T/solver.dt)},runge_kutta{solver.rk},ENO{iorder},{fluxnames[solver.iflux]} FLUX') + solver.dt /= 2 + + plot_eno_TimestepAnalysis(solver, mesh.xcc, u_list, u_analytical, dt_list, iorder) + +def main(): + #performEnoOrderAnalysis() + performEnoTimestepAnalysis() + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/example/1d-linear-convection/eno/rusanov/rk1/eno1-10/01/eno.py b/example/1d-linear-convection/eno/rusanov/rk1/eno1-10/01/eno.py new file mode 100644 index 00000000..b3a27d65 --- /dev/null +++ b/example/1d-linear-convection/eno/rusanov/rk1/eno1-10/01/eno.py @@ -0,0 +1,476 @@ +import numpy as np +import matplotlib.pyplot as plt + +# 初始条件 +def initial_condition(x): + u0 = np.zeros_like(x) + for i in range(len(x)): + if 0.5 <= x[i] <= 1.0: + u0[i] = 2.0 + else: + u0[i] = 1.0 + return u0 + +# 理论解 +def analytical_solution(x, t, a, L): + # 初始条件沿 x - at 平移 + x_shifted = x - a * t + return initial_condition((x_shifted + L) % L) # 周期边界条件 + +def residual(q, eno): + reconstruction(q, eno) + inviscid_flux(eno.up1_2m, eno.up1_2p, eno.flux, eno) + for i in range(eno.nx): + eno.res[i] = -(eno.flux[i + 1] - eno.flux[i]) / eno.mesh.dx + +def reconstruction(q, eno): + # Choose the stencil by ENO method + eno.dd[0, 0:eno.ntcell-1] = q[0:eno.ntcell-1] + + for m in range(1, eno.iorder): + for j in range(0, eno.ntcell-1): + eno.dd[m, j] = eno.dd[m-1, j+1] - eno.dd[m-1, j] + + for i in range(eno.nx + 1): + eno.il[i] = i - 1 + for m in range(1, eno.iorder): + if abs(eno.dd[m, eno.il[i]-1+eno.ishift]) <= abs(eno.dd[m, eno.il[i]+eno.ishift]): + eno.il[i] -= 1 + + for i in range(eno.nx + 1): + eno.ir[i] = i + for m in range(1, eno.iorder): + if abs(eno.dd[m, eno.ir[i]-1+eno.ishift]) <= abs(eno.dd[m, eno.ir[i]+eno.ishift]): + eno.ir[i] -= 1 + + # Reconstruction u(j+1/2) + for i in range(eno.nx + 1): + k1 = eno.il[i] + k2 = eno.ir[i] + l1 = i - k1 + l2 = i - k2 + eno.up1_2m[i] = 0 + eno.up1_2p[i] = 0 + for m in range(eno.iorder): + eno.up1_2m[i] += q[k1 + eno.ishift + m] * eno.coef[l1, m] + eno.up1_2p[i] += q[k2 + eno.ishift + m] * eno.coef[l2, m] + +fluxnames = [ + 'Rusanov', + 'Engquist-Osher', +] + +def inviscid_flux(up1_2m, up1_2p, flux, eno): + if eno.solver.iflux == 0: + rusanov_flux(up1_2m, up1_2p, flux, eno) + else: + engquist_osher_flux(up1_2m, up1_2p, flux, eno) + +def engquist_osher_flux(up1_2m, up1_2p, flux, eno): + for i in range(eno.nx + 1): + u_L = up1_2m[i] + u_R = up1_2p[i] + + cp = 0.5 * ( eno.solver.c + abs(eno.solver.c) ) + cm = 0.5 * ( eno.solver.c - abs(eno.solver.c) ) + + flux[i] = cp * u_L + cm * u_R + +def rusanov_flux(up1_2m, up1_2p, flux, eno): + for i in range(eno.nx + 1): + u_L = up1_2m[i] + u_R = up1_2p[i] + F_L = eno.solver.c * u_L # 左状态通量 + F_R = eno.solver.c * u_R # 右状态通量 + alpha = abs(eno.solver.c) # 最大波速 + flux[i] = 0.5 * (F_L + F_R) - 0.5 * alpha * (u_R - u_L) + + +def boundary(u, eno): + for i in range(-eno.ighost, 1): + u[eno.ist - 1 + i] = u[eno.ied + i] + for i in range(1, eno.ighost + 2): + u[eno.ied + i] = u[eno.ist - 1 + i] + +def update_oldfield(qn, q): + qn[:] = q[:] + +def calculate_eno_crj(r, j, k): + result = 0 + + # 外层求和:m 从 j+1 到 k + for m in range(j + 1, k + 1): + numerator = 0 + + # 内层求和:l 从 0 到 k,且 l ≠ m + for l in range(0, k + 1): + if l == m: + continue # 跳过 l = m 的情况 + + product = 1 + + # 内层连乘:q 从 0 到 k,且 q ≠ m, l + for q in range(0, k + 1): + if q == m or q == l: + continue # 跳过 q = m 或 q = l 的情况 + product *= (r - q + 1) + + numerator += product + + denominator = 1 + + # 分母连乘:l 从 0 到 k,且 l ≠ m + for l in range(0, k + 1): + if l == m: + continue # 跳过 l = m 的情况 + denominator *= (m - l) + + result += numerator / denominator + + return result + +def calc_eno_coef( iorder, coef ): + for r in range(-1,iorder): + for j in range(iorder): + coef[r+1, j] = calculate_eno_crj(r, j, iorder) + +def init_coef( iorder, coef ): + if iorder == 1: + coef[0] = [1.0] + coef[1] = [1.0] + elif iorder == 2: + coef[0] = [3.0/2.0, -1.0/2.0] + coef[1] = [1.0/2.0, 1.0/2.0] + coef[2] = [-1.0/2.0, 3.0/2.0] + elif iorder == 3: + coef[0] = [ 11.0/6.0, -7.0/6.0, 1.0/3.0 ] + coef[1] = [ 1.0/3.0, 5.0/6.0, -1.0/6.0 ] + coef[2] = [ -1.0/6.0, 5.0/6.0, 1.0/3.0 ] + coef[3] = [ 1.0/3.0, -7.0/6.0, 11.0/6.0 ] + elif iorder == 4: + coef[0] = [ 25.0/12.0, -23.0/12.0, 13.0/12.0, -1.0/4.0 ] + coef[1] = [ 1.0/4.0, 13.0/12.0, -5.0/12.0, 1.0/12.0 ] + coef[2] = [ -1.0/12.0, 7.0/12.0, 7.0/12.0, -1.0/12.0 ] + coef[3] = [ 1.0/12.0, -5.0/12.0, 13.0/12.0, 1.0/4.0 ] + coef[4] = [ -1.0/4.0, 13.0/12.0, -23.0/12.0, 25.0/12.0 ] + elif iorder == 5: + coef[0] = [ 137.0/60.0, -163.0/60.0, 137.0/60.0, -21.0/20.0, 1.0/5.0 ] + coef[1] = [ 1.0/5.0, 77.0/60.0, -43.0/60.0, 17.0/60.0, -1.0/20.0 ] + coef[2] = [ -1.0/20.0, 9.0/20.0, 47.0/60.0, -13.0/60.0, 1.0/30.0 ] + coef[3] = [ 1.0/30.0, -13.0/60.0, 47.0/60.0, 9.0/20.0, -1.0/20.0 ] + coef[4] = [ -1.0/20.0, 17.0/60.0, -43.0/60.0, 77.0/60.0, 1.0/5.0 ] + coef[5] = [ 1.0/5.0, -21.0/20.0, 137.0/60.0, -163.0/60.0, 137.0/60.0 ] + elif iorder == 6: + coef[0] = [ 49.0/20.0, -71.0/20.0, 79.0/20.0, -163.0/60.0, 31.0/30.0, -1.0/6.0 ] + coef[1] = [ 1.0/6.0, 29.0/20.0, -21.0/20.0, 37.0/60.0, -13.0/60.0, 1.0/30.0 ] + coef[2] = [ -1.0/30.0, 11.0/30.0, 19.0/20.0, -23.0/60.0, 7.0/60.0, -1.0/60.0 ] + coef[3] = [ 1.0/60.0, -2.0/15.0, 37.0/60.0, 37.0/60.0, -2.0/15.0, 1.0/60.0 ] + coef[4] = [ -1.0/60.0, 7.0/60.0, -23.0/60.0, 19.0/20.0, 11.0/30.0, -1.0/30.0 ] + coef[5] = [ 1.0/30.0, -13.0/60.0, 37.0/60.0, -21.0/20.0, 29.0/20.0, 1.0/6.0 ] + coef[6] = [ -1.0/6.0, 31.0/30.0, -163.0/60.0, 79.0/20.0, -71.0/20.0, 49.0/20.0 ] + elif iorder == 7: + coef[0] = [ 363.0/140.0, -617.0/140.0, 853.0/140.0, -2341.0/420.0, 667.0/210.0, -43.0/42.0, 1.0/7.0 ] + coef[1] = [ 1.0/7.0, 223.0/140.0, -197.0/140.0, 153.0/140.0, -241.0/420.0, 37.0/210.0, -1.0/42.0 ] + coef[2] = [ -1.0/42.0, 13.0/42.0, 153.0/140.0, -241.0/420.0, 109.0/420.0, -31.0/420.0, 1.0/105.0 ] + coef[3] = [ 1.0/105.0, -19.0/210.0, 107.0/210.0, 319.0/420.0, -101.0/420.0, 5.0/84.0, -1.0/140.0 ] + coef[4] = [ -1.0/140.0, 5.0/84.0, -101.0/420.0, 319.0/420.0, 107.0/210.0, -19.0/210.0, 1.0/105.0 ] + coef[5] = [ 1.0/105.0, -31.0/420.0, 109.0/420.0, -241.0/420.0, 153.0/140.0, 13.0/42.0, -1.0/42.0 ] + coef[6] = [ -1.0/42.0, 37.0/210.0, -241.0/420.0, 153.0/140.0, -197.0/140.0, 223.0/140.0, 1.0/7.0 ] + coef[7] = [ 1.0/7.0, -43.0/42.0, 667.0/210.0, -2341.0/420.0, 853.0/140.0, -617.0/140.0, 363.0/140.0 ] + +def init_field(eno): + for i in range(eno.ist, eno.ied + 1): + j = i - eno.ist + if 0.5 <= eno.mesh.xcc[j] <= 1.0: + eno.u[i] = 2.0 + else: + eno.u[i] = 1.0 + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def runge_kutta(eno): + rk = eno.solver.rk + if rk == 1: + runge_kutta_1(eno) + elif rk == 2: + runge_kutta_2(eno) + else: + runge_kutta_3(eno) + +def runge_kutta_1(eno): + dt = eno.solver.dt + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = eno.u[j] + dt * eno.res[i] + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def runge_kutta_2(eno): + dt = eno.solver.dt + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = eno.u[j] + dt * eno.res[i] + boundary(eno.u, eno) + + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = 0.5 * eno.un[j] + 0.5 * eno.u[j] + 0.5 * dt * eno.res[i] + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def runge_kutta_3(eno): + dt = eno.solver.dt + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = eno.u[j] + dt * eno.res[i] + boundary(eno.u, eno) + + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = 0.75 * eno.un[j] + 0.25 * eno.u[j] + 0.25 * dt * eno.res[i] + boundary(eno.u, eno) + + residual(eno.u, eno) + c1, c2, c3 = 1.0/3.0, 2.0/3.0, 2.0/3.0 + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = c1 * eno.un[j] + c2 * eno.u[j] + c3 * dt * eno.res[i] + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def get_ordinal_numbers(order): + if order == 1: + return 'st' + elif order == 2: + return 'nd' + elif order == 3: + return 'rd' + else: + return 'th' + +def visualize(eno): + with open('solution.plt', 'w') as f: + for i in range(eno.ist, eno.ied + 1): + j = i - eno.ist + f.write(f"{eno.xcc[j]:20.10e}{eno.u[i]:20.10e}\n") + + # 可视化 + u_numerical = np.copy(eno.u[eno.ist:eno.ied+1]) + print(f'u_numerical.size={u_numerical.size}') + print(f'eno.xcc.size={eno.xcc.size}') + #计算理论解 + u_analytical = analytical_solution(eno.mesh.xcc, eno.T, eno.c, eno.L) + print(f'u_analytical.size={u_analytical.size}') + plt.figure("OneFLOW-CFD Solver", figsize=(10, 6)) + plt.scatter(eno.xcc, u_numerical, facecolor="none", edgecolor="blue", s=20, linewidths=0.5, label=f'Numerical (Rusanov)') + plt.plot(eno.xcc, u_analytical, 'r--', label='Analytical') + plt.xlabel('x') + plt.ylabel('u') + ordinal1 = get_ordinal_numbers(eno.iorder) + ordinal2 = get_ordinal_numbers(eno.rk) + plt.title(f'1D Convection Equation at t = {eno.T:.3f} using {eno.iorder}{ordinal1}-order ENO and {eno.rk}{ordinal2}-order Runge-Kutta methods') + plt.legend() + plt.grid(True, color='gray', linestyle='--', linewidth=0.5, alpha=0.7) + plt.tight_layout() + plt.show() + +class Mesh: + def __init__(self): + #self.nx = 40 + self.nx = 200 + self.L = 2.0 + self.x = np.zeros(self.nx + 1) + self.xcc = np.zeros(self.nx) + self.init_mesh() + def init_mesh(self): + xstart = 0.0 + xend = self.L + self.dx = (xend - xstart) / self.nx + + for i in range(0, self.nx+1): + self.x[i] = xstart + i * self.dx + + for i in range(0, self.nx): + self.xcc[i] = 0.5 * (self.x[i] + self.x[i + 1]) + +class Solver: + def __init__(self): + self.iflux = 0 + self.rk = 1 + self.c = 1.0 + self.T = 0.625 + self.dt = .0025 + +class Eno: + def __init__(self, solver, mesh, iorder): + self.solver = solver + self.mesh = mesh + self.nx = mesh.nx + self.iorder = iorder + self.ighost = iorder + self.ishift = self.ighost + 1 + self.ist = 0 + self.ishift + self.ied = self.nx - 1 + self.ishift + self.ntcell = self.nx + 2 * self.ishift + self.isize = iorder * (iorder + 1) + + self.il = np.zeros(self.nx + 1, dtype=int) + self.ir = np.zeros(self.nx + 1, dtype=int) + self.coef = np.zeros((iorder + 1, iorder)) + self.dd = np.zeros((iorder, self.ntcell)) + self.up1_2m = np.zeros(self.nx + 1) + self.up1_2p = np.zeros(self.nx + 1) + self.flux = np.zeros(self.nx + 1) + self.res = np.zeros(self.nx) + + # Field module variables + self.u = np.zeros(self.ntcell) + self.un = np.zeros(self.ntcell) + +def plot_eno_OrderAnalysis(solver, xcc, u_list, u_analytical): + # 定义一个包含不同颜色、线形和标记的列表 + styles = [ + {'color': 'black', 'linestyle': '-', 'marker': 'o'}, + {'color': 'blue', 'linestyle': '--', 'marker': 's'}, + {'color': 'black', 'linestyle': '-', 'marker': '^'}, + {'color': 'blue', 'linestyle': '--', 'marker': 'v'}, + {'color': 'black', 'linestyle': '-', 'marker': '<'}, + {'color': 'blue', 'linestyle': '--', 'marker': '>'}, + {'color': 'black', 'linestyle': '-', 'marker': 'D'}, + {'color': 'blue', 'linestyle': '--', 'marker': 'o'}, + {'color': 'black', 'linestyle': '-', 'marker': 's'}, + {'color': 'blue', 'linestyle': '--', 'marker': '^'}, + {'color': 'black', 'linestyle': '-', 'marker': 'v'}, + {'color': 'blue', 'linestyle': '--', 'marker': '<'}, + {'color': 'black', 'linestyle': '-', 'marker': '>'}, + {'color': 'blue', 'linestyle': '--', 'marker': 'D'}, + ] + + n = len(u_list) + num_styles = len(styles) + ordinal = get_ordinal_numbers(solver.rk) + + plt.figure("OneFLOW-CFD Solver", figsize=(10, 6)) + plt.title(f'1D Convection Equation at t = {solver.T:.3f} using [1-{n}]th-order ENO and {solver.rk}{ordinal}-order Runge-Kutta methods') + for i in range(0, n): + lable = 'Numerical (Rusanov)ENO' + str(i+1) + style = styles[i % num_styles] + plt.plot(xcc, u_list[i], marker=style['marker'], markerfacecolor='none', linestyle=style['linestyle'], color=style['color'], \ + markersize=5, linewidth=0.5, alpha=1.0, label=f'{lable}') + plt.plot(xcc, u_analytical, 'r--', linewidth=0.5, markersize=5, marker='o', markerfacecolor='none',label='Analytical') + plt.xlabel('x') + plt.ylabel('u') + plt.legend() + plt.grid(True, color='gray', linestyle='--', linewidth=0.5, alpha=0.7) + plt.tight_layout() + plt.show() + +def plot_eno_TimestepAnalysis(solver, xcc, u_list, u_analytical, dt_list, iorder): + # 定义一个包含不同颜色、线形和标记的列表 + styles = [ + {'color': 'black', 'linestyle': '-', 'marker': 'o'}, + {'color': 'blue', 'linestyle': '--', 'marker': 's'}, + {'color': 'black', 'linestyle': '-', 'marker': '^'}, + {'color': 'blue', 'linestyle': '--', 'marker': 'v'}, + {'color': 'black', 'linestyle': '-', 'marker': '<'}, + {'color': 'blue', 'linestyle': '--', 'marker': '>'}, + {'color': 'black', 'linestyle': '-', 'marker': 'D'}, + {'color': 'blue', 'linestyle': '--', 'marker': 'o'}, + {'color': 'black', 'linestyle': '-', 'marker': 's'}, + {'color': 'blue', 'linestyle': '--', 'marker': '^'}, + {'color': 'black', 'linestyle': '-', 'marker': 'v'}, + {'color': 'blue', 'linestyle': '--', 'marker': '<'}, + {'color': 'black', 'linestyle': '-', 'marker': '>'}, + {'color': 'blue', 'linestyle': '--', 'marker': 'D'}, + ] + + n = len(u_list) + num_styles = len(styles) + + ordinalENO = get_ordinal_numbers(iorder) + ordinalRK = get_ordinal_numbers(solver.rk) + + plt.figure("OneFLOW-CFD Solver", figsize=(10, 6)) + plt.title(f'1D Convection Equation at t = {solver.T:.3f} using {iorder}{ordinalENO}-order ENO and {solver.rk}{ordinalRK}-order Runge-Kutta methods') + for i in range(0, n): + lable = 'Numerical (Rusanov)ENO' + str(iorder) + ' T='+str(dt_list[i]) + style = styles[i % num_styles] + plt.plot(xcc, u_list[i], marker=style['marker'], markerfacecolor='none', linestyle=style['linestyle'], color=style['color'], \ + markersize=5, linewidth=1.0, alpha=1.0, label=f'{lable}') + plt.plot(xcc, u_analytical, 'r--', label='Analytical') + plt.xlabel('x') + plt.ylabel('u') + plt.legend() + plt.grid(True, color='gray', linestyle='--', linewidth=0.5, alpha=0.7) + plt.tight_layout() + plt.show() + +def RunEno(solver, mesh, iorder): + eno = Eno(solver, mesh, iorder) + #init_coef(eno.iorder, eno.coef) + calc_eno_coef(eno.iorder, eno.coef) + init_field(eno) + + simu_time = solver.T + t = 0.0 + dt = solver.dt + while t < simu_time: + runge_kutta(eno) + if t + dt > simu_time: + dt = simu_time - t + t += dt + #print(f'T={t:.3f},runge_kutta{solver.rk},ENO{eno.iorder},{fluxnames[solver.iflux]} FLUX') + #visualize(eno) + return np.copy(eno.u[eno.ist:eno.ied+1]) + +def performEnoOrderAnalysis(iorder_max): + mesh = Mesh() + solver = Solver() + #计算理论解 + u_analytical = analytical_solution(mesh.xcc, solver.T, solver.c, mesh.L) + + u_list = [] + solver.rk = 3 + #solver.dt = 0.025/64 + solver.dt = 0.025/(np.power(2, 9)) + for iorder in range(1, iorder_max+1): + u = RunEno(solver, mesh, iorder) + print(f'iorder={iorder},NOrder={iorder_max},T={solver.T:.3f},dt={solver.dt},dx={mesh.dx},nt={int(solver.T/solver.dt)},runge_kutta{solver.rk},ENO{iorder},{fluxnames[solver.iflux]} FLUX') + u_list.append(u) + + plot_eno_OrderAnalysis(solver, mesh.xcc, u_list, u_analytical) + +def performEnoTimestepAnalysis(): + mesh = Mesh() + solver = Solver() + #计算理论解 + u_analytical = analytical_solution(mesh.xcc, solver.T, solver.c, mesh.L) + + u_list = [] + dt_list = [] + solver.dt = 0.025/4 + #solver.dt = 0.025/64 + n = 12 + solver.rk = 3 + iorder = 7 + for i in range(0, n): + u = RunEno(solver, mesh, iorder) + u_list.append(u) + dt_list.append(solver.dt) + print(f'i={i+1},N={n},T={solver.T:.3f},dt={solver.dt},nt={int(solver.T/solver.dt)},runge_kutta{solver.rk},ENO{iorder},{fluxnames[solver.iflux]} FLUX') + solver.dt /= 2 + + plot_eno_TimestepAnalysis(solver, mesh.xcc, u_list, u_analytical, dt_list, iorder) + +def main(): + #performEnoOrderAnalysis(20) + performEnoOrderAnalysis(12) + #performEnoTimestepAnalysis() + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/example/1d-linear-convection/eno/rusanov/rk1/eno1-7/01/eno.py b/example/1d-linear-convection/eno/rusanov/rk1/eno1-7/01/eno.py new file mode 100644 index 00000000..cd64e7ad --- /dev/null +++ b/example/1d-linear-convection/eno/rusanov/rk1/eno1-7/01/eno.py @@ -0,0 +1,360 @@ +import numpy as np +import matplotlib.pyplot as plt + +# 初始条件 +def initial_condition(x): + u0 = np.zeros_like(x) + for i in range(len(x)): + if 0.5 <= x[i] <= 1.0: + u0[i] = 2.0 + else: + u0[i] = 1.0 + return u0 + +# 理论解 +def analytical_solution(x, t, a, L): + # 初始条件沿 x - at 平移 + x_shifted = x - a * t + return initial_condition((x_shifted + L) % L) # 周期边界条件 + +def residual(q, eno): + reconstruction(q, eno) + inviscid_flux(eno.up1_2m, eno.up1_2p, eno.flux, eno) + for i in range(eno.nx): + eno.res[i] = -(eno.flux[i + 1] - eno.flux[i]) / eno.mesh.dx + +def reconstruction(q, eno): + # Choose the stencil by ENO method + eno.dd[0, 0:eno.ntcell-1] = q[0:eno.ntcell-1] + + for m in range(1, eno.iorder): + for j in range(0, eno.ntcell-1): + eno.dd[m, j] = eno.dd[m-1, j+1] - eno.dd[m-1, j] + + for i in range(eno.nx + 1): + eno.il[i] = i - 1 + for m in range(1, eno.iorder): + if abs(eno.dd[m, eno.il[i]-1+eno.ishift]) <= abs(eno.dd[m, eno.il[i]+eno.ishift]): + eno.il[i] -= 1 + + for i in range(eno.nx + 1): + eno.ir[i] = i + for m in range(1, eno.iorder): + if abs(eno.dd[m, eno.ir[i]-1+eno.ishift]) <= abs(eno.dd[m, eno.ir[i]+eno.ishift]): + eno.ir[i] -= 1 + + # Reconstruction u(j+1/2) + for i in range(eno.nx + 1): + k1 = eno.il[i] + k2 = eno.ir[i] + l1 = i - k1 + l2 = i - k2 + eno.up1_2m[i] = 0 + eno.up1_2p[i] = 0 + for m in range(eno.iorder): + eno.up1_2m[i] += q[k1 + eno.ishift + m] * eno.coef[l1, m] + eno.up1_2p[i] += q[k2 + eno.ishift + m] * eno.coef[l2, m] + +fluxnames = [ + 'Rusanov', + 'Engquist-Osher', +] + +def inviscid_flux(up1_2m, up1_2p, flux, eno): + if eno.solver.iflux == 0: + rusanov_flux(up1_2m, up1_2p, flux, eno) + else: + engquist_osher_flux(up1_2m, up1_2p, flux, eno) + +def engquist_osher_flux(up1_2m, up1_2p, flux, eno): + for i in range(eno.nx + 1): + u_L = up1_2m[i] + u_R = up1_2p[i] + + cp = 0.5 * ( eno.solver.c + abs(eno.solver.c) ) + cm = 0.5 * ( eno.solver.c - abs(eno.solver.c) ) + + flux[i] = cp * u_L + cm * u_R + +def rusanov_flux(up1_2m, up1_2p, flux, eno): + for i in range(eno.nx + 1): + u_L = up1_2m[i] + u_R = up1_2p[i] + F_L = eno.solver.c * u_L # 左状态通量 + F_R = eno.solver.c * u_R # 右状态通量 + alpha = abs(eno.solver.c) # 最大波速 + flux[i] = 0.5 * (F_L + F_R) - 0.5 * alpha * (u_R - u_L) + + +def boundary(u, eno): + for i in range(-eno.ighost, 1): + u[eno.ist - 1 + i] = u[eno.ied + i] + for i in range(1, eno.ighost + 2): + u[eno.ied + i] = u[eno.ist - 1 + i] + +def update_oldfield(qn, q): + qn[:] = q[:] + +def init_coef( iorder, coef ): + if iorder == 1: + coef[0] = [1.0] + coef[1] = [1.0] + elif iorder == 2: + coef[0] = [3.0/2.0, -1.0/2.0] + coef[1] = [1.0/2.0, 1.0/2.0] + coef[2] = [-1.0/2.0, 3.0/2.0] + elif iorder == 3: + coef[0] = [ 11.0/6.0, -7.0/6.0, 1.0/3.0 ] + coef[1] = [ 1.0/3.0, 5.0/6.0, -1.0/6.0 ] + coef[2] = [ -1.0/6.0, 5.0/6.0, 1.0/3.0 ] + coef[3] = [ 1.0/3.0, -7.0/6.0, 11.0/6.0 ] + elif iorder == 4: + coef[0] = [ 25.0/12.0, -23.0/12.0, 13.0/12.0, -1.0/4.0 ] + coef[1] = [ 1.0/4.0, 13.0/12.0, -5.0/12.0, 1.0/12.0 ] + coef[2] = [ -1.0/12.0, 7.0/12.0, 7.0/12.0, -1.0/12.0 ] + coef[3] = [ 1.0/12.0, -5.0/12.0, 13.0/12.0, 1.0/4.0 ] + coef[4] = [ -1.0/4.0, 13.0/12.0, -23.0/12.0, 25.0/12.0 ] + elif iorder == 5: + coef[0] = [ 137.0/60.0, -163.0/60.0, 137.0/60.0, -21.0/20.0, 1.0/5.0 ] + coef[1] = [ 1.0/5.0, 77.0/60.0, -43.0/60.0, 17.0/60.0, -1.0/20.0 ] + coef[2] = [ -1.0/20.0, 9.0/20.0, 47.0/60.0, -13.0/60.0, 1.0/30.0 ] + coef[3] = [ 1.0/30.0, -13.0/60.0, 47.0/60.0, 9.0/20.0, -1.0/20.0 ] + coef[4] = [ -1.0/20.0, 17.0/60.0, -43.0/60.0, 77.0/60.0, 1.0/5.0 ] + coef[5] = [ 1.0/5.0, -21.0/20.0, 137.0/60.0, -163.0/60.0, 137.0/60.0 ] + elif iorder == 6: + coef[0] = [ 49.0/20.0, -71.0/20.0, 79.0/20.0, -163.0/60.0, 31.0/30.0, -1.0/6.0 ] + coef[1] = [ 1.0/6.0, 29.0/20.0, -21.0/20.0, 37.0/60.0, -13.0/60.0, 1.0/30.0 ] + coef[2] = [ -1.0/30.0, 11.0/30.0, 19.0/20.0, -23.0/60.0, 7.0/60.0, -1.0/60.0 ] + coef[3] = [ 1.0/60.0, -2.0/15.0, 37.0/60.0, 37.0/60.0, -2.0/15.0, 1.0/60.0 ] + coef[4] = [ -1.0/60.0, 7.0/60.0, -23.0/60.0, 19.0/20.0, 11.0/30.0, -1.0/30.0 ] + coef[5] = [ 1.0/30.0, -13.0/60.0, 37.0/60.0, -21.0/20.0, 29.0/20.0, 1.0/6.0 ] + coef[6] = [ -1.0/6.0, 31.0/30.0, -163.0/60.0, 79.0/20.0, -71.0/20.0, 49.0/20.0 ] + elif iorder == 7: + coef[0] = [ 363.0/140.0, -617.0/140.0, 853.0/140.0, -2341.0/420.0, 667.0/210.0, -43.0/42.0, 1.0/7.0 ] + coef[1] = [ 1.0/7.0, 223.0/140.0, -197.0/140.0, 153.0/140.0, -241.0/420.0, 37.0/210.0, -1.0/42.0 ] + coef[2] = [ -1.0/42.0, 13.0/42.0, 153.0/140.0, -241.0/420.0, 109.0/420.0, -31.0/420.0, 1.0/105.0 ] + coef[3] = [ 1.0/105.0, -19.0/210.0, 107.0/210.0, 319.0/420.0, -101.0/420.0, 5.0/84.0, -1.0/140.0 ] + coef[4] = [ -1.0/140.0, 5.0/84.0, -101.0/420.0, 319.0/420.0, 107.0/210.0, -19.0/210.0, 1.0/105.0 ] + coef[5] = [ 1.0/105.0, -31.0/420.0, 109.0/420.0, -241.0/420.0, 153.0/140.0, 13.0/42.0, -1.0/42.0 ] + coef[6] = [ -1.0/42.0, 37.0/210.0, -241.0/420.0, 153.0/140.0, -197.0/140.0, 223.0/140.0, 1.0/7.0 ] + coef[7] = [ 1.0/7.0, -43.0/42.0, 667.0/210.0, -2341.0/420.0, 853.0/140.0, -617.0/140.0, 363.0/140.0 ] + +def init_field(eno): + for i in range(eno.ist, eno.ied + 1): + j = i - eno.ist + if 0.5 <= eno.mesh.xcc[j] <= 1.0: + eno.u[i] = 2.0 + else: + eno.u[i] = 1.0 + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def runge_kutta(eno): + rk = eno.solver.rk + if rk == 1: + runge_kutta_1(eno) + elif rk == 2: + runge_kutta_2(eno) + else: + runge_kutta_3(eno) + +def runge_kutta_1(eno): + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = eno.u[j] + eno.dt * eno.res[i] + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def runge_kutta_2(eno): + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = eno.u[j] + eno.dt * eno.res[i] + boundary(eno.u, eno) + + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = 0.5 * eno.un[j] + 0.5 * eno.u[j] + 0.5 * eno.dt * eno.res[i] + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def runge_kutta_3(eno): + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = eno.u[j] + eno.dt * eno.res[i] + boundary(eno.u, eno) + + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = 0.75 * eno.un[j] + 0.25 * eno.u[j] + 0.25 * eno.dt * eno.res[i] + boundary(eno.u, eno) + + residual(eno.u, eno) + c1, c2, c3 = 1.0/3.0, 2.0/3.0, 2.0/3.0 + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = c1 * eno.un[j] + c2 * eno.u[j] + c3 * eno.dt * eno.res[i] + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def get_ordinal_numbers(order): + if order == 1: + return 'st' + elif order == 2: + return 'nd' + elif order == 3: + return 'rd' + else: + return 'th' + +def visualize(eno): + with open('solution.plt', 'w') as f: + for i in range(eno.ist, eno.ied + 1): + j = i - eno.ist + f.write(f"{eno.xcc[j]:20.10e}{eno.u[i]:20.10e}\n") + + # 可视化 + u_numerical = np.copy(eno.u[eno.ist:eno.ied+1]) + print(f'u_numerical.size={u_numerical.size}') + print(f'eno.xcc.size={eno.xcc.size}') + #计算理论解 + u_analytical = analytical_solution(eno.mesh.xcc, eno.T, eno.c, eno.L) + print(f'u_analytical.size={u_analytical.size}') + plt.figure("OneFLOW-CFD Solver", figsize=(10, 6)) + plt.scatter(eno.xcc, u_numerical, facecolor="none", edgecolor="blue", s=20, linewidths=0.5, label=f'Numerical (Rusanov)') + plt.plot(eno.xcc, u_analytical, 'r--', label='Analytical') + plt.xlabel('x') + plt.ylabel('u') + ordinal1 = get_ordinal_numbers(eno.iorder) + ordinal2 = get_ordinal_numbers(eno.rk) + plt.title(f'1D Convection Equation at t = {eno.T:.3f} using {eno.iorder}{ordinal1}-order ENO and {eno.rk}{ordinal2}-order Runge-Kutta methods') + plt.legend() + plt.grid(True, color='gray', linestyle='--', linewidth=0.5, alpha=0.7) + plt.tight_layout() + plt.show() + +class Mesh: + def __init__(self): + self.nx = 40 + self.L = 2.0 + self.x = np.zeros(self.nx + 1) + self.xcc = np.zeros(self.nx) + self.init_mesh() + def init_mesh(self): + xstart = 0.0 + xend = self.L + self.dx = (xend - xstart) / self.nx + + for i in range(0, self.nx+1): + self.x[i] = xstart + i * self.dx + + for i in range(0, self.nx): + self.xcc[i] = 0.5 * (self.x[i] + self.x[i + 1]) + +class Solver: + def __init__(self): + self.iflux = 0 + self.rk = 1 + self.c = 1.0 + self.T = 0.625 + +class Eno: + def __init__(self, solver, mesh, iorder): + self.solver = solver + self.mesh = mesh + self.nx = mesh.nx + self.iorder = iorder + self.ighost = iorder + self.ishift = self.ighost + 1 + self.ist = 0 + self.ishift + self.ied = self.nx - 1 + self.ishift + self.ntcell = self.nx + 2 * self.ishift + self.isize = iorder * (iorder + 1) + + self.il = np.zeros(self.nx + 1, dtype=int) + self.ir = np.zeros(self.nx + 1, dtype=int) + self.coef = np.zeros((iorder + 1, iorder)) + self.dd = np.zeros((iorder, self.ntcell)) + self.up1_2m = np.zeros(self.nx + 1) + self.up1_2p = np.zeros(self.nx + 1) + self.flux = np.zeros(self.nx + 1) + self.res = np.zeros(self.nx) + + # Field module variables + self.u = np.zeros(self.ntcell) + self.un = np.zeros(self.ntcell) + + self.dt = .0025 + +def plot_eno_field(solver, xcc, u_list, u_analytical): + # 定义一个包含不同颜色、线形和标记的列表 + styles = [ + {'color': 'black', 'linestyle': '-', 'marker': 'o'}, + {'color': 'blue', 'linestyle': '--', 'marker': 's'}, + {'color': 'black', 'linestyle': '-', 'marker': '^'}, + {'color': 'blue', 'linestyle': '--', 'marker': 'v'}, + {'color': 'black', 'linestyle': '-', 'marker': '<'}, + {'color': 'blue', 'linestyle': '--', 'marker': '>'}, + {'color': 'black', 'linestyle': '-', 'marker': 'D'}, + ] + + n = len(u_list) + num_styles = len(styles) + ordinal = get_ordinal_numbers(solver.rk) + + plt.figure("OneFLOW-CFD Solver", figsize=(10, 6)) + plt.title(f'1D Convection Equation at t = {solver.T:.3f} using [1-7]th-order ENO and {solver.rk}{ordinal}-order Runge-Kutta methods') + for i in range(0, n): + lable = 'Numerical (Rusanov)ENO' + str(i+1) + style = styles[i % num_styles] + plt.plot(xcc, u_list[i], marker=style['marker'], markerfacecolor='none', linestyle=style['linestyle'], color=style['color'], \ + markersize=5, linewidth=0.5, alpha=1.0, label=f'{lable}') + plt.plot(xcc, u_analytical, 'r--', label='Analytical') + plt.xlabel('x') + plt.ylabel('u') + plt.legend() + plt.grid(True, color='gray', linestyle='--', linewidth=0.5, alpha=0.7) + plt.tight_layout() + plt.show() + +def RunEno(solver, mesh, iorder): + eno = Eno(solver, mesh, iorder) + init_coef(eno.iorder, eno.coef) + init_field(eno) + + simu_time = solver.T + t = 0.0 + dt = eno.dt + while t < simu_time: + runge_kutta(eno) + if t + dt > simu_time: + dt = simu_time - t + t += dt + print(f'T={t:.3f},runge_kutta{solver.rk},ENO{eno.iorder},{fluxnames[solver.iflux]} FLUX') + #visualize(eno) + return np.copy(eno.u[eno.ist:eno.ied+1]) + +def performEnoOrderAnalysis(): + iorder_max = 7 + mesh = Mesh() + solver = Solver() + #计算理论解 + u_analytical = analytical_solution(mesh.xcc, solver.T, solver.c, mesh.L) + + u_list = [] + for iorder in range(1, iorder_max+1): + u = RunEno(solver, mesh, iorder) + u_list.append(u) + + plot_eno_field(solver, mesh.xcc, u_list, u_analytical) + +def main(): + performEnoOrderAnalysis() + + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/example/1d-linear-convection/eno/rusanov/rk1/eno1-7/01/plot.py b/example/1d-linear-convection/eno/rusanov/rk1/eno1-7/01/plot.py new file mode 100644 index 00000000..e389044c --- /dev/null +++ b/example/1d-linear-convection/eno/rusanov/rk1/eno1-7/01/plot.py @@ -0,0 +1,53 @@ +import numpy as np +import matplotlib.pyplot as plt +import csv +import sys + +nvar = len(sys.argv) +print('nvar=',nvar) +print('sys.argv=',sys.argv) + +order = 1 +if nvar >= 2: + var = sys.argv[1] + print('var=',var) + order = int(var) + +print('order=',order) + +x_list = [] +u_list = [] + +with open('solution.plt', newline='') as csvfile: + #readCSV = csv.reader(csvfile, delimiter= ' ') + icount = 0 + for line in csvfile: + # 去除首尾空格,按连续空格分割 + row = line.strip().split() + #print("row=",row) + x_list.append(row[0]) + u_list.append(row[1]) + icount += 1 + +ni = icount +print("ni=",ni) + +#print("x_list=",x_list) + +x = np.zeros( ni ) +u = np.zeros( ni ) + +for i in range(0, ni): + x[i] = float(x_list[i]) + u[i] = float(u_list[i]) + +labelname = 'Eno' + str(order) + +plt.figure("OneFLOW-CFD Solver", figsize=(8, 6), dpi=100) +plt.plot(x, u, "b-", linewidth=1.0, marker = 's', markerfacecolor='None', label=labelname) +plt.xlabel("$x$") +plt.ylabel("$u$") +plt.title("burgers T=1") +plt.legend() +plt.tight_layout() +plt.show(); \ No newline at end of file diff --git a/example/1d-linear-convection/eno/rusanov/rk1/eno1/01/eno.py b/example/1d-linear-convection/eno/rusanov/rk1/eno1/01/eno.py new file mode 100644 index 00000000..063a2724 --- /dev/null +++ b/example/1d-linear-convection/eno/rusanov/rk1/eno1/01/eno.py @@ -0,0 +1,271 @@ +import numpy as np +import matplotlib.pyplot as plt + +# 初始条件 +def initial_condition(x): + u0 = np.zeros_like(x) + for i in range(len(x)): + if 0.5 <= x[i] <= 1.0: + u0[i] = 2.0 + else: + u0[i] = 1.0 + return u0 + +# 理论解 +def analytical_solution(x, t, a): + # 初始条件沿 x - at 平移 + x_shifted = x - a * t + return initial_condition((x_shifted + L) % L) # 周期边界条件 + +def residual(q): + reconstruction(q) + inviscid_flux(up1_2m, up1_2p, flux) + for i in range(nx): + res[i] = -(flux[i + 1] - flux[i]) / dx + +def reconstruction(q): + global il, ir, dd, up1_2m, up1_2p + + # Choose the stencil by ENO method + dd[0, 0:ntcell-1] = q[0:ntcell-1] + + for m in range(1, iorder): + for j in range(0, ntcell-1): + dd[m, j] = dd[m-1, j+1] - dd[m-1, j] + + for i in range(nx + 1): + il[i] = i - 1 + for m in range(1, iorder): + if abs(dd[m, il[i]-1+ishift]) <= abs(dd[m, il[i]+ishift]): + il[i] -= 1 + + for i in range(nx + 1): + ir[i] = i + for m in range(1, iorder): + if abs(dd[m, ir[i]-1+ishift]) <= abs(dd[m, ir[i]+ishift]): + ir[i] -= 1 + + # Reconstruction u(j+1/2) + for i in range(nx + 1): + k1 = il[i] + k2 = ir[i] + l1 = i - k1 + l2 = i - k2 + up1_2m[i] = 0 + up1_2p[i] = 0 + for m in range(iorder): + up1_2m[i] += q[k1 + ishift + m] * coef[l1, m] + up1_2p[i] += q[k2 + ishift + m] * coef[l2, m] + +def inviscid_flux(up1_2m, up1_2p, flux): + iflux = 0 + if iflux == 0: + rusanov_flux(up1_2m, up1_2p, flux) + else: + engquist_osher_flux(up1_2m, up1_2p, flux) + +def engquist_osher_flux(up1_2m, up1_2p, flux): + for i in range(nx + 1): + u_L = up1_2m[i] + u_R = up1_2p[i] + + cp = 0.5 * ( c + abs(c) ) + cm = 0.5 * ( c - abs(c) ) + + flux[i] = cp * uL + cm * u_R + +def rusanov_flux(up1_2m, up1_2p, flux): + for i in range(nx + 1): + u_L = up1_2m[i] + u_R = up1_2p[i] + F_L = c * u_L # 左状态通量 + F_R = c * u_R # 右状态通量 + alpha = abs(c) # 最大波速 + flux[i] = 0.5 * (F_L + F_R) - 0.5 * alpha * (u_R - u_L) + + +def boundary(u): + for i in range(-ighost, 1): + u[ist - 1 + i] = u[ied + i] + for i in range(1, ighost + 2): + u[ied + i] = u[ist - 1 + i] + +def update_oldfield(qn, q): + qn[:] = q[:] + +def init_coef(): + global coef + coef[0] = [1.0] + coef[1] = [1.0] + +def init_mesh(): + global xstart, xend, dx, x, xcc + xstart = 0.0 + xend = L + dx = (xend - xstart) / nx + + for i in range(0, nx+1): + x[i] = xstart + i * dx + + for i in range(0, nx): + xcc[i] = 0.5 * (x[i] + x[i + 1]) + +def init_field(): + global u, un + for i in range(ist, ied + 1): + j = i - ist + if 0.5 <= xcc[j] <= 1.0: + u[i] = 2.0 + else: + u[i] = 1.0 + boundary(u) + update_oldfield(un, u) + +def runge_kutta(): + if rk == 1: + runge_kutta_1() + elif rk == 2: + runge_kutta_2() + else: + runge_kutta_3() + +def runge_kutta_1(): + global u, un, dt + residual(u) + for i in range(nx): + j = i + ishift + u[j] = u[j] + dt * res[i] + boundary(u) + update_oldfield(un, u) + +def runge_kutta_2(): + global u, un, dt + residual(u) + for i in range(nx): + j = i + ishift + u[j] = u[j] + dt * res[i] + boundary(u) + + residual(u) + for i in range(nx): + j = i + ishift + u[j] = 0.5 * un[j] + 0.5 * u[j] + 0.5 * dt * res[i] + boundary(u) + update_oldfield(un, u) + +def runge_kutta_3(): + global u, un, dt + residual(u) + for i in range(nx): + j = i + ishift + u[j] = u[j] + dt * res[i] + boundary(u) + + residual(u) + for i in range(nx): + j = i + ishift + u[j] = 0.75 * un[j] + 0.25 * u[j] + 0.25 * dt * res[i] + boundary(u) + + residual(u) + c1, c2, c3 = 1.0/3.0, 2.0/3.0, 2.0/3.0 + for i in range(nx): + j = i + ishift + u[j] = c1 * un[j] + c2 * u[j] + c3 * dt * res[i] + boundary(u) + update_oldfield(un, u) + +def get_ordinal_numbers(order): + if order == 1: + return 'st' + elif order == 2: + return 'nd' + elif order == 3: + return 'rd' + else: + return 'th' + +def visualize(): + with open('solution.plt', 'w') as f: + for i in range(ist, ied + 1): + j = i - ist + f.write(f"{xcc[j]:20.10e}{u[i]:20.10e}\n") + + # 可视化 + u_numerical = np.copy(u[ist:ied+1]) + print(f'u_numerical.size={u_numerical.size}') + print(f'xcc.size={xcc.size}') + #计算理论解 + u_analytical = analytical_solution(xcc, T, c) + print(f'u_analytical.size={u_analytical.size}') + plt.figure("OneFLOW-CFD Solver", figsize=(10, 6)) + plt.scatter(xcc, u_numerical, facecolor="none", edgecolor="blue", s=20, linewidths=0.5, label=f'Numerical (Rusanov)') + plt.plot(xcc, u_analytical, 'r--', label='Analytical') + plt.xlabel('x') + plt.ylabel('u') + ordinal1 = get_ordinal_numbers(iorder) + ordinal2 = get_ordinal_numbers(rk) + plt.title(f'1D Convection Equation at t = {T:.2f} using {iorder}{ordinal1}-order ENO and {rk}{ordinal2}-order Runge-Kutta methods') + plt.legend() + plt.grid(True, color='gray', linestyle='--', linewidth=0.5, alpha=0.7) + plt.tight_layout() + plt.show() + +# Global constants and variables +rk = 1 +nx = 40 +iorder = 1 +ighost = iorder +ishift = ighost + 1 +ist = 0 + ishift +ied = nx - 1 + ishift +ntcell = nx + 2 * ishift +isize = iorder * (iorder + 1) + +il = np.zeros(nx + 1, dtype=int) +ir = np.zeros(nx + 1, dtype=int) +coef = np.zeros((iorder + 1, iorder)) +dd = np.zeros((iorder, ntcell)) +up1_2m = np.zeros(nx + 1) +up1_2p = np.zeros(nx + 1) +flux = np.zeros(nx + 1) +res = np.zeros(nx) +dt = 0.0 + +# Mesh module variables +xstart = 0.0 +xend = 0.0 +L = 2.0 +dx = 0.0 +x = np.zeros(nx + 1) +xcc = np.zeros(nx) + +# Field module variables +u = np.zeros(ntcell) +un = np.zeros(ntcell) + +def main(): + global dt, T, c + init_coef() + init_mesh() + init_field() + + c = 1.0 + T = 0.625 + dt = .0025 + nt = int(T / dt) + simu_time = T + + t = 0.0 + + while t < simu_time: + runge_kutta() + t += dt + if t + dt > simu_time: + dt = simu_time - t + + print(t) + visualize() + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/example/1d-linear-convection/eno/rusanov/rk1/eno1/01/plot.py b/example/1d-linear-convection/eno/rusanov/rk1/eno1/01/plot.py new file mode 100644 index 00000000..e389044c --- /dev/null +++ b/example/1d-linear-convection/eno/rusanov/rk1/eno1/01/plot.py @@ -0,0 +1,53 @@ +import numpy as np +import matplotlib.pyplot as plt +import csv +import sys + +nvar = len(sys.argv) +print('nvar=',nvar) +print('sys.argv=',sys.argv) + +order = 1 +if nvar >= 2: + var = sys.argv[1] + print('var=',var) + order = int(var) + +print('order=',order) + +x_list = [] +u_list = [] + +with open('solution.plt', newline='') as csvfile: + #readCSV = csv.reader(csvfile, delimiter= ' ') + icount = 0 + for line in csvfile: + # 去除首尾空格,按连续空格分割 + row = line.strip().split() + #print("row=",row) + x_list.append(row[0]) + u_list.append(row[1]) + icount += 1 + +ni = icount +print("ni=",ni) + +#print("x_list=",x_list) + +x = np.zeros( ni ) +u = np.zeros( ni ) + +for i in range(0, ni): + x[i] = float(x_list[i]) + u[i] = float(u_list[i]) + +labelname = 'Eno' + str(order) + +plt.figure("OneFLOW-CFD Solver", figsize=(8, 6), dpi=100) +plt.plot(x, u, "b-", linewidth=1.0, marker = 's', markerfacecolor='None', label=labelname) +plt.xlabel("$x$") +plt.ylabel("$u$") +plt.title("burgers T=1") +plt.legend() +plt.tight_layout() +plt.show(); \ No newline at end of file diff --git a/example/1d-linear-convection/eno/rusanov/rk1/eno2/01/eno.py b/example/1d-linear-convection/eno/rusanov/rk1/eno2/01/eno.py new file mode 100644 index 00000000..b164a197 --- /dev/null +++ b/example/1d-linear-convection/eno/rusanov/rk1/eno2/01/eno.py @@ -0,0 +1,238 @@ +import numpy as np +import matplotlib.pyplot as plt + +# 初始条件 +def initial_condition(x): + u0 = np.zeros_like(x) + for i in range(len(x)): + if 0.5 <= x[i] <= 1.0: + u0[i] = 2.0 + else: + u0[i] = 1.0 + return u0 + +# 理论解 +def analytical_solution(x, t, a): + # 初始条件沿 x - at 平移 + x_shifted = x - a * t + return initial_condition((x_shifted + L) % L) # 周期边界条件 + +def residual(q): + reconstruction(q) + inviscid_flux(up1_2m, up1_2p, flux) + for i in range(nx): + res[i] = -(flux[i + 1] - flux[i]) / dx + +def reconstruction(q): + global il, ir, dd, up1_2m, up1_2p + + # Choose the stencil by ENO method + dd[0, 0:ntcell-1] = q[0:ntcell-1] + + for m in range(1, iorder): + for j in range(0, ntcell-1): + dd[m, j] = dd[m-1, j+1] - dd[m-1, j] + + for i in range(nx + 1): + il[i] = i - 1 + for m in range(1, iorder): + if abs(dd[m, il[i]-1+ishift]) <= abs(dd[m, il[i]+ishift]): + il[i] -= 1 + + for i in range(nx + 1): + ir[i] = i + for m in range(1, iorder): + if abs(dd[m, ir[i]-1+ishift]) <= abs(dd[m, ir[i]+ishift]): + ir[i] -= 1 + + # Reconstruction u(j+1/2) + for i in range(nx + 1): + k1 = il[i] + k2 = ir[i] + l1 = i - k1 + l2 = i - k2 + up1_2m[i] = 0 + up1_2p[i] = 0 + for m in range(iorder): + up1_2m[i] += q[k1 + ishift + m] * coef[l1, m] + up1_2p[i] += q[k2 + ishift + m] * coef[l2, m] + +def inviscid_flux(up1_2m, up1_2p, flux): + iflux = 0 + if iflux == 0: + rusanov_flux(up1_2m, up1_2p, flux) + else: + engquist_osher_flux(up1_2m, up1_2p, flux) + +def engquist_osher_flux(up1_2m, up1_2p, flux): + for i in range(nx + 1): + u_L = up1_2m[i] + u_R = up1_2p[i] + + cp = 0.5 * ( c + abs(c) ) + cm = 0.5 * ( c - abs(c) ) + + flux[i] = cp * uL + cm * u_R + +def rusanov_flux(up1_2m, up1_2p, flux): + for i in range(nx + 1): + u_L = up1_2m[i] + u_R = up1_2p[i] + F_L = c * u_L # 左状态通量 + F_R = c * u_R # 右状态通量 + alpha = abs(c) # 最大波速 + flux[i] = 0.5 * (F_L + F_R) - 0.5 * alpha * (u_R - u_L) + + +def boundary(u): + for i in range(-ighost, 1): + u[ist - 1 + i] = u[ied + i] + for i in range(1, ighost + 2): + u[ied + i] = u[ist - 1 + i] + +def update_oldfield(qn, q): + qn[:] = q[:] + +def init_coef(): + global coef + coef[0] = [3.0/2.0, -1.0/2.0] + coef[1] = [1.0/2.0, 1.0/2.0] + coef[2] = [-1.0/2.0, 3.0/2.0] + +def init_mesh(): + global xstart, xend, dx, x, xcc + xstart = 0.0 + xend = L + dx = (xend - xstart) / nx + + for i in range(0, nx+1): + x[i] = xstart + i * dx + + for i in range(0, nx): + xcc[i] = 0.5 * (x[i] + x[i + 1]) + +def init_field(): + global u, un + for i in range(ist, ied + 1): + j = i - ist + if 0.5 <= xcc[j] <= 1.0: + u[i] = 2.0 + else: + u[i] = 1.0 + boundary(u) + update_oldfield(un, u) + +def runge_kutta_1(): + global u, un, dt + residual(u) + for i in range(nx): + j = i + ishift + u[j] = u[j] + dt * res[i] + boundary(u) + update_oldfield(un, u) + +def runge_kutta_3(): + global u, un, dt + residual(u) + for i in range(nx): + j = i + ishift + u[j] = u[j] + dt * res[i] + boundary(u) + + residual(u) + for i in range(nx): + j = i + ishift + u[j] = 0.75 * un[j] + 0.25 * u[j] + 0.25 * dt * res[i] + boundary(u) + + residual(u) + c1, c2, c3 = 1.0/3.0, 2.0/3.0, 2.0/3.0 + for i in range(nx): + j = i + ishift + u[j] = c1 * un[j] + c2 * u[j] + c3 * dt * res[i] + boundary(u) + update_oldfield(un, u) + +def visualize(): + with open('solution.plt', 'w') as f: + for i in range(ist, ied + 1): + j = i - ist + f.write(f"{xcc[j]:20.10e}{u[i]:20.10e}\n") + + # 可视化 + u_numerical = np.copy(u[ist:ied+1]) + print(f'u_numerical.size={u_numerical.size}') + print(f'xcc.size={xcc.size}') + #计算理论解 + u_analytical = analytical_solution(xcc, T, c) + print(f'u_analytical.size={u_analytical.size}') + plt.figure(figsize=(10, 6)) + plt.scatter(xcc, u_numerical, facecolor="none", edgecolor="blue", s=20, linewidths=0.5, label='Numerical (Rusanov)') + plt.plot(xcc, u_analytical, 'r--', label='Analytical') + plt.xlabel('x') + plt.ylabel('u') + plt.title(f'1D Convection Equation at t = {T:.2f}') + plt.legend() + plt.tight_layout() + #plt.grid(True) + plt.show() + +# Global constants and variables +nx = 40 +iorder = 2 +ighost = iorder +ishift = ighost + 1 +ist = 0 + ishift +ied = nx - 1 + ishift +ntcell = nx + 2 * ishift +isize = iorder * (iorder + 1) + +il = np.zeros(nx + 1, dtype=int) +ir = np.zeros(nx + 1, dtype=int) +coef = np.zeros((iorder + 1, iorder)) +dd = np.zeros((iorder, ntcell)) +up1_2m = np.zeros(nx + 1) +up1_2p = np.zeros(nx + 1) +flux = np.zeros(nx + 1) +res = np.zeros(nx) +dt = 0.0 + +# Mesh module variables +xstart = 0.0 +xend = 0.0 +L = 2.0 +dx = 0.0 +x = np.zeros(nx + 1) +xcc = np.zeros(nx) + +# Field module variables +u = np.zeros(ntcell) +un = np.zeros(ntcell) + +def main(): + global dt, T, c + init_coef() + init_mesh() + init_field() + + nt = 250 + dt = .0025 + c = 1.0 + + T = dt * nt + simu_time = T + + t = 0.0 + + while t < simu_time: + #runge_kutta_3() + runge_kutta_1() + t += dt + if t + dt > simu_time: + dt = simu_time - t + + print(t) + visualize() + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/example/1d-linear-convection/eno/rusanov/rk1/eno2/01/plot.py b/example/1d-linear-convection/eno/rusanov/rk1/eno2/01/plot.py new file mode 100644 index 00000000..e389044c --- /dev/null +++ b/example/1d-linear-convection/eno/rusanov/rk1/eno2/01/plot.py @@ -0,0 +1,53 @@ +import numpy as np +import matplotlib.pyplot as plt +import csv +import sys + +nvar = len(sys.argv) +print('nvar=',nvar) +print('sys.argv=',sys.argv) + +order = 1 +if nvar >= 2: + var = sys.argv[1] + print('var=',var) + order = int(var) + +print('order=',order) + +x_list = [] +u_list = [] + +with open('solution.plt', newline='') as csvfile: + #readCSV = csv.reader(csvfile, delimiter= ' ') + icount = 0 + for line in csvfile: + # 去除首尾空格,按连续空格分割 + row = line.strip().split() + #print("row=",row) + x_list.append(row[0]) + u_list.append(row[1]) + icount += 1 + +ni = icount +print("ni=",ni) + +#print("x_list=",x_list) + +x = np.zeros( ni ) +u = np.zeros( ni ) + +for i in range(0, ni): + x[i] = float(x_list[i]) + u[i] = float(u_list[i]) + +labelname = 'Eno' + str(order) + +plt.figure("OneFLOW-CFD Solver", figsize=(8, 6), dpi=100) +plt.plot(x, u, "b-", linewidth=1.0, marker = 's', markerfacecolor='None', label=labelname) +plt.xlabel("$x$") +plt.ylabel("$u$") +plt.title("burgers T=1") +plt.legend() +plt.tight_layout() +plt.show(); \ No newline at end of file diff --git a/example/1d-linear-convection/eno/rusanov/rk1/eno2/01a/eno.py b/example/1d-linear-convection/eno/rusanov/rk1/eno2/01a/eno.py new file mode 100644 index 00000000..3a6714dd --- /dev/null +++ b/example/1d-linear-convection/eno/rusanov/rk1/eno2/01a/eno.py @@ -0,0 +1,272 @@ +import numpy as np +import matplotlib.pyplot as plt + +# 初始条件 +def initial_condition(x): + u0 = np.zeros_like(x) + for i in range(len(x)): + if 0.5 <= x[i] <= 1.0: + u0[i] = 2.0 + else: + u0[i] = 1.0 + return u0 + +# 理论解 +def analytical_solution(x, t, a): + # 初始条件沿 x - at 平移 + x_shifted = x - a * t + return initial_condition((x_shifted + L) % L) # 周期边界条件 + +def residual(q): + reconstruction(q) + inviscid_flux(up1_2m, up1_2p, flux) + for i in range(nx): + res[i] = -(flux[i + 1] - flux[i]) / dx + +def reconstruction(q): + global il, ir, dd, up1_2m, up1_2p + + # Choose the stencil by ENO method + dd[0, 0:ntcell-1] = q[0:ntcell-1] + + for m in range(1, iorder): + for j in range(0, ntcell-1): + dd[m, j] = dd[m-1, j+1] - dd[m-1, j] + + for i in range(nx + 1): + il[i] = i - 1 + for m in range(1, iorder): + if abs(dd[m, il[i]-1+ishift]) <= abs(dd[m, il[i]+ishift]): + il[i] -= 1 + + for i in range(nx + 1): + ir[i] = i + for m in range(1, iorder): + if abs(dd[m, ir[i]-1+ishift]) <= abs(dd[m, ir[i]+ishift]): + ir[i] -= 1 + + # Reconstruction u(j+1/2) + for i in range(nx + 1): + k1 = il[i] + k2 = ir[i] + l1 = i - k1 + l2 = i - k2 + up1_2m[i] = 0 + up1_2p[i] = 0 + for m in range(iorder): + up1_2m[i] += q[k1 + ishift + m] * coef[l1, m] + up1_2p[i] += q[k2 + ishift + m] * coef[l2, m] + +def inviscid_flux(up1_2m, up1_2p, flux): + iflux = 0 + if iflux == 0: + rusanov_flux(up1_2m, up1_2p, flux) + else: + engquist_osher_flux(up1_2m, up1_2p, flux) + +def engquist_osher_flux(up1_2m, up1_2p, flux): + for i in range(nx + 1): + u_L = up1_2m[i] + u_R = up1_2p[i] + + cp = 0.5 * ( c + abs(c) ) + cm = 0.5 * ( c - abs(c) ) + + flux[i] = cp * uL + cm * u_R + +def rusanov_flux(up1_2m, up1_2p, flux): + for i in range(nx + 1): + u_L = up1_2m[i] + u_R = up1_2p[i] + F_L = c * u_L # 左状态通量 + F_R = c * u_R # 右状态通量 + alpha = abs(c) # 最大波速 + flux[i] = 0.5 * (F_L + F_R) - 0.5 * alpha * (u_R - u_L) + + +def boundary(u): + for i in range(-ighost, 1): + u[ist - 1 + i] = u[ied + i] + for i in range(1, ighost + 2): + u[ied + i] = u[ist - 1 + i] + +def update_oldfield(qn, q): + qn[:] = q[:] + +def init_coef(): + global coef + coef[0] = [3.0/2.0, -1.0/2.0] + coef[1] = [1.0/2.0, 1.0/2.0] + coef[2] = [-1.0/2.0, 3.0/2.0] + +def init_mesh(): + global xstart, xend, dx, x, xcc + xstart = 0.0 + xend = L + dx = (xend - xstart) / nx + + for i in range(0, nx+1): + x[i] = xstart + i * dx + + for i in range(0, nx): + xcc[i] = 0.5 * (x[i] + x[i + 1]) + +def init_field(): + global u, un + for i in range(ist, ied + 1): + j = i - ist + if 0.5 <= xcc[j] <= 1.0: + u[i] = 2.0 + else: + u[i] = 1.0 + boundary(u) + update_oldfield(un, u) + +def runge_kutta(): + if rk == 1: + runge_kutta_1() + elif rk == 2: + runge_kutta_2() + else: + runge_kutta_3() + +def runge_kutta_1(): + global u, un, dt + residual(u) + for i in range(nx): + j = i + ishift + u[j] = u[j] + dt * res[i] + boundary(u) + update_oldfield(un, u) + +def runge_kutta_2(): + global u, un, dt + residual(u) + for i in range(nx): + j = i + ishift + u[j] = u[j] + dt * res[i] + boundary(u) + + residual(u) + for i in range(nx): + j = i + ishift + u[j] = 0.5 * un[j] + 0.5 * u[j] + 0.5 * dt * res[i] + boundary(u) + update_oldfield(un, u) + +def runge_kutta_3(): + global u, un, dt + residual(u) + for i in range(nx): + j = i + ishift + u[j] = u[j] + dt * res[i] + boundary(u) + + residual(u) + for i in range(nx): + j = i + ishift + u[j] = 0.75 * un[j] + 0.25 * u[j] + 0.25 * dt * res[i] + boundary(u) + + residual(u) + c1, c2, c3 = 1.0/3.0, 2.0/3.0, 2.0/3.0 + for i in range(nx): + j = i + ishift + u[j] = c1 * un[j] + c2 * u[j] + c3 * dt * res[i] + boundary(u) + update_oldfield(un, u) + +def get_ordinal_numbers(order): + if order == 1: + return 'st' + elif order == 2: + return 'nd' + elif order == 3: + return 'rd' + else: + return 'th' + +def visualize(): + with open('solution.plt', 'w') as f: + for i in range(ist, ied + 1): + j = i - ist + f.write(f"{xcc[j]:20.10e}{u[i]:20.10e}\n") + + # 可视化 + u_numerical = np.copy(u[ist:ied+1]) + print(f'u_numerical.size={u_numerical.size}') + print(f'xcc.size={xcc.size}') + #计算理论解 + u_analytical = analytical_solution(xcc, T, c) + print(f'u_analytical.size={u_analytical.size}') + plt.figure("OneFLOW-CFD Solver", figsize=(10, 6)) + plt.scatter(xcc, u_numerical, facecolor="none", edgecolor="blue", s=20, linewidths=0.5, label=f'Numerical (Rusanov)') + plt.plot(xcc, u_analytical, 'r--', label='Analytical') + plt.xlabel('x') + plt.ylabel('u') + ordinal1 = get_ordinal_numbers(iorder) + ordinal2 = get_ordinal_numbers(rk) + plt.title(f'1D Convection Equation at t = {T:.2f} using {iorder}{ordinal1}-order ENO and {rk}{ordinal2}-order Runge-Kutta methods') + plt.legend() + plt.grid(True, color='gray', linestyle='--', linewidth=0.5, alpha=0.7) + plt.tight_layout() + plt.show() + +# Global constants and variables +rk = 1 +nx = 40 +iorder = 2 +ighost = iorder +ishift = ighost + 1 +ist = 0 + ishift +ied = nx - 1 + ishift +ntcell = nx + 2 * ishift +isize = iorder * (iorder + 1) + +il = np.zeros(nx + 1, dtype=int) +ir = np.zeros(nx + 1, dtype=int) +coef = np.zeros((iorder + 1, iorder)) +dd = np.zeros((iorder, ntcell)) +up1_2m = np.zeros(nx + 1) +up1_2p = np.zeros(nx + 1) +flux = np.zeros(nx + 1) +res = np.zeros(nx) +dt = 0.0 + +# Mesh module variables +xstart = 0.0 +xend = 0.0 +L = 2.0 +dx = 0.0 +x = np.zeros(nx + 1) +xcc = np.zeros(nx) + +# Field module variables +u = np.zeros(ntcell) +un = np.zeros(ntcell) + +def main(): + global dt, T, c + init_coef() + init_mesh() + init_field() + + c = 1.0 + T = 0.625 + dt = .0025 + nt = int(T / dt) + simu_time = T + + t = 0.0 + + while t < simu_time: + runge_kutta() + t += dt + if t + dt > simu_time: + dt = simu_time - t + + print(t) + visualize() + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/example/1d-linear-convection/eno/rusanov/rk1/eno2/01a/plot.py b/example/1d-linear-convection/eno/rusanov/rk1/eno2/01a/plot.py new file mode 100644 index 00000000..e389044c --- /dev/null +++ b/example/1d-linear-convection/eno/rusanov/rk1/eno2/01a/plot.py @@ -0,0 +1,53 @@ +import numpy as np +import matplotlib.pyplot as plt +import csv +import sys + +nvar = len(sys.argv) +print('nvar=',nvar) +print('sys.argv=',sys.argv) + +order = 1 +if nvar >= 2: + var = sys.argv[1] + print('var=',var) + order = int(var) + +print('order=',order) + +x_list = [] +u_list = [] + +with open('solution.plt', newline='') as csvfile: + #readCSV = csv.reader(csvfile, delimiter= ' ') + icount = 0 + for line in csvfile: + # 去除首尾空格,按连续空格分割 + row = line.strip().split() + #print("row=",row) + x_list.append(row[0]) + u_list.append(row[1]) + icount += 1 + +ni = icount +print("ni=",ni) + +#print("x_list=",x_list) + +x = np.zeros( ni ) +u = np.zeros( ni ) + +for i in range(0, ni): + x[i] = float(x_list[i]) + u[i] = float(u_list[i]) + +labelname = 'Eno' + str(order) + +plt.figure("OneFLOW-CFD Solver", figsize=(8, 6), dpi=100) +plt.plot(x, u, "b-", linewidth=1.0, marker = 's', markerfacecolor='None', label=labelname) +plt.xlabel("$x$") +plt.ylabel("$u$") +plt.title("burgers T=1") +plt.legend() +plt.tight_layout() +plt.show(); \ No newline at end of file diff --git a/example/1d-linear-convection/eno/rusanov/rk1/eno3/01/eno.py b/example/1d-linear-convection/eno/rusanov/rk1/eno3/01/eno.py new file mode 100644 index 00000000..6e22aca8 --- /dev/null +++ b/example/1d-linear-convection/eno/rusanov/rk1/eno3/01/eno.py @@ -0,0 +1,239 @@ +import numpy as np +import matplotlib.pyplot as plt + +# 初始条件 +def initial_condition(x): + u0 = np.zeros_like(x) + for i in range(len(x)): + if 0.5 <= x[i] <= 1.0: + u0[i] = 2.0 + else: + u0[i] = 1.0 + return u0 + +# 理论解 +def analytical_solution(x, t, a): + # 初始条件沿 x - at 平移 + x_shifted = x - a * t + return initial_condition((x_shifted + L) % L) # 周期边界条件 + +def residual(q): + reconstruction(q) + inviscid_flux(up1_2m, up1_2p, flux) + for i in range(nx): + res[i] = -(flux[i + 1] - flux[i]) / dx + +def reconstruction(q): + global il, ir, dd, up1_2m, up1_2p + + # Choose the stencil by ENO method + dd[0, 0:ntcell-1] = q[0:ntcell-1] + + for m in range(1, iorder): + for j in range(0, ntcell-1): + dd[m, j] = dd[m-1, j+1] - dd[m-1, j] + + for i in range(nx + 1): + il[i] = i - 1 + for m in range(1, iorder): + if abs(dd[m, il[i]-1+ishift]) <= abs(dd[m, il[i]+ishift]): + il[i] -= 1 + + for i in range(nx + 1): + ir[i] = i + for m in range(1, iorder): + if abs(dd[m, ir[i]-1+ishift]) <= abs(dd[m, ir[i]+ishift]): + ir[i] -= 1 + + # Reconstruction u(j+1/2) + for i in range(nx + 1): + k1 = il[i] + k2 = ir[i] + l1 = i - k1 + l2 = i - k2 + up1_2m[i] = 0 + up1_2p[i] = 0 + for m in range(iorder): + up1_2m[i] += q[k1 + ishift + m] * coef[l1, m] + up1_2p[i] += q[k2 + ishift + m] * coef[l2, m] + +def inviscid_flux(up1_2m, up1_2p, flux): + iflux = 0 + if iflux == 0: + rusanov_flux(up1_2m, up1_2p, flux) + else: + engquist_osher_flux(up1_2m, up1_2p, flux) + +def engquist_osher_flux(up1_2m, up1_2p, flux): + for i in range(nx + 1): + u_L = up1_2m[i] + u_R = up1_2p[i] + + cp = 0.5 * ( c + abs(c) ) + cm = 0.5 * ( c - abs(c) ) + + flux[i] = cp * uL + cm * u_R + +def rusanov_flux(up1_2m, up1_2p, flux): + for i in range(nx + 1): + u_L = up1_2m[i] + u_R = up1_2p[i] + F_L = c * u_L # 左状态通量 + F_R = c * u_R # 右状态通量 + alpha = abs(c) # 最大波速 + flux[i] = 0.5 * (F_L + F_R) - 0.5 * alpha * (u_R - u_L) + + +def boundary(u): + for i in range(-ighost, 1): + u[ist - 1 + i] = u[ied + i] + for i in range(1, ighost + 2): + u[ied + i] = u[ist - 1 + i] + +def update_oldfield(qn, q): + qn[:] = q[:] + +def init_coef(): + global coef + coef[0] = [ 11.0/6.0, -7.0/6.0, 1.0/3.0 ] + coef[1] = [ 1.0/3.0, 5.0/6.0, -1.0/6.0 ] + coef[2] = [ -1.0/6.0, 5.0/6.0, 1.0/3.0 ] + coef[3] = [ 1.0/3.0, -7.0/6.0, 11.0/6.0 ] + +def init_mesh(): + global xstart, xend, dx, x, xcc + xstart = 0.0 + xend = L + dx = (xend - xstart) / nx + + for i in range(0, nx+1): + x[i] = xstart + i * dx + + for i in range(0, nx): + xcc[i] = 0.5 * (x[i] + x[i + 1]) + +def init_field(): + global u, un + for i in range(ist, ied + 1): + j = i - ist + if 0.5 <= xcc[j] <= 1.0: + u[i] = 2.0 + else: + u[i] = 1.0 + boundary(u) + update_oldfield(un, u) + +def runge_kutta_1(): + global u, un, dt + residual(u) + for i in range(nx): + j = i + ishift + u[j] = u[j] + dt * res[i] + boundary(u) + update_oldfield(un, u) + +def runge_kutta_3(): + global u, un, dt + residual(u) + for i in range(nx): + j = i + ishift + u[j] = u[j] + dt * res[i] + boundary(u) + + residual(u) + for i in range(nx): + j = i + ishift + u[j] = 0.75 * un[j] + 0.25 * u[j] + 0.25 * dt * res[i] + boundary(u) + + residual(u) + c1, c2, c3 = 1.0/3.0, 2.0/3.0, 2.0/3.0 + for i in range(nx): + j = i + ishift + u[j] = c1 * un[j] + c2 * u[j] + c3 * dt * res[i] + boundary(u) + update_oldfield(un, u) + +def visualize(): + with open('solution.plt', 'w') as f: + for i in range(ist, ied + 1): + j = i - ist + f.write(f"{xcc[j]:20.10e}{u[i]:20.10e}\n") + + # 可视化 + u_numerical = np.copy(u[ist:ied+1]) + print(f'u_numerical.size={u_numerical.size}') + print(f'xcc.size={xcc.size}') + #计算理论解 + u_analytical = analytical_solution(xcc, T, c) + print(f'u_analytical.size={u_analytical.size}') + plt.figure(figsize=(10, 6)) + plt.scatter(xcc, u_numerical, facecolor="none", edgecolor="blue", s=20, linewidths=0.5, label='Numerical (Rusanov)') + plt.plot(xcc, u_analytical, 'r--', label='Analytical') + plt.xlabel('x') + plt.ylabel('u') + plt.title(f'1D Convection Equation at t = {T:.2f}') + plt.legend() + plt.tight_layout() + #plt.grid(True) + plt.show() + +# Global constants and variables +nx = 40 +iorder = 3 +ighost = iorder +ishift = ighost + 1 +ist = 0 + ishift +ied = nx - 1 + ishift +ntcell = nx + 2 * ishift +isize = iorder * (iorder + 1) + +il = np.zeros(nx + 1, dtype=int) +ir = np.zeros(nx + 1, dtype=int) +coef = np.zeros((iorder + 1, iorder)) +dd = np.zeros((iorder, ntcell)) +up1_2m = np.zeros(nx + 1) +up1_2p = np.zeros(nx + 1) +flux = np.zeros(nx + 1) +res = np.zeros(nx) +dt = 0.0 + +# Mesh module variables +xstart = 0.0 +xend = 0.0 +L = 2.0 +dx = 0.0 +x = np.zeros(nx + 1) +xcc = np.zeros(nx) + +# Field module variables +u = np.zeros(ntcell) +un = np.zeros(ntcell) + +def main(): + global dt, T, c + init_coef() + init_mesh() + init_field() + + nt = 250 + dt = .0025 + c = 1.0 + + T = dt * nt + simu_time = T + + t = 0.0 + + while t < simu_time: + #runge_kutta_3() + runge_kutta_1() + t += dt + if t + dt > simu_time: + dt = simu_time - t + + print(t) + visualize() + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/example/1d-linear-convection/eno/rusanov/rk1/eno3/01/plot.py b/example/1d-linear-convection/eno/rusanov/rk1/eno3/01/plot.py new file mode 100644 index 00000000..e389044c --- /dev/null +++ b/example/1d-linear-convection/eno/rusanov/rk1/eno3/01/plot.py @@ -0,0 +1,53 @@ +import numpy as np +import matplotlib.pyplot as plt +import csv +import sys + +nvar = len(sys.argv) +print('nvar=',nvar) +print('sys.argv=',sys.argv) + +order = 1 +if nvar >= 2: + var = sys.argv[1] + print('var=',var) + order = int(var) + +print('order=',order) + +x_list = [] +u_list = [] + +with open('solution.plt', newline='') as csvfile: + #readCSV = csv.reader(csvfile, delimiter= ' ') + icount = 0 + for line in csvfile: + # 去除首尾空格,按连续空格分割 + row = line.strip().split() + #print("row=",row) + x_list.append(row[0]) + u_list.append(row[1]) + icount += 1 + +ni = icount +print("ni=",ni) + +#print("x_list=",x_list) + +x = np.zeros( ni ) +u = np.zeros( ni ) + +for i in range(0, ni): + x[i] = float(x_list[i]) + u[i] = float(u_list[i]) + +labelname = 'Eno' + str(order) + +plt.figure("OneFLOW-CFD Solver", figsize=(8, 6), dpi=100) +plt.plot(x, u, "b-", linewidth=1.0, marker = 's', markerfacecolor='None', label=labelname) +plt.xlabel("$x$") +plt.ylabel("$u$") +plt.title("burgers T=1") +plt.legend() +plt.tight_layout() +plt.show(); \ No newline at end of file diff --git a/example/1d-linear-convection/eno/rusanov/rk1/eno3/01a/eno.py b/example/1d-linear-convection/eno/rusanov/rk1/eno3/01a/eno.py new file mode 100644 index 00000000..6ff07ed8 --- /dev/null +++ b/example/1d-linear-convection/eno/rusanov/rk1/eno3/01a/eno.py @@ -0,0 +1,273 @@ +import numpy as np +import matplotlib.pyplot as plt + +# 初始条件 +def initial_condition(x): + u0 = np.zeros_like(x) + for i in range(len(x)): + if 0.5 <= x[i] <= 1.0: + u0[i] = 2.0 + else: + u0[i] = 1.0 + return u0 + +# 理论解 +def analytical_solution(x, t, a): + # 初始条件沿 x - at 平移 + x_shifted = x - a * t + return initial_condition((x_shifted + L) % L) # 周期边界条件 + +def residual(q): + reconstruction(q) + inviscid_flux(up1_2m, up1_2p, flux) + for i in range(nx): + res[i] = -(flux[i + 1] - flux[i]) / dx + +def reconstruction(q): + global il, ir, dd, up1_2m, up1_2p + + # Choose the stencil by ENO method + dd[0, 0:ntcell-1] = q[0:ntcell-1] + + for m in range(1, iorder): + for j in range(0, ntcell-1): + dd[m, j] = dd[m-1, j+1] - dd[m-1, j] + + for i in range(nx + 1): + il[i] = i - 1 + for m in range(1, iorder): + if abs(dd[m, il[i]-1+ishift]) <= abs(dd[m, il[i]+ishift]): + il[i] -= 1 + + for i in range(nx + 1): + ir[i] = i + for m in range(1, iorder): + if abs(dd[m, ir[i]-1+ishift]) <= abs(dd[m, ir[i]+ishift]): + ir[i] -= 1 + + # Reconstruction u(j+1/2) + for i in range(nx + 1): + k1 = il[i] + k2 = ir[i] + l1 = i - k1 + l2 = i - k2 + up1_2m[i] = 0 + up1_2p[i] = 0 + for m in range(iorder): + up1_2m[i] += q[k1 + ishift + m] * coef[l1, m] + up1_2p[i] += q[k2 + ishift + m] * coef[l2, m] + +def inviscid_flux(up1_2m, up1_2p, flux): + iflux = 0 + if iflux == 0: + rusanov_flux(up1_2m, up1_2p, flux) + else: + engquist_osher_flux(up1_2m, up1_2p, flux) + +def engquist_osher_flux(up1_2m, up1_2p, flux): + for i in range(nx + 1): + u_L = up1_2m[i] + u_R = up1_2p[i] + + cp = 0.5 * ( c + abs(c) ) + cm = 0.5 * ( c - abs(c) ) + + flux[i] = cp * uL + cm * u_R + +def rusanov_flux(up1_2m, up1_2p, flux): + for i in range(nx + 1): + u_L = up1_2m[i] + u_R = up1_2p[i] + F_L = c * u_L # 左状态通量 + F_R = c * u_R # 右状态通量 + alpha = abs(c) # 最大波速 + flux[i] = 0.5 * (F_L + F_R) - 0.5 * alpha * (u_R - u_L) + + +def boundary(u): + for i in range(-ighost, 1): + u[ist - 1 + i] = u[ied + i] + for i in range(1, ighost + 2): + u[ied + i] = u[ist - 1 + i] + +def update_oldfield(qn, q): + qn[:] = q[:] + +def init_coef(): + global coef + coef[0] = [ 11.0/6.0, -7.0/6.0, 1.0/3.0 ] + coef[1] = [ 1.0/3.0, 5.0/6.0, -1.0/6.0 ] + coef[2] = [ -1.0/6.0, 5.0/6.0, 1.0/3.0 ] + coef[3] = [ 1.0/3.0, -7.0/6.0, 11.0/6.0 ] + +def init_mesh(): + global xstart, xend, dx, x, xcc + xstart = 0.0 + xend = L + dx = (xend - xstart) / nx + + for i in range(0, nx+1): + x[i] = xstart + i * dx + + for i in range(0, nx): + xcc[i] = 0.5 * (x[i] + x[i + 1]) + +def init_field(): + global u, un + for i in range(ist, ied + 1): + j = i - ist + if 0.5 <= xcc[j] <= 1.0: + u[i] = 2.0 + else: + u[i] = 1.0 + boundary(u) + update_oldfield(un, u) + +def runge_kutta(): + if rk == 1: + runge_kutta_1() + elif rk == 2: + runge_kutta_2() + else: + runge_kutta_3() + +def runge_kutta_1(): + global u, un, dt + residual(u) + for i in range(nx): + j = i + ishift + u[j] = u[j] + dt * res[i] + boundary(u) + update_oldfield(un, u) + +def runge_kutta_2(): + global u, un, dt + residual(u) + for i in range(nx): + j = i + ishift + u[j] = u[j] + dt * res[i] + boundary(u) + + residual(u) + for i in range(nx): + j = i + ishift + u[j] = 0.5 * un[j] + 0.5 * u[j] + 0.5 * dt * res[i] + boundary(u) + update_oldfield(un, u) + +def runge_kutta_3(): + global u, un, dt + residual(u) + for i in range(nx): + j = i + ishift + u[j] = u[j] + dt * res[i] + boundary(u) + + residual(u) + for i in range(nx): + j = i + ishift + u[j] = 0.75 * un[j] + 0.25 * u[j] + 0.25 * dt * res[i] + boundary(u) + + residual(u) + c1, c2, c3 = 1.0/3.0, 2.0/3.0, 2.0/3.0 + for i in range(nx): + j = i + ishift + u[j] = c1 * un[j] + c2 * u[j] + c3 * dt * res[i] + boundary(u) + update_oldfield(un, u) + +def get_ordinal_numbers(order): + if order == 1: + return 'st' + elif order == 2: + return 'nd' + elif order == 3: + return 'rd' + else: + return 'th' + +def visualize(): + with open('solution.plt', 'w') as f: + for i in range(ist, ied + 1): + j = i - ist + f.write(f"{xcc[j]:20.10e}{u[i]:20.10e}\n") + + # 可视化 + u_numerical = np.copy(u[ist:ied+1]) + print(f'u_numerical.size={u_numerical.size}') + print(f'xcc.size={xcc.size}') + #计算理论解 + u_analytical = analytical_solution(xcc, T, c) + print(f'u_analytical.size={u_analytical.size}') + plt.figure("OneFLOW-CFD Solver", figsize=(10, 6)) + plt.scatter(xcc, u_numerical, facecolor="none", edgecolor="blue", s=20, linewidths=0.5, label=f'Numerical (Rusanov)') + plt.plot(xcc, u_analytical, 'r--', label='Analytical') + plt.xlabel('x') + plt.ylabel('u') + ordinal1 = get_ordinal_numbers(iorder) + ordinal2 = get_ordinal_numbers(rk) + plt.title(f'1D Convection Equation at t = {T:.3f} using {iorder}{ordinal1}-order ENO and {rk}{ordinal2}-order Runge-Kutta methods') + plt.legend() + plt.grid(True, color='gray', linestyle='--', linewidth=0.5, alpha=0.7) + plt.tight_layout() + plt.show() + +# Global constants and variables +rk = 1 +nx = 40 +iorder = 3 +ighost = iorder +ishift = ighost + 1 +ist = 0 + ishift +ied = nx - 1 + ishift +ntcell = nx + 2 * ishift +isize = iorder * (iorder + 1) + +il = np.zeros(nx + 1, dtype=int) +ir = np.zeros(nx + 1, dtype=int) +coef = np.zeros((iorder + 1, iorder)) +dd = np.zeros((iorder, ntcell)) +up1_2m = np.zeros(nx + 1) +up1_2p = np.zeros(nx + 1) +flux = np.zeros(nx + 1) +res = np.zeros(nx) +dt = 0.0 + +# Mesh module variables +xstart = 0.0 +xend = 0.0 +L = 2.0 +dx = 0.0 +x = np.zeros(nx + 1) +xcc = np.zeros(nx) + +# Field module variables +u = np.zeros(ntcell) +un = np.zeros(ntcell) + +def main(): + global dt, T, c + init_coef() + init_mesh() + init_field() + + c = 1.0 + T = 0.625 + dt = .0025 + nt = int(T / dt) + simu_time = T + + t = 0.0 + + while t < simu_time: + runge_kutta() + t += dt + if t + dt > simu_time: + dt = simu_time - t + + print(t) + visualize() + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/example/1d-linear-convection/eno/rusanov/rk1/eno3/01a/plot.py b/example/1d-linear-convection/eno/rusanov/rk1/eno3/01a/plot.py new file mode 100644 index 00000000..e389044c --- /dev/null +++ b/example/1d-linear-convection/eno/rusanov/rk1/eno3/01a/plot.py @@ -0,0 +1,53 @@ +import numpy as np +import matplotlib.pyplot as plt +import csv +import sys + +nvar = len(sys.argv) +print('nvar=',nvar) +print('sys.argv=',sys.argv) + +order = 1 +if nvar >= 2: + var = sys.argv[1] + print('var=',var) + order = int(var) + +print('order=',order) + +x_list = [] +u_list = [] + +with open('solution.plt', newline='') as csvfile: + #readCSV = csv.reader(csvfile, delimiter= ' ') + icount = 0 + for line in csvfile: + # 去除首尾空格,按连续空格分割 + row = line.strip().split() + #print("row=",row) + x_list.append(row[0]) + u_list.append(row[1]) + icount += 1 + +ni = icount +print("ni=",ni) + +#print("x_list=",x_list) + +x = np.zeros( ni ) +u = np.zeros( ni ) + +for i in range(0, ni): + x[i] = float(x_list[i]) + u[i] = float(u_list[i]) + +labelname = 'Eno' + str(order) + +plt.figure("OneFLOW-CFD Solver", figsize=(8, 6), dpi=100) +plt.plot(x, u, "b-", linewidth=1.0, marker = 's', markerfacecolor='None', label=labelname) +plt.xlabel("$x$") +plt.ylabel("$u$") +plt.title("burgers T=1") +plt.legend() +plt.tight_layout() +plt.show(); \ No newline at end of file diff --git a/example/1d-linear-convection/eno/rusanov/rk1/eno4/01/eno.py b/example/1d-linear-convection/eno/rusanov/rk1/eno4/01/eno.py new file mode 100644 index 00000000..211cccce --- /dev/null +++ b/example/1d-linear-convection/eno/rusanov/rk1/eno4/01/eno.py @@ -0,0 +1,240 @@ +import numpy as np +import matplotlib.pyplot as plt + +# 初始条件 +def initial_condition(x): + u0 = np.zeros_like(x) + for i in range(len(x)): + if 0.5 <= x[i] <= 1.0: + u0[i] = 2.0 + else: + u0[i] = 1.0 + return u0 + +# 理论解 +def analytical_solution(x, t, a): + # 初始条件沿 x - at 平移 + x_shifted = x - a * t + return initial_condition((x_shifted + L) % L) # 周期边界条件 + +def residual(q): + reconstruction(q) + inviscid_flux(up1_2m, up1_2p, flux) + for i in range(nx): + res[i] = -(flux[i + 1] - flux[i]) / dx + +def reconstruction(q): + global il, ir, dd, up1_2m, up1_2p + + # Choose the stencil by ENO method + dd[0, 0:ntcell-1] = q[0:ntcell-1] + + for m in range(1, iorder): + for j in range(0, ntcell-1): + dd[m, j] = dd[m-1, j+1] - dd[m-1, j] + + for i in range(nx + 1): + il[i] = i - 1 + for m in range(1, iorder): + if abs(dd[m, il[i]-1+ishift]) <= abs(dd[m, il[i]+ishift]): + il[i] -= 1 + + for i in range(nx + 1): + ir[i] = i + for m in range(1, iorder): + if abs(dd[m, ir[i]-1+ishift]) <= abs(dd[m, ir[i]+ishift]): + ir[i] -= 1 + + # Reconstruction u(j+1/2) + for i in range(nx + 1): + k1 = il[i] + k2 = ir[i] + l1 = i - k1 + l2 = i - k2 + up1_2m[i] = 0 + up1_2p[i] = 0 + for m in range(iorder): + up1_2m[i] += q[k1 + ishift + m] * coef[l1, m] + up1_2p[i] += q[k2 + ishift + m] * coef[l2, m] + +def inviscid_flux(up1_2m, up1_2p, flux): + iflux = 0 + if iflux == 0: + rusanov_flux(up1_2m, up1_2p, flux) + else: + engquist_osher_flux(up1_2m, up1_2p, flux) + +def engquist_osher_flux(up1_2m, up1_2p, flux): + for i in range(nx + 1): + u_L = up1_2m[i] + u_R = up1_2p[i] + + cp = 0.5 * ( c + abs(c) ) + cm = 0.5 * ( c - abs(c) ) + + flux[i] = cp * uL + cm * u_R + +def rusanov_flux(up1_2m, up1_2p, flux): + for i in range(nx + 1): + u_L = up1_2m[i] + u_R = up1_2p[i] + F_L = c * u_L # 左状态通量 + F_R = c * u_R # 右状态通量 + alpha = abs(c) # 最大波速 + flux[i] = 0.5 * (F_L + F_R) - 0.5 * alpha * (u_R - u_L) + + +def boundary(u): + for i in range(-ighost, 1): + u[ist - 1 + i] = u[ied + i] + for i in range(1, ighost + 2): + u[ied + i] = u[ist - 1 + i] + +def update_oldfield(qn, q): + qn[:] = q[:] + +def init_coef(): + global coef + coef[0] = [ 25.0/12.0, -23.0/12.0, 13.0/12.0, -1.0/4.0 ] + coef[1] = [ 1.0/4.0, 13.0/12.0, -5.0/12.0, 1.0/12.0 ] + coef[2] = [ -1.0/12.0, 7.0/12.0, 7.0/12.0, -1.0/12.0 ] + coef[3] = [ 1.0/12.0, -5.0/12.0, 13.0/12.0, 1.0/4.0 ] + coef[4] = [ -1.0/4.0, 13.0/12.0, -23.0/12.0, 25.0/12.0 ] + +def init_mesh(): + global xstart, xend, dx, x, xcc + xstart = 0.0 + xend = L + dx = (xend - xstart) / nx + + for i in range(0, nx+1): + x[i] = xstart + i * dx + + for i in range(0, nx): + xcc[i] = 0.5 * (x[i] + x[i + 1]) + +def init_field(): + global u, un + for i in range(ist, ied + 1): + j = i - ist + if 0.5 <= xcc[j] <= 1.0: + u[i] = 2.0 + else: + u[i] = 1.0 + boundary(u) + update_oldfield(un, u) + +def runge_kutta_1(): + global u, un, dt + residual(u) + for i in range(nx): + j = i + ishift + u[j] = u[j] + dt * res[i] + boundary(u) + update_oldfield(un, u) + +def runge_kutta_3(): + global u, un, dt + residual(u) + for i in range(nx): + j = i + ishift + u[j] = u[j] + dt * res[i] + boundary(u) + + residual(u) + for i in range(nx): + j = i + ishift + u[j] = 0.75 * un[j] + 0.25 * u[j] + 0.25 * dt * res[i] + boundary(u) + + residual(u) + c1, c2, c3 = 1.0/3.0, 2.0/3.0, 2.0/3.0 + for i in range(nx): + j = i + ishift + u[j] = c1 * un[j] + c2 * u[j] + c3 * dt * res[i] + boundary(u) + update_oldfield(un, u) + +def visualize(): + with open('solution.plt', 'w') as f: + for i in range(ist, ied + 1): + j = i - ist + f.write(f"{xcc[j]:20.10e}{u[i]:20.10e}\n") + + # 可视化 + u_numerical = np.copy(u[ist:ied+1]) + print(f'u_numerical.size={u_numerical.size}') + print(f'xcc.size={xcc.size}') + #计算理论解 + u_analytical = analytical_solution(xcc, T, c) + print(f'u_analytical.size={u_analytical.size}') + plt.figure(figsize=(10, 6)) + plt.scatter(xcc, u_numerical, facecolor="none", edgecolor="blue", s=20, linewidths=0.5, label='Numerical (Rusanov)') + plt.plot(xcc, u_analytical, 'r--', label='Analytical') + plt.xlabel('x') + plt.ylabel('u') + plt.title(f'1D Convection Equation at t = {T:.2f}') + plt.legend() + plt.tight_layout() + #plt.grid(True) + plt.show() + +# Global constants and variables +nx = 40 +iorder = 4 +ighost = iorder +ishift = ighost + 1 +ist = 0 + ishift +ied = nx - 1 + ishift +ntcell = nx + 2 * ishift +isize = iorder * (iorder + 1) + +il = np.zeros(nx + 1, dtype=int) +ir = np.zeros(nx + 1, dtype=int) +coef = np.zeros((iorder + 1, iorder)) +dd = np.zeros((iorder, ntcell)) +up1_2m = np.zeros(nx + 1) +up1_2p = np.zeros(nx + 1) +flux = np.zeros(nx + 1) +res = np.zeros(nx) +dt = 0.0 + +# Mesh module variables +xstart = 0.0 +xend = 0.0 +L = 2.0 +dx = 0.0 +x = np.zeros(nx + 1) +xcc = np.zeros(nx) + +# Field module variables +u = np.zeros(ntcell) +un = np.zeros(ntcell) + +def main(): + global dt, T, c + init_coef() + init_mesh() + init_field() + + nt = 250 + dt = .0025 + c = 1.0 + + T = dt * nt + simu_time = T + + t = 0.0 + + while t < simu_time: + #runge_kutta_3() + runge_kutta_1() + t += dt + if t + dt > simu_time: + dt = simu_time - t + + print(t) + visualize() + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/example/1d-linear-convection/eno/rusanov/rk1/eno4/01/plot.py b/example/1d-linear-convection/eno/rusanov/rk1/eno4/01/plot.py new file mode 100644 index 00000000..e389044c --- /dev/null +++ b/example/1d-linear-convection/eno/rusanov/rk1/eno4/01/plot.py @@ -0,0 +1,53 @@ +import numpy as np +import matplotlib.pyplot as plt +import csv +import sys + +nvar = len(sys.argv) +print('nvar=',nvar) +print('sys.argv=',sys.argv) + +order = 1 +if nvar >= 2: + var = sys.argv[1] + print('var=',var) + order = int(var) + +print('order=',order) + +x_list = [] +u_list = [] + +with open('solution.plt', newline='') as csvfile: + #readCSV = csv.reader(csvfile, delimiter= ' ') + icount = 0 + for line in csvfile: + # 去除首尾空格,按连续空格分割 + row = line.strip().split() + #print("row=",row) + x_list.append(row[0]) + u_list.append(row[1]) + icount += 1 + +ni = icount +print("ni=",ni) + +#print("x_list=",x_list) + +x = np.zeros( ni ) +u = np.zeros( ni ) + +for i in range(0, ni): + x[i] = float(x_list[i]) + u[i] = float(u_list[i]) + +labelname = 'Eno' + str(order) + +plt.figure("OneFLOW-CFD Solver", figsize=(8, 6), dpi=100) +plt.plot(x, u, "b-", linewidth=1.0, marker = 's', markerfacecolor='None', label=labelname) +plt.xlabel("$x$") +plt.ylabel("$u$") +plt.title("burgers T=1") +plt.legend() +plt.tight_layout() +plt.show(); \ No newline at end of file diff --git a/example/1d-linear-convection/eno/rusanov/rk1/eno4/01a/eno.py b/example/1d-linear-convection/eno/rusanov/rk1/eno4/01a/eno.py new file mode 100644 index 00000000..7f3de80c --- /dev/null +++ b/example/1d-linear-convection/eno/rusanov/rk1/eno4/01a/eno.py @@ -0,0 +1,274 @@ +import numpy as np +import matplotlib.pyplot as plt + +# 初始条件 +def initial_condition(x): + u0 = np.zeros_like(x) + for i in range(len(x)): + if 0.5 <= x[i] <= 1.0: + u0[i] = 2.0 + else: + u0[i] = 1.0 + return u0 + +# 理论解 +def analytical_solution(x, t, a): + # 初始条件沿 x - at 平移 + x_shifted = x - a * t + return initial_condition((x_shifted + L) % L) # 周期边界条件 + +def residual(q): + reconstruction(q) + inviscid_flux(up1_2m, up1_2p, flux) + for i in range(nx): + res[i] = -(flux[i + 1] - flux[i]) / dx + +def reconstruction(q): + global il, ir, dd, up1_2m, up1_2p + + # Choose the stencil by ENO method + dd[0, 0:ntcell-1] = q[0:ntcell-1] + + for m in range(1, iorder): + for j in range(0, ntcell-1): + dd[m, j] = dd[m-1, j+1] - dd[m-1, j] + + for i in range(nx + 1): + il[i] = i - 1 + for m in range(1, iorder): + if abs(dd[m, il[i]-1+ishift]) <= abs(dd[m, il[i]+ishift]): + il[i] -= 1 + + for i in range(nx + 1): + ir[i] = i + for m in range(1, iorder): + if abs(dd[m, ir[i]-1+ishift]) <= abs(dd[m, ir[i]+ishift]): + ir[i] -= 1 + + # Reconstruction u(j+1/2) + for i in range(nx + 1): + k1 = il[i] + k2 = ir[i] + l1 = i - k1 + l2 = i - k2 + up1_2m[i] = 0 + up1_2p[i] = 0 + for m in range(iorder): + up1_2m[i] += q[k1 + ishift + m] * coef[l1, m] + up1_2p[i] += q[k2 + ishift + m] * coef[l2, m] + +def inviscid_flux(up1_2m, up1_2p, flux): + iflux = 0 + if iflux == 0: + rusanov_flux(up1_2m, up1_2p, flux) + else: + engquist_osher_flux(up1_2m, up1_2p, flux) + +def engquist_osher_flux(up1_2m, up1_2p, flux): + for i in range(nx + 1): + u_L = up1_2m[i] + u_R = up1_2p[i] + + cp = 0.5 * ( c + abs(c) ) + cm = 0.5 * ( c - abs(c) ) + + flux[i] = cp * uL + cm * u_R + +def rusanov_flux(up1_2m, up1_2p, flux): + for i in range(nx + 1): + u_L = up1_2m[i] + u_R = up1_2p[i] + F_L = c * u_L # 左状态通量 + F_R = c * u_R # 右状态通量 + alpha = abs(c) # 最大波速 + flux[i] = 0.5 * (F_L + F_R) - 0.5 * alpha * (u_R - u_L) + + +def boundary(u): + for i in range(-ighost, 1): + u[ist - 1 + i] = u[ied + i] + for i in range(1, ighost + 2): + u[ied + i] = u[ist - 1 + i] + +def update_oldfield(qn, q): + qn[:] = q[:] + +def init_coef(): + global coef + coef[0] = [ 25.0/12.0, -23.0/12.0, 13.0/12.0, -1.0/4.0 ] + coef[1] = [ 1.0/4.0, 13.0/12.0, -5.0/12.0, 1.0/12.0 ] + coef[2] = [ -1.0/12.0, 7.0/12.0, 7.0/12.0, -1.0/12.0 ] + coef[3] = [ 1.0/12.0, -5.0/12.0, 13.0/12.0, 1.0/4.0 ] + coef[4] = [ -1.0/4.0, 13.0/12.0, -23.0/12.0, 25.0/12.0 ] + +def init_mesh(): + global xstart, xend, dx, x, xcc + xstart = 0.0 + xend = L + dx = (xend - xstart) / nx + + for i in range(0, nx+1): + x[i] = xstart + i * dx + + for i in range(0, nx): + xcc[i] = 0.5 * (x[i] + x[i + 1]) + +def init_field(): + global u, un + for i in range(ist, ied + 1): + j = i - ist + if 0.5 <= xcc[j] <= 1.0: + u[i] = 2.0 + else: + u[i] = 1.0 + boundary(u) + update_oldfield(un, u) + +def runge_kutta(): + if rk == 1: + runge_kutta_1() + elif rk == 2: + runge_kutta_2() + else: + runge_kutta_3() + +def runge_kutta_1(): + global u, un, dt + residual(u) + for i in range(nx): + j = i + ishift + u[j] = u[j] + dt * res[i] + boundary(u) + update_oldfield(un, u) + +def runge_kutta_2(): + global u, un, dt + residual(u) + for i in range(nx): + j = i + ishift + u[j] = u[j] + dt * res[i] + boundary(u) + + residual(u) + for i in range(nx): + j = i + ishift + u[j] = 0.5 * un[j] + 0.5 * u[j] + 0.5 * dt * res[i] + boundary(u) + update_oldfield(un, u) + +def runge_kutta_3(): + global u, un, dt + residual(u) + for i in range(nx): + j = i + ishift + u[j] = u[j] + dt * res[i] + boundary(u) + + residual(u) + for i in range(nx): + j = i + ishift + u[j] = 0.75 * un[j] + 0.25 * u[j] + 0.25 * dt * res[i] + boundary(u) + + residual(u) + c1, c2, c3 = 1.0/3.0, 2.0/3.0, 2.0/3.0 + for i in range(nx): + j = i + ishift + u[j] = c1 * un[j] + c2 * u[j] + c3 * dt * res[i] + boundary(u) + update_oldfield(un, u) + +def get_ordinal_numbers(order): + if order == 1: + return 'st' + elif order == 2: + return 'nd' + elif order == 3: + return 'rd' + else: + return 'th' + +def visualize(): + with open('solution.plt', 'w') as f: + for i in range(ist, ied + 1): + j = i - ist + f.write(f"{xcc[j]:20.10e}{u[i]:20.10e}\n") + + # 可视化 + u_numerical = np.copy(u[ist:ied+1]) + print(f'u_numerical.size={u_numerical.size}') + print(f'xcc.size={xcc.size}') + #计算理论解 + u_analytical = analytical_solution(xcc, T, c) + print(f'u_analytical.size={u_analytical.size}') + plt.figure("OneFLOW-CFD Solver", figsize=(10, 6)) + plt.scatter(xcc, u_numerical, facecolor="none", edgecolor="blue", s=20, linewidths=0.5, label=f'Numerical (Rusanov)') + plt.plot(xcc, u_analytical, 'r--', label='Analytical') + plt.xlabel('x') + plt.ylabel('u') + ordinal1 = get_ordinal_numbers(iorder) + ordinal2 = get_ordinal_numbers(rk) + plt.title(f'1D Convection Equation at t = {T:.3f} using {iorder}{ordinal1}-order ENO and {rk}{ordinal2}-order Runge-Kutta methods') + plt.legend() + plt.grid(True, color='gray', linestyle='--', linewidth=0.5, alpha=0.7) + plt.tight_layout() + plt.show() + +# Global constants and variables +rk = 1 +nx = 40 +iorder = 4 +ighost = iorder +ishift = ighost + 1 +ist = 0 + ishift +ied = nx - 1 + ishift +ntcell = nx + 2 * ishift +isize = iorder * (iorder + 1) + +il = np.zeros(nx + 1, dtype=int) +ir = np.zeros(nx + 1, dtype=int) +coef = np.zeros((iorder + 1, iorder)) +dd = np.zeros((iorder, ntcell)) +up1_2m = np.zeros(nx + 1) +up1_2p = np.zeros(nx + 1) +flux = np.zeros(nx + 1) +res = np.zeros(nx) +dt = 0.0 + +# Mesh module variables +xstart = 0.0 +xend = 0.0 +L = 2.0 +dx = 0.0 +x = np.zeros(nx + 1) +xcc = np.zeros(nx) + +# Field module variables +u = np.zeros(ntcell) +un = np.zeros(ntcell) + +def main(): + global dt, T, c + init_coef() + init_mesh() + init_field() + + c = 1.0 + T = 0.625 + dt = .0025 + nt = int(T / dt) + simu_time = T + + t = 0.0 + + while t < simu_time: + runge_kutta() + t += dt + if t + dt > simu_time: + dt = simu_time - t + + print(t) + visualize() + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/example/1d-linear-convection/eno/rusanov/rk1/eno4/01a/plot.py b/example/1d-linear-convection/eno/rusanov/rk1/eno4/01a/plot.py new file mode 100644 index 00000000..e389044c --- /dev/null +++ b/example/1d-linear-convection/eno/rusanov/rk1/eno4/01a/plot.py @@ -0,0 +1,53 @@ +import numpy as np +import matplotlib.pyplot as plt +import csv +import sys + +nvar = len(sys.argv) +print('nvar=',nvar) +print('sys.argv=',sys.argv) + +order = 1 +if nvar >= 2: + var = sys.argv[1] + print('var=',var) + order = int(var) + +print('order=',order) + +x_list = [] +u_list = [] + +with open('solution.plt', newline='') as csvfile: + #readCSV = csv.reader(csvfile, delimiter= ' ') + icount = 0 + for line in csvfile: + # 去除首尾空格,按连续空格分割 + row = line.strip().split() + #print("row=",row) + x_list.append(row[0]) + u_list.append(row[1]) + icount += 1 + +ni = icount +print("ni=",ni) + +#print("x_list=",x_list) + +x = np.zeros( ni ) +u = np.zeros( ni ) + +for i in range(0, ni): + x[i] = float(x_list[i]) + u[i] = float(u_list[i]) + +labelname = 'Eno' + str(order) + +plt.figure("OneFLOW-CFD Solver", figsize=(8, 6), dpi=100) +plt.plot(x, u, "b-", linewidth=1.0, marker = 's', markerfacecolor='None', label=labelname) +plt.xlabel("$x$") +plt.ylabel("$u$") +plt.title("burgers T=1") +plt.legend() +plt.tight_layout() +plt.show(); \ No newline at end of file diff --git a/example/1d-linear-convection/eno/rusanov/rk1/eno5/01/eno.py b/example/1d-linear-convection/eno/rusanov/rk1/eno5/01/eno.py new file mode 100644 index 00000000..dbd534e0 --- /dev/null +++ b/example/1d-linear-convection/eno/rusanov/rk1/eno5/01/eno.py @@ -0,0 +1,241 @@ +import numpy as np +import matplotlib.pyplot as plt + +# 初始条件 +def initial_condition(x): + u0 = np.zeros_like(x) + for i in range(len(x)): + if 0.5 <= x[i] <= 1.0: + u0[i] = 2.0 + else: + u0[i] = 1.0 + return u0 + +# 理论解 +def analytical_solution(x, t, a): + # 初始条件沿 x - at 平移 + x_shifted = x - a * t + return initial_condition((x_shifted + L) % L) # 周期边界条件 + +def residual(q): + reconstruction(q) + inviscid_flux(up1_2m, up1_2p, flux) + for i in range(nx): + res[i] = -(flux[i + 1] - flux[i]) / dx + +def reconstruction(q): + global il, ir, dd, up1_2m, up1_2p + + # Choose the stencil by ENO method + dd[0, 0:ntcell-1] = q[0:ntcell-1] + + for m in range(1, iorder): + for j in range(0, ntcell-1): + dd[m, j] = dd[m-1, j+1] - dd[m-1, j] + + for i in range(nx + 1): + il[i] = i - 1 + for m in range(1, iorder): + if abs(dd[m, il[i]-1+ishift]) <= abs(dd[m, il[i]+ishift]): + il[i] -= 1 + + for i in range(nx + 1): + ir[i] = i + for m in range(1, iorder): + if abs(dd[m, ir[i]-1+ishift]) <= abs(dd[m, ir[i]+ishift]): + ir[i] -= 1 + + # Reconstruction u(j+1/2) + for i in range(nx + 1): + k1 = il[i] + k2 = ir[i] + l1 = i - k1 + l2 = i - k2 + up1_2m[i] = 0 + up1_2p[i] = 0 + for m in range(iorder): + up1_2m[i] += q[k1 + ishift + m] * coef[l1, m] + up1_2p[i] += q[k2 + ishift + m] * coef[l2, m] + +def inviscid_flux(up1_2m, up1_2p, flux): + iflux = 0 + if iflux == 0: + rusanov_flux(up1_2m, up1_2p, flux) + else: + engquist_osher_flux(up1_2m, up1_2p, flux) + +def engquist_osher_flux(up1_2m, up1_2p, flux): + for i in range(nx + 1): + u_L = up1_2m[i] + u_R = up1_2p[i] + + cp = 0.5 * ( c + abs(c) ) + cm = 0.5 * ( c - abs(c) ) + + flux[i] = cp * uL + cm * u_R + +def rusanov_flux(up1_2m, up1_2p, flux): + for i in range(nx + 1): + u_L = up1_2m[i] + u_R = up1_2p[i] + F_L = c * u_L # 左状态通量 + F_R = c * u_R # 右状态通量 + alpha = abs(c) # 最大波速 + flux[i] = 0.5 * (F_L + F_R) - 0.5 * alpha * (u_R - u_L) + + +def boundary(u): + for i in range(-ighost, 1): + u[ist - 1 + i] = u[ied + i] + for i in range(1, ighost + 2): + u[ied + i] = u[ist - 1 + i] + +def update_oldfield(qn, q): + qn[:] = q[:] + +def init_coef(): + global coef + coef[0] = [ 137.0/60.0, -163.0/60.0, 137.0/60.0, -21.0/20.0, 1.0/5.0 ] + coef[1] = [ 1.0/5.0, 77.0/60.0, -43.0/60.0, 17.0/60.0, -1.0/20.0 ] + coef[2] = [ -1.0/20.0, 9.0/20.0, 47.0/60.0, -13.0/60.0, 1.0/30.0 ] + coef[3] = [ 1.0/30.0, -13.0/60.0, 47.0/60.0, 9.0/20.0, -1.0/20.0 ] + coef[4] = [ -1.0/20.0, 17.0/60.0, -43.0/60.0, 77.0/60.0, 1.0/5.0 ] + coef[5] = [ 1.0/5.0, -21.0/20.0, 137.0/60.0, -163.0/60.0, 137.0/60.0 ] + +def init_mesh(): + global xstart, xend, dx, x, xcc + xstart = 0.0 + xend = L + dx = (xend - xstart) / nx + + for i in range(0, nx+1): + x[i] = xstart + i * dx + + for i in range(0, nx): + xcc[i] = 0.5 * (x[i] + x[i + 1]) + +def init_field(): + global u, un + for i in range(ist, ied + 1): + j = i - ist + if 0.5 <= xcc[j] <= 1.0: + u[i] = 2.0 + else: + u[i] = 1.0 + boundary(u) + update_oldfield(un, u) + +def runge_kutta_1(): + global u, un, dt + residual(u) + for i in range(nx): + j = i + ishift + u[j] = u[j] + dt * res[i] + boundary(u) + update_oldfield(un, u) + +def runge_kutta_3(): + global u, un, dt + residual(u) + for i in range(nx): + j = i + ishift + u[j] = u[j] + dt * res[i] + boundary(u) + + residual(u) + for i in range(nx): + j = i + ishift + u[j] = 0.75 * un[j] + 0.25 * u[j] + 0.25 * dt * res[i] + boundary(u) + + residual(u) + c1, c2, c3 = 1.0/3.0, 2.0/3.0, 2.0/3.0 + for i in range(nx): + j = i + ishift + u[j] = c1 * un[j] + c2 * u[j] + c3 * dt * res[i] + boundary(u) + update_oldfield(un, u) + +def visualize(): + with open('solution.plt', 'w') as f: + for i in range(ist, ied + 1): + j = i - ist + f.write(f"{xcc[j]:20.10e}{u[i]:20.10e}\n") + + # 可视化 + u_numerical = np.copy(u[ist:ied+1]) + print(f'u_numerical.size={u_numerical.size}') + print(f'xcc.size={xcc.size}') + #计算理论解 + u_analytical = analytical_solution(xcc, T, c) + print(f'u_analytical.size={u_analytical.size}') + plt.figure(figsize=(10, 6)) + plt.scatter(xcc, u_numerical, facecolor="none", edgecolor="blue", s=20, linewidths=0.5, label='Numerical (Rusanov)') + plt.plot(xcc, u_analytical, 'r--', label='Analytical') + plt.xlabel('x') + plt.ylabel('u') + plt.title(f'1D Convection Equation at t = {T:.2f}') + plt.legend() + plt.tight_layout() + #plt.grid(True) + plt.show() + +# Global constants and variables +nx = 40 +iorder = 5 +ighost = iorder +ishift = ighost + 1 +ist = 0 + ishift +ied = nx - 1 + ishift +ntcell = nx + 2 * ishift +isize = iorder * (iorder + 1) + +il = np.zeros(nx + 1, dtype=int) +ir = np.zeros(nx + 1, dtype=int) +coef = np.zeros((iorder + 1, iorder)) +dd = np.zeros((iorder, ntcell)) +up1_2m = np.zeros(nx + 1) +up1_2p = np.zeros(nx + 1) +flux = np.zeros(nx + 1) +res = np.zeros(nx) +dt = 0.0 + +# Mesh module variables +xstart = 0.0 +xend = 0.0 +L = 2.0 +dx = 0.0 +x = np.zeros(nx + 1) +xcc = np.zeros(nx) + +# Field module variables +u = np.zeros(ntcell) +un = np.zeros(ntcell) + +def main(): + global dt, T, c + init_coef() + init_mesh() + init_field() + + nt = 250 + dt = .0025 + c = 1.0 + + T = dt * nt + simu_time = T + + t = 0.0 + + while t < simu_time: + #runge_kutta_3() + runge_kutta_1() + t += dt + if t + dt > simu_time: + dt = simu_time - t + + print(t) + visualize() + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/example/1d-linear-convection/eno/rusanov/rk1/eno5/01/plot.py b/example/1d-linear-convection/eno/rusanov/rk1/eno5/01/plot.py new file mode 100644 index 00000000..e389044c --- /dev/null +++ b/example/1d-linear-convection/eno/rusanov/rk1/eno5/01/plot.py @@ -0,0 +1,53 @@ +import numpy as np +import matplotlib.pyplot as plt +import csv +import sys + +nvar = len(sys.argv) +print('nvar=',nvar) +print('sys.argv=',sys.argv) + +order = 1 +if nvar >= 2: + var = sys.argv[1] + print('var=',var) + order = int(var) + +print('order=',order) + +x_list = [] +u_list = [] + +with open('solution.plt', newline='') as csvfile: + #readCSV = csv.reader(csvfile, delimiter= ' ') + icount = 0 + for line in csvfile: + # 去除首尾空格,按连续空格分割 + row = line.strip().split() + #print("row=",row) + x_list.append(row[0]) + u_list.append(row[1]) + icount += 1 + +ni = icount +print("ni=",ni) + +#print("x_list=",x_list) + +x = np.zeros( ni ) +u = np.zeros( ni ) + +for i in range(0, ni): + x[i] = float(x_list[i]) + u[i] = float(u_list[i]) + +labelname = 'Eno' + str(order) + +plt.figure("OneFLOW-CFD Solver", figsize=(8, 6), dpi=100) +plt.plot(x, u, "b-", linewidth=1.0, marker = 's', markerfacecolor='None', label=labelname) +plt.xlabel("$x$") +plt.ylabel("$u$") +plt.title("burgers T=1") +plt.legend() +plt.tight_layout() +plt.show(); \ No newline at end of file diff --git a/example/1d-linear-convection/eno/rusanov/rk1/eno5/01a/eno.py b/example/1d-linear-convection/eno/rusanov/rk1/eno5/01a/eno.py new file mode 100644 index 00000000..1c8c35ab --- /dev/null +++ b/example/1d-linear-convection/eno/rusanov/rk1/eno5/01a/eno.py @@ -0,0 +1,275 @@ +import numpy as np +import matplotlib.pyplot as plt + +# 初始条件 +def initial_condition(x): + u0 = np.zeros_like(x) + for i in range(len(x)): + if 0.5 <= x[i] <= 1.0: + u0[i] = 2.0 + else: + u0[i] = 1.0 + return u0 + +# 理论解 +def analytical_solution(x, t, a): + # 初始条件沿 x - at 平移 + x_shifted = x - a * t + return initial_condition((x_shifted + L) % L) # 周期边界条件 + +def residual(q): + reconstruction(q) + inviscid_flux(up1_2m, up1_2p, flux) + for i in range(nx): + res[i] = -(flux[i + 1] - flux[i]) / dx + +def reconstruction(q): + global il, ir, dd, up1_2m, up1_2p + + # Choose the stencil by ENO method + dd[0, 0:ntcell-1] = q[0:ntcell-1] + + for m in range(1, iorder): + for j in range(0, ntcell-1): + dd[m, j] = dd[m-1, j+1] - dd[m-1, j] + + for i in range(nx + 1): + il[i] = i - 1 + for m in range(1, iorder): + if abs(dd[m, il[i]-1+ishift]) <= abs(dd[m, il[i]+ishift]): + il[i] -= 1 + + for i in range(nx + 1): + ir[i] = i + for m in range(1, iorder): + if abs(dd[m, ir[i]-1+ishift]) <= abs(dd[m, ir[i]+ishift]): + ir[i] -= 1 + + # Reconstruction u(j+1/2) + for i in range(nx + 1): + k1 = il[i] + k2 = ir[i] + l1 = i - k1 + l2 = i - k2 + up1_2m[i] = 0 + up1_2p[i] = 0 + for m in range(iorder): + up1_2m[i] += q[k1 + ishift + m] * coef[l1, m] + up1_2p[i] += q[k2 + ishift + m] * coef[l2, m] + +def inviscid_flux(up1_2m, up1_2p, flux): + iflux = 0 + if iflux == 0: + rusanov_flux(up1_2m, up1_2p, flux) + else: + engquist_osher_flux(up1_2m, up1_2p, flux) + +def engquist_osher_flux(up1_2m, up1_2p, flux): + for i in range(nx + 1): + u_L = up1_2m[i] + u_R = up1_2p[i] + + cp = 0.5 * ( c + abs(c) ) + cm = 0.5 * ( c - abs(c) ) + + flux[i] = cp * uL + cm * u_R + +def rusanov_flux(up1_2m, up1_2p, flux): + for i in range(nx + 1): + u_L = up1_2m[i] + u_R = up1_2p[i] + F_L = c * u_L # 左状态通量 + F_R = c * u_R # 右状态通量 + alpha = abs(c) # 最大波速 + flux[i] = 0.5 * (F_L + F_R) - 0.5 * alpha * (u_R - u_L) + + +def boundary(u): + for i in range(-ighost, 1): + u[ist - 1 + i] = u[ied + i] + for i in range(1, ighost + 2): + u[ied + i] = u[ist - 1 + i] + +def update_oldfield(qn, q): + qn[:] = q[:] + +def init_coef(): + global coef + coef[0] = [ 137.0/60.0, -163.0/60.0, 137.0/60.0, -21.0/20.0, 1.0/5.0 ] + coef[1] = [ 1.0/5.0, 77.0/60.0, -43.0/60.0, 17.0/60.0, -1.0/20.0 ] + coef[2] = [ -1.0/20.0, 9.0/20.0, 47.0/60.0, -13.0/60.0, 1.0/30.0 ] + coef[3] = [ 1.0/30.0, -13.0/60.0, 47.0/60.0, 9.0/20.0, -1.0/20.0 ] + coef[4] = [ -1.0/20.0, 17.0/60.0, -43.0/60.0, 77.0/60.0, 1.0/5.0 ] + coef[5] = [ 1.0/5.0, -21.0/20.0, 137.0/60.0, -163.0/60.0, 137.0/60.0 ] + +def init_mesh(): + global xstart, xend, dx, x, xcc + xstart = 0.0 + xend = L + dx = (xend - xstart) / nx + + for i in range(0, nx+1): + x[i] = xstart + i * dx + + for i in range(0, nx): + xcc[i] = 0.5 * (x[i] + x[i + 1]) + +def init_field(): + global u, un + for i in range(ist, ied + 1): + j = i - ist + if 0.5 <= xcc[j] <= 1.0: + u[i] = 2.0 + else: + u[i] = 1.0 + boundary(u) + update_oldfield(un, u) + +def runge_kutta(): + if rk == 1: + runge_kutta_1() + elif rk == 2: + runge_kutta_2() + else: + runge_kutta_3() + +def runge_kutta_1(): + global u, un, dt + residual(u) + for i in range(nx): + j = i + ishift + u[j] = u[j] + dt * res[i] + boundary(u) + update_oldfield(un, u) + +def runge_kutta_2(): + global u, un, dt + residual(u) + for i in range(nx): + j = i + ishift + u[j] = u[j] + dt * res[i] + boundary(u) + + residual(u) + for i in range(nx): + j = i + ishift + u[j] = 0.5 * un[j] + 0.5 * u[j] + 0.5 * dt * res[i] + boundary(u) + update_oldfield(un, u) + +def runge_kutta_3(): + global u, un, dt + residual(u) + for i in range(nx): + j = i + ishift + u[j] = u[j] + dt * res[i] + boundary(u) + + residual(u) + for i in range(nx): + j = i + ishift + u[j] = 0.75 * un[j] + 0.25 * u[j] + 0.25 * dt * res[i] + boundary(u) + + residual(u) + c1, c2, c3 = 1.0/3.0, 2.0/3.0, 2.0/3.0 + for i in range(nx): + j = i + ishift + u[j] = c1 * un[j] + c2 * u[j] + c3 * dt * res[i] + boundary(u) + update_oldfield(un, u) + +def get_ordinal_numbers(order): + if order == 1: + return 'st' + elif order == 2: + return 'nd' + elif order == 3: + return 'rd' + else: + return 'th' + +def visualize(): + with open('solution.plt', 'w') as f: + for i in range(ist, ied + 1): + j = i - ist + f.write(f"{xcc[j]:20.10e}{u[i]:20.10e}\n") + + # 可视化 + u_numerical = np.copy(u[ist:ied+1]) + print(f'u_numerical.size={u_numerical.size}') + print(f'xcc.size={xcc.size}') + #计算理论解 + u_analytical = analytical_solution(xcc, T, c) + print(f'u_analytical.size={u_analytical.size}') + plt.figure("OneFLOW-CFD Solver", figsize=(10, 6)) + plt.scatter(xcc, u_numerical, facecolor="none", edgecolor="blue", s=20, linewidths=0.5, label=f'Numerical (Rusanov)') + plt.plot(xcc, u_analytical, 'r--', label='Analytical') + plt.xlabel('x') + plt.ylabel('u') + ordinal1 = get_ordinal_numbers(iorder) + ordinal2 = get_ordinal_numbers(rk) + plt.title(f'1D Convection Equation at t = {T:.3f} using {iorder}{ordinal1}-order ENO and {rk}{ordinal2}-order Runge-Kutta methods') + plt.legend() + plt.grid(True, color='gray', linestyle='--', linewidth=0.5, alpha=0.7) + plt.tight_layout() + plt.show() + +# Global constants and variables +rk = 1 +nx = 40 +iorder = 5 +ighost = iorder +ishift = ighost + 1 +ist = 0 + ishift +ied = nx - 1 + ishift +ntcell = nx + 2 * ishift +isize = iorder * (iorder + 1) + +il = np.zeros(nx + 1, dtype=int) +ir = np.zeros(nx + 1, dtype=int) +coef = np.zeros((iorder + 1, iorder)) +dd = np.zeros((iorder, ntcell)) +up1_2m = np.zeros(nx + 1) +up1_2p = np.zeros(nx + 1) +flux = np.zeros(nx + 1) +res = np.zeros(nx) +dt = 0.0 + +# Mesh module variables +xstart = 0.0 +xend = 0.0 +L = 2.0 +dx = 0.0 +x = np.zeros(nx + 1) +xcc = np.zeros(nx) + +# Field module variables +u = np.zeros(ntcell) +un = np.zeros(ntcell) + +def main(): + global dt, T, c + init_coef() + init_mesh() + init_field() + + c = 1.0 + T = 0.625 + dt = .0025 + nt = int(T / dt) + simu_time = T + + t = 0.0 + + while t < simu_time: + runge_kutta() + t += dt + if t + dt > simu_time: + dt = simu_time - t + + print(t) + visualize() + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/example/1d-linear-convection/eno/rusanov/rk1/eno5/01a/plot.py b/example/1d-linear-convection/eno/rusanov/rk1/eno5/01a/plot.py new file mode 100644 index 00000000..e389044c --- /dev/null +++ b/example/1d-linear-convection/eno/rusanov/rk1/eno5/01a/plot.py @@ -0,0 +1,53 @@ +import numpy as np +import matplotlib.pyplot as plt +import csv +import sys + +nvar = len(sys.argv) +print('nvar=',nvar) +print('sys.argv=',sys.argv) + +order = 1 +if nvar >= 2: + var = sys.argv[1] + print('var=',var) + order = int(var) + +print('order=',order) + +x_list = [] +u_list = [] + +with open('solution.plt', newline='') as csvfile: + #readCSV = csv.reader(csvfile, delimiter= ' ') + icount = 0 + for line in csvfile: + # 去除首尾空格,按连续空格分割 + row = line.strip().split() + #print("row=",row) + x_list.append(row[0]) + u_list.append(row[1]) + icount += 1 + +ni = icount +print("ni=",ni) + +#print("x_list=",x_list) + +x = np.zeros( ni ) +u = np.zeros( ni ) + +for i in range(0, ni): + x[i] = float(x_list[i]) + u[i] = float(u_list[i]) + +labelname = 'Eno' + str(order) + +plt.figure("OneFLOW-CFD Solver", figsize=(8, 6), dpi=100) +plt.plot(x, u, "b-", linewidth=1.0, marker = 's', markerfacecolor='None', label=labelname) +plt.xlabel("$x$") +plt.ylabel("$u$") +plt.title("burgers T=1") +plt.legend() +plt.tight_layout() +plt.show(); \ No newline at end of file diff --git a/example/1d-linear-convection/eno/rusanov/rk1/eno6/01/eno.py b/example/1d-linear-convection/eno/rusanov/rk1/eno6/01/eno.py new file mode 100644 index 00000000..608e1154 --- /dev/null +++ b/example/1d-linear-convection/eno/rusanov/rk1/eno6/01/eno.py @@ -0,0 +1,242 @@ +import numpy as np +import matplotlib.pyplot as plt + +# 初始条件 +def initial_condition(x): + u0 = np.zeros_like(x) + for i in range(len(x)): + if 0.5 <= x[i] <= 1.0: + u0[i] = 2.0 + else: + u0[i] = 1.0 + return u0 + +# 理论解 +def analytical_solution(x, t, a): + # 初始条件沿 x - at 平移 + x_shifted = x - a * t + return initial_condition((x_shifted + L) % L) # 周期边界条件 + +def residual(q): + reconstruction(q) + inviscid_flux(up1_2m, up1_2p, flux) + for i in range(nx): + res[i] = -(flux[i + 1] - flux[i]) / dx + +def reconstruction(q): + global il, ir, dd, up1_2m, up1_2p + + # Choose the stencil by ENO method + dd[0, 0:ntcell-1] = q[0:ntcell-1] + + for m in range(1, iorder): + for j in range(0, ntcell-1): + dd[m, j] = dd[m-1, j+1] - dd[m-1, j] + + for i in range(nx + 1): + il[i] = i - 1 + for m in range(1, iorder): + if abs(dd[m, il[i]-1+ishift]) <= abs(dd[m, il[i]+ishift]): + il[i] -= 1 + + for i in range(nx + 1): + ir[i] = i + for m in range(1, iorder): + if abs(dd[m, ir[i]-1+ishift]) <= abs(dd[m, ir[i]+ishift]): + ir[i] -= 1 + + # Reconstruction u(j+1/2) + for i in range(nx + 1): + k1 = il[i] + k2 = ir[i] + l1 = i - k1 + l2 = i - k2 + up1_2m[i] = 0 + up1_2p[i] = 0 + for m in range(iorder): + up1_2m[i] += q[k1 + ishift + m] * coef[l1, m] + up1_2p[i] += q[k2 + ishift + m] * coef[l2, m] + +def inviscid_flux(up1_2m, up1_2p, flux): + iflux = 0 + if iflux == 0: + rusanov_flux(up1_2m, up1_2p, flux) + else: + engquist_osher_flux(up1_2m, up1_2p, flux) + +def engquist_osher_flux(up1_2m, up1_2p, flux): + for i in range(nx + 1): + u_L = up1_2m[i] + u_R = up1_2p[i] + + cp = 0.5 * ( c + abs(c) ) + cm = 0.5 * ( c - abs(c) ) + + flux[i] = cp * uL + cm * u_R + +def rusanov_flux(up1_2m, up1_2p, flux): + for i in range(nx + 1): + u_L = up1_2m[i] + u_R = up1_2p[i] + F_L = c * u_L # 左状态通量 + F_R = c * u_R # 右状态通量 + alpha = abs(c) # 最大波速 + flux[i] = 0.5 * (F_L + F_R) - 0.5 * alpha * (u_R - u_L) + + +def boundary(u): + for i in range(-ighost, 1): + u[ist - 1 + i] = u[ied + i] + for i in range(1, ighost + 2): + u[ied + i] = u[ist - 1 + i] + +def update_oldfield(qn, q): + qn[:] = q[:] + +def init_coef(): + global coef + coef[0] = [ 49.0/20.0, -71.0/20.0, 79.0/20.0, -163.0/60.0, 31.0/30.0, -1.0/6.0 ] + coef[1] = [ 1.0/6.0, 29.0/20.0, -21.0/20.0, 37.0/60.0, -13.0/60.0, 1.0/30.0 ] + coef[2] = [ -1.0/30.0, 11.0/30.0, 19.0/20.0, -23.0/60.0, 7.0/60.0, -1.0/60.0 ] + coef[3] = [ 1.0/60.0, -2.0/15.0, 37.0/60.0, 37.0/60.0, -2.0/15.0, 1.0/60.0 ] + coef[4] = [ -1.0/60.0, 7.0/60.0, -23.0/60.0, 19.0/20.0, 11.0/30.0, -1.0/30.0 ] + coef[5] = [ 1.0/30.0, -13.0/60.0, 37.0/60.0, -21.0/20.0, 29.0/20.0, 1.0/6.0 ] + coef[6] = [ -1.0/6.0, 31.0/30.0, -163.0/60.0, 79.0/20.0, -71.0/20.0, 49.0/20.0 ] + +def init_mesh(): + global xstart, xend, dx, x, xcc + xstart = 0.0 + xend = L + dx = (xend - xstart) / nx + + for i in range(0, nx+1): + x[i] = xstart + i * dx + + for i in range(0, nx): + xcc[i] = 0.5 * (x[i] + x[i + 1]) + +def init_field(): + global u, un + for i in range(ist, ied + 1): + j = i - ist + if 0.5 <= xcc[j] <= 1.0: + u[i] = 2.0 + else: + u[i] = 1.0 + boundary(u) + update_oldfield(un, u) + +def runge_kutta_1(): + global u, un, dt + residual(u) + for i in range(nx): + j = i + ishift + u[j] = u[j] + dt * res[i] + boundary(u) + update_oldfield(un, u) + +def runge_kutta_3(): + global u, un, dt + residual(u) + for i in range(nx): + j = i + ishift + u[j] = u[j] + dt * res[i] + boundary(u) + + residual(u) + for i in range(nx): + j = i + ishift + u[j] = 0.75 * un[j] + 0.25 * u[j] + 0.25 * dt * res[i] + boundary(u) + + residual(u) + c1, c2, c3 = 1.0/3.0, 2.0/3.0, 2.0/3.0 + for i in range(nx): + j = i + ishift + u[j] = c1 * un[j] + c2 * u[j] + c3 * dt * res[i] + boundary(u) + update_oldfield(un, u) + +def visualize(): + with open('solution.plt', 'w') as f: + for i in range(ist, ied + 1): + j = i - ist + f.write(f"{xcc[j]:20.10e}{u[i]:20.10e}\n") + + # 可视化 + u_numerical = np.copy(u[ist:ied+1]) + print(f'u_numerical.size={u_numerical.size}') + print(f'xcc.size={xcc.size}') + #计算理论解 + u_analytical = analytical_solution(xcc, T, c) + print(f'u_analytical.size={u_analytical.size}') + plt.figure(figsize=(10, 6)) + plt.scatter(xcc, u_numerical, facecolor="none", edgecolor="blue", s=20, linewidths=0.5, label='Numerical (Rusanov)') + plt.plot(xcc, u_analytical, 'r--', label='Analytical') + plt.xlabel('x') + plt.ylabel('u') + plt.title(f'1D Convection Equation at t = {T:.2f}') + plt.legend() + plt.tight_layout() + #plt.grid(True) + plt.show() + +# Global constants and variables +nx = 40 +iorder = 6 +ighost = iorder +ishift = ighost + 1 +ist = 0 + ishift +ied = nx - 1 + ishift +ntcell = nx + 2 * ishift +isize = iorder * (iorder + 1) + +il = np.zeros(nx + 1, dtype=int) +ir = np.zeros(nx + 1, dtype=int) +coef = np.zeros((iorder + 1, iorder)) +dd = np.zeros((iorder, ntcell)) +up1_2m = np.zeros(nx + 1) +up1_2p = np.zeros(nx + 1) +flux = np.zeros(nx + 1) +res = np.zeros(nx) +dt = 0.0 + +# Mesh module variables +xstart = 0.0 +xend = 0.0 +L = 2.0 +dx = 0.0 +x = np.zeros(nx + 1) +xcc = np.zeros(nx) + +# Field module variables +u = np.zeros(ntcell) +un = np.zeros(ntcell) + +def main(): + global dt, T, c + init_coef() + init_mesh() + init_field() + + nt = 250 + dt = .0025 + c = 1.0 + + T = dt * nt + simu_time = T + + t = 0.0 + + while t < simu_time: + #runge_kutta_3() + runge_kutta_1() + t += dt + if t + dt > simu_time: + dt = simu_time - t + + print(t) + visualize() + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/example/1d-linear-convection/eno/rusanov/rk1/eno6/01/plot.py b/example/1d-linear-convection/eno/rusanov/rk1/eno6/01/plot.py new file mode 100644 index 00000000..e389044c --- /dev/null +++ b/example/1d-linear-convection/eno/rusanov/rk1/eno6/01/plot.py @@ -0,0 +1,53 @@ +import numpy as np +import matplotlib.pyplot as plt +import csv +import sys + +nvar = len(sys.argv) +print('nvar=',nvar) +print('sys.argv=',sys.argv) + +order = 1 +if nvar >= 2: + var = sys.argv[1] + print('var=',var) + order = int(var) + +print('order=',order) + +x_list = [] +u_list = [] + +with open('solution.plt', newline='') as csvfile: + #readCSV = csv.reader(csvfile, delimiter= ' ') + icount = 0 + for line in csvfile: + # 去除首尾空格,按连续空格分割 + row = line.strip().split() + #print("row=",row) + x_list.append(row[0]) + u_list.append(row[1]) + icount += 1 + +ni = icount +print("ni=",ni) + +#print("x_list=",x_list) + +x = np.zeros( ni ) +u = np.zeros( ni ) + +for i in range(0, ni): + x[i] = float(x_list[i]) + u[i] = float(u_list[i]) + +labelname = 'Eno' + str(order) + +plt.figure("OneFLOW-CFD Solver", figsize=(8, 6), dpi=100) +plt.plot(x, u, "b-", linewidth=1.0, marker = 's', markerfacecolor='None', label=labelname) +plt.xlabel("$x$") +plt.ylabel("$u$") +plt.title("burgers T=1") +plt.legend() +plt.tight_layout() +plt.show(); \ No newline at end of file diff --git a/example/1d-linear-convection/eno/rusanov/rk1/eno6/01a/eno.py b/example/1d-linear-convection/eno/rusanov/rk1/eno6/01a/eno.py new file mode 100644 index 00000000..d2899652 --- /dev/null +++ b/example/1d-linear-convection/eno/rusanov/rk1/eno6/01a/eno.py @@ -0,0 +1,276 @@ +import numpy as np +import matplotlib.pyplot as plt + +# 初始条件 +def initial_condition(x): + u0 = np.zeros_like(x) + for i in range(len(x)): + if 0.5 <= x[i] <= 1.0: + u0[i] = 2.0 + else: + u0[i] = 1.0 + return u0 + +# 理论解 +def analytical_solution(x, t, a): + # 初始条件沿 x - at 平移 + x_shifted = x - a * t + return initial_condition((x_shifted + L) % L) # 周期边界条件 + +def residual(q): + reconstruction(q) + inviscid_flux(up1_2m, up1_2p, flux) + for i in range(nx): + res[i] = -(flux[i + 1] - flux[i]) / dx + +def reconstruction(q): + global il, ir, dd, up1_2m, up1_2p + + # Choose the stencil by ENO method + dd[0, 0:ntcell-1] = q[0:ntcell-1] + + for m in range(1, iorder): + for j in range(0, ntcell-1): + dd[m, j] = dd[m-1, j+1] - dd[m-1, j] + + for i in range(nx + 1): + il[i] = i - 1 + for m in range(1, iorder): + if abs(dd[m, il[i]-1+ishift]) <= abs(dd[m, il[i]+ishift]): + il[i] -= 1 + + for i in range(nx + 1): + ir[i] = i + for m in range(1, iorder): + if abs(dd[m, ir[i]-1+ishift]) <= abs(dd[m, ir[i]+ishift]): + ir[i] -= 1 + + # Reconstruction u(j+1/2) + for i in range(nx + 1): + k1 = il[i] + k2 = ir[i] + l1 = i - k1 + l2 = i - k2 + up1_2m[i] = 0 + up1_2p[i] = 0 + for m in range(iorder): + up1_2m[i] += q[k1 + ishift + m] * coef[l1, m] + up1_2p[i] += q[k2 + ishift + m] * coef[l2, m] + +def inviscid_flux(up1_2m, up1_2p, flux): + iflux = 0 + if iflux == 0: + rusanov_flux(up1_2m, up1_2p, flux) + else: + engquist_osher_flux(up1_2m, up1_2p, flux) + +def engquist_osher_flux(up1_2m, up1_2p, flux): + for i in range(nx + 1): + u_L = up1_2m[i] + u_R = up1_2p[i] + + cp = 0.5 * ( c + abs(c) ) + cm = 0.5 * ( c - abs(c) ) + + flux[i] = cp * uL + cm * u_R + +def rusanov_flux(up1_2m, up1_2p, flux): + for i in range(nx + 1): + u_L = up1_2m[i] + u_R = up1_2p[i] + F_L = c * u_L # 左状态通量 + F_R = c * u_R # 右状态通量 + alpha = abs(c) # 最大波速 + flux[i] = 0.5 * (F_L + F_R) - 0.5 * alpha * (u_R - u_L) + + +def boundary(u): + for i in range(-ighost, 1): + u[ist - 1 + i] = u[ied + i] + for i in range(1, ighost + 2): + u[ied + i] = u[ist - 1 + i] + +def update_oldfield(qn, q): + qn[:] = q[:] + +def init_coef(): + global coef + coef[0] = [ 49.0/20.0, -71.0/20.0, 79.0/20.0, -163.0/60.0, 31.0/30.0, -1.0/6.0 ] + coef[1] = [ 1.0/6.0, 29.0/20.0, -21.0/20.0, 37.0/60.0, -13.0/60.0, 1.0/30.0 ] + coef[2] = [ -1.0/30.0, 11.0/30.0, 19.0/20.0, -23.0/60.0, 7.0/60.0, -1.0/60.0 ] + coef[3] = [ 1.0/60.0, -2.0/15.0, 37.0/60.0, 37.0/60.0, -2.0/15.0, 1.0/60.0 ] + coef[4] = [ -1.0/60.0, 7.0/60.0, -23.0/60.0, 19.0/20.0, 11.0/30.0, -1.0/30.0 ] + coef[5] = [ 1.0/30.0, -13.0/60.0, 37.0/60.0, -21.0/20.0, 29.0/20.0, 1.0/6.0 ] + coef[6] = [ -1.0/6.0, 31.0/30.0, -163.0/60.0, 79.0/20.0, -71.0/20.0, 49.0/20.0 ] + +def init_mesh(): + global xstart, xend, dx, x, xcc + xstart = 0.0 + xend = L + dx = (xend - xstart) / nx + + for i in range(0, nx+1): + x[i] = xstart + i * dx + + for i in range(0, nx): + xcc[i] = 0.5 * (x[i] + x[i + 1]) + +def init_field(): + global u, un + for i in range(ist, ied + 1): + j = i - ist + if 0.5 <= xcc[j] <= 1.0: + u[i] = 2.0 + else: + u[i] = 1.0 + boundary(u) + update_oldfield(un, u) + +def runge_kutta(): + if rk == 1: + runge_kutta_1() + elif rk == 2: + runge_kutta_2() + else: + runge_kutta_3() + +def runge_kutta_1(): + global u, un, dt + residual(u) + for i in range(nx): + j = i + ishift + u[j] = u[j] + dt * res[i] + boundary(u) + update_oldfield(un, u) + +def runge_kutta_2(): + global u, un, dt + residual(u) + for i in range(nx): + j = i + ishift + u[j] = u[j] + dt * res[i] + boundary(u) + + residual(u) + for i in range(nx): + j = i + ishift + u[j] = 0.5 * un[j] + 0.5 * u[j] + 0.5 * dt * res[i] + boundary(u) + update_oldfield(un, u) + +def runge_kutta_3(): + global u, un, dt + residual(u) + for i in range(nx): + j = i + ishift + u[j] = u[j] + dt * res[i] + boundary(u) + + residual(u) + for i in range(nx): + j = i + ishift + u[j] = 0.75 * un[j] + 0.25 * u[j] + 0.25 * dt * res[i] + boundary(u) + + residual(u) + c1, c2, c3 = 1.0/3.0, 2.0/3.0, 2.0/3.0 + for i in range(nx): + j = i + ishift + u[j] = c1 * un[j] + c2 * u[j] + c3 * dt * res[i] + boundary(u) + update_oldfield(un, u) + +def get_ordinal_numbers(order): + if order == 1: + return 'st' + elif order == 2: + return 'nd' + elif order == 3: + return 'rd' + else: + return 'th' + +def visualize(): + with open('solution.plt', 'w') as f: + for i in range(ist, ied + 1): + j = i - ist + f.write(f"{xcc[j]:20.10e}{u[i]:20.10e}\n") + + # 可视化 + u_numerical = np.copy(u[ist:ied+1]) + print(f'u_numerical.size={u_numerical.size}') + print(f'xcc.size={xcc.size}') + #计算理论解 + u_analytical = analytical_solution(xcc, T, c) + print(f'u_analytical.size={u_analytical.size}') + plt.figure("OneFLOW-CFD Solver", figsize=(10, 6)) + plt.scatter(xcc, u_numerical, facecolor="none", edgecolor="blue", s=20, linewidths=0.5, label=f'Numerical (Rusanov)') + plt.plot(xcc, u_analytical, 'r--', label='Analytical') + plt.xlabel('x') + plt.ylabel('u') + ordinal1 = get_ordinal_numbers(iorder) + ordinal2 = get_ordinal_numbers(rk) + plt.title(f'1D Convection Equation at t = {T:.3f} using {iorder}{ordinal1}-order ENO and {rk}{ordinal2}-order Runge-Kutta methods') + plt.legend() + plt.grid(True, color='gray', linestyle='--', linewidth=0.5, alpha=0.7) + plt.tight_layout() + plt.show() + +# Global constants and variables +rk = 1 +nx = 40 +iorder = 6 +ighost = iorder +ishift = ighost + 1 +ist = 0 + ishift +ied = nx - 1 + ishift +ntcell = nx + 2 * ishift +isize = iorder * (iorder + 1) + +il = np.zeros(nx + 1, dtype=int) +ir = np.zeros(nx + 1, dtype=int) +coef = np.zeros((iorder + 1, iorder)) +dd = np.zeros((iorder, ntcell)) +up1_2m = np.zeros(nx + 1) +up1_2p = np.zeros(nx + 1) +flux = np.zeros(nx + 1) +res = np.zeros(nx) +dt = 0.0 + +# Mesh module variables +xstart = 0.0 +xend = 0.0 +L = 2.0 +dx = 0.0 +x = np.zeros(nx + 1) +xcc = np.zeros(nx) + +# Field module variables +u = np.zeros(ntcell) +un = np.zeros(ntcell) + +def main(): + global dt, T, c + init_coef() + init_mesh() + init_field() + + c = 1.0 + T = 0.625 + dt = .0025 + nt = int(T / dt) + simu_time = T + + t = 0.0 + + while t < simu_time: + runge_kutta() + t += dt + if t + dt > simu_time: + dt = simu_time - t + + print(t) + visualize() + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/example/1d-linear-convection/eno/rusanov/rk1/eno6/01a/plot.py b/example/1d-linear-convection/eno/rusanov/rk1/eno6/01a/plot.py new file mode 100644 index 00000000..e389044c --- /dev/null +++ b/example/1d-linear-convection/eno/rusanov/rk1/eno6/01a/plot.py @@ -0,0 +1,53 @@ +import numpy as np +import matplotlib.pyplot as plt +import csv +import sys + +nvar = len(sys.argv) +print('nvar=',nvar) +print('sys.argv=',sys.argv) + +order = 1 +if nvar >= 2: + var = sys.argv[1] + print('var=',var) + order = int(var) + +print('order=',order) + +x_list = [] +u_list = [] + +with open('solution.plt', newline='') as csvfile: + #readCSV = csv.reader(csvfile, delimiter= ' ') + icount = 0 + for line in csvfile: + # 去除首尾空格,按连续空格分割 + row = line.strip().split() + #print("row=",row) + x_list.append(row[0]) + u_list.append(row[1]) + icount += 1 + +ni = icount +print("ni=",ni) + +#print("x_list=",x_list) + +x = np.zeros( ni ) +u = np.zeros( ni ) + +for i in range(0, ni): + x[i] = float(x_list[i]) + u[i] = float(u_list[i]) + +labelname = 'Eno' + str(order) + +plt.figure("OneFLOW-CFD Solver", figsize=(8, 6), dpi=100) +plt.plot(x, u, "b-", linewidth=1.0, marker = 's', markerfacecolor='None', label=labelname) +plt.xlabel("$x$") +plt.ylabel("$u$") +plt.title("burgers T=1") +plt.legend() +plt.tight_layout() +plt.show(); \ No newline at end of file diff --git a/example/1d-linear-convection/eno/rusanov/rk1/eno7/01/eno.py b/example/1d-linear-convection/eno/rusanov/rk1/eno7/01/eno.py new file mode 100644 index 00000000..663be6b3 --- /dev/null +++ b/example/1d-linear-convection/eno/rusanov/rk1/eno7/01/eno.py @@ -0,0 +1,279 @@ +import numpy as np +import matplotlib.pyplot as plt + +# 初始条件 +def initial_condition(x): + u0 = np.zeros_like(x) + for i in range(len(x)): + if 0.5 <= x[i] <= 1.0: + u0[i] = 2.0 + else: + u0[i] = 1.0 + return u0 + +# 理论解 +def analytical_solution(x, t, a): + # 初始条件沿 x - at 平移 + x_shifted = x - a * t + return initial_condition((x_shifted + L) % L) # 周期边界条件 + +def residual(q): + reconstruction(q) + inviscid_flux(up1_2m, up1_2p, flux) + for i in range(nx): + res[i] = -(flux[i + 1] - flux[i]) / dx + +def reconstruction(q): + global il, ir, dd, up1_2m, up1_2p + + # Choose the stencil by ENO method + dd[0, 0:ntcell-1] = q[0:ntcell-1] + + for m in range(1, iorder): + for j in range(0, ntcell-1): + dd[m, j] = dd[m-1, j+1] - dd[m-1, j] + + for i in range(nx + 1): + il[i] = i - 1 + for m in range(1, iorder): + if abs(dd[m, il[i]-1+ishift]) <= abs(dd[m, il[i]+ishift]): + il[i] -= 1 + + for i in range(nx + 1): + ir[i] = i + for m in range(1, iorder): + if abs(dd[m, ir[i]-1+ishift]) <= abs(dd[m, ir[i]+ishift]): + ir[i] -= 1 + + # Reconstruction u(j+1/2) + for i in range(nx + 1): + k1 = il[i] + k2 = ir[i] + l1 = i - k1 + l2 = i - k2 + up1_2m[i] = 0 + up1_2p[i] = 0 + for m in range(iorder): + up1_2m[i] += q[k1 + ishift + m] * coef[l1, m] + up1_2p[i] += q[k2 + ishift + m] * coef[l2, m] + +def inviscid_flux(up1_2m, up1_2p, flux): + iflux = 0 + if iflux == 0: + rusanov_flux(up1_2m, up1_2p, flux) + else: + engquist_osher_flux(up1_2m, up1_2p, flux) + +def engquist_osher_flux(up1_2m, up1_2p, flux): + for i in range(nx + 1): + u_L = up1_2m[i] + u_R = up1_2p[i] + + cp = 0.5 * ( c + abs(c) ) + cm = 0.5 * ( c - abs(c) ) + + flux[i] = cp * uL + cm * u_R + +def rusanov_flux(up1_2m, up1_2p, flux): + for i in range(nx + 1): + u_L = up1_2m[i] + u_R = up1_2p[i] + F_L = c * u_L # 左状态通量 + F_R = c * u_R # 右状态通量 + alpha = abs(c) # 最大波速 + flux[i] = 0.5 * (F_L + F_R) - 0.5 * alpha * (u_R - u_L) + + +def boundary(u): + for i in range(-ighost, 1): + u[ist - 1 + i] = u[ied + i] + for i in range(1, ighost + 2): + u[ied + i] = u[ist - 1 + i] + +def update_oldfield(qn, q): + qn[:] = q[:] + +def init_coef(): + global coef + coef[0] = [ 363.0/140.0, -617.0/140.0, 853.0/140.0, -2341.0/420.0, 667.0/210.0, -43.0/42.0, 1.0/7.0 ] + coef[1] = [ 1.0/7.0, 223.0/140.0, -197.0/140.0, 153.0/140.0, -241.0/420.0, 37.0/210.0, -1.0/42.0 ] + coef[2] = [ -1.0/42.0, 13.0/42.0, 153.0/140.0, -241.0/420.0, 109.0/420.0, -31.0/420.0, 1.0/105.0 ] + coef[3] = [ 1.0/105.0, -19.0/210.0, 107.0/210.0, 319.0/420.0, -101.0/420.0, 5.0/84.0, -1.0/140.0 ] + coef[4] = [ -1.0/140.0, 5.0/84.0, -101.0/420.0, 319.0/420.0, 107.0/210.0, -19.0/210.0, 1.0/105.0 ] + coef[5] = [ 1.0/105.0, -31.0/420.0, 109.0/420.0, -241.0/420.0, 153.0/140.0, 13.0/42.0, -1.0/42.0 ] + coef[6] = [ -1.0/42.0, 37.0/210.0, -241.0/420.0, 153.0/140.0, -197.0/140.0, 223.0/140.0, 1.0/7.0 ] + coef[7] = [ 1.0/7.0, -43.0/42.0, 667.0/210.0, -2341.0/420.0, 853.0/140.0, -617.0/140.0, 363.0/140.0 ] + +def init_mesh(): + global xstart, xend, dx, x, xcc + xstart = 0.0 + xend = L + dx = (xend - xstart) / nx + + for i in range(0, nx+1): + x[i] = xstart + i * dx + + for i in range(0, nx): + xcc[i] = 0.5 * (x[i] + x[i + 1]) + +def init_field(): + global u, un + for i in range(ist, ied + 1): + j = i - ist + if 0.5 <= xcc[j] <= 1.0: + u[i] = 2.0 + else: + u[i] = 1.0 + boundary(u) + update_oldfield(un, u) + +def runge_kutta(): + if rk == 1: + runge_kutta_1() + elif rk == 2: + runge_kutta_2() + else: + runge_kutta_3() + +def runge_kutta_1(): + global u, un, dt + residual(u) + for i in range(nx): + j = i + ishift + u[j] = u[j] + dt * res[i] + boundary(u) + update_oldfield(un, u) + +def runge_kutta_2(): + global u, un, dt + residual(u) + for i in range(nx): + j = i + ishift + u[j] = u[j] + dt * res[i] + boundary(u) + + residual(u) + for i in range(nx): + j = i + ishift + u[j] = 0.5 * un[j] + 0.5 * u[j] + 0.5 * dt * res[i] + boundary(u) + update_oldfield(un, u) + +def runge_kutta_3(): + global u, un, dt + residual(u) + for i in range(nx): + j = i + ishift + u[j] = u[j] + dt * res[i] + boundary(u) + + residual(u) + for i in range(nx): + j = i + ishift + u[j] = 0.75 * un[j] + 0.25 * u[j] + 0.25 * dt * res[i] + boundary(u) + + residual(u) + c1, c2, c3 = 1.0/3.0, 2.0/3.0, 2.0/3.0 + for i in range(nx): + j = i + ishift + u[j] = c1 * un[j] + c2 * u[j] + c3 * dt * res[i] + boundary(u) + update_oldfield(un, u) + +def get_ordinal_numbers(order): + if order == 1: + return 'st' + elif order == 2: + return 'nd' + elif order == 3: + return 'rd' + else: + return 'th' + +def visualize(): + with open('solution.plt', 'w') as f: + for i in range(ist, ied + 1): + j = i - ist + f.write(f"{xcc[j]:20.10e}{u[i]:20.10e}\n") + + # 可视化 + u_numerical = np.copy(u[ist:ied+1]) + print(f'u_numerical.size={u_numerical.size}') + print(f'xcc.size={xcc.size}') + #计算理论解 + u_analytical = analytical_solution(xcc, T, c) + print(f'u_analytical.size={u_analytical.size}') + plt.figure("OneFLOW-CFD Solver", figsize=(10, 6)) + plt.scatter(xcc, u_numerical, facecolor="none", edgecolor="blue", s=20, linewidths=0.5, label=f'Numerical (Rusanov)') + plt.plot(xcc, u_analytical, 'r--', label='Analytical') + plt.xlabel('x') + plt.ylabel('u') + ordinal1 = get_ordinal_numbers(iorder) + ordinal2 = get_ordinal_numbers(rk) + plt.title(f'1D Convection Equation at t = {T:.2f} using {iorder}{ordinal1}-order ENO and {rk}{ordinal2}-order Runge-Kutta methods') + plt.legend() + plt.grid(True, color='gray', linestyle='--', linewidth=0.5, alpha=0.7) + plt.tight_layout() + plt.show() + +# Global constants and variables +rk = 1 +nx = 40 +iorder = 7 +ighost = iorder +ishift = ighost + 1 +ist = 0 + ishift +ied = nx - 1 + ishift +ntcell = nx + 2 * ishift +isize = iorder * (iorder + 1) + +il = np.zeros(nx + 1, dtype=int) +ir = np.zeros(nx + 1, dtype=int) +coef = np.zeros((iorder + 1, iorder)) +dd = np.zeros((iorder, ntcell)) +up1_2m = np.zeros(nx + 1) +up1_2p = np.zeros(nx + 1) +flux = np.zeros(nx + 1) +res = np.zeros(nx) +dt = 0.0 + +# Mesh module variables +xstart = 0.0 +xend = 0.0 +L = 2.0 +dx = 0.0 +x = np.zeros(nx + 1) +xcc = np.zeros(nx) + +# Field module variables +u = np.zeros(ntcell) +un = np.zeros(ntcell) + +def main(): + global dt, T, c + init_coef() + init_mesh() + init_field() + + c = 1.0 + T = 0.625 + #dt = .0025 + dt = .000025 + nt = int(T / dt) + + simu_time = T + + t = 0.0 + + while t < simu_time: + runge_kutta() + t += dt + if t + dt > simu_time: + dt = simu_time - t + + print(t) + visualize() + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/example/1d-linear-convection/eno/rusanov/rk1/eno7/01/plot.py b/example/1d-linear-convection/eno/rusanov/rk1/eno7/01/plot.py new file mode 100644 index 00000000..e389044c --- /dev/null +++ b/example/1d-linear-convection/eno/rusanov/rk1/eno7/01/plot.py @@ -0,0 +1,53 @@ +import numpy as np +import matplotlib.pyplot as plt +import csv +import sys + +nvar = len(sys.argv) +print('nvar=',nvar) +print('sys.argv=',sys.argv) + +order = 1 +if nvar >= 2: + var = sys.argv[1] + print('var=',var) + order = int(var) + +print('order=',order) + +x_list = [] +u_list = [] + +with open('solution.plt', newline='') as csvfile: + #readCSV = csv.reader(csvfile, delimiter= ' ') + icount = 0 + for line in csvfile: + # 去除首尾空格,按连续空格分割 + row = line.strip().split() + #print("row=",row) + x_list.append(row[0]) + u_list.append(row[1]) + icount += 1 + +ni = icount +print("ni=",ni) + +#print("x_list=",x_list) + +x = np.zeros( ni ) +u = np.zeros( ni ) + +for i in range(0, ni): + x[i] = float(x_list[i]) + u[i] = float(u_list[i]) + +labelname = 'Eno' + str(order) + +plt.figure("OneFLOW-CFD Solver", figsize=(8, 6), dpi=100) +plt.plot(x, u, "b-", linewidth=1.0, marker = 's', markerfacecolor='None', label=labelname) +plt.xlabel("$x$") +plt.ylabel("$u$") +plt.title("burgers T=1") +plt.legend() +plt.tight_layout() +plt.show(); \ No newline at end of file diff --git a/example/1d-linear-convection/eno/rusanov/rk1/eno7/01a/eno.py b/example/1d-linear-convection/eno/rusanov/rk1/eno7/01a/eno.py new file mode 100644 index 00000000..4a30fc01 --- /dev/null +++ b/example/1d-linear-convection/eno/rusanov/rk1/eno7/01a/eno.py @@ -0,0 +1,277 @@ +import numpy as np +import matplotlib.pyplot as plt + +# 初始条件 +def initial_condition(x): + u0 = np.zeros_like(x) + for i in range(len(x)): + if 0.5 <= x[i] <= 1.0: + u0[i] = 2.0 + else: + u0[i] = 1.0 + return u0 + +# 理论解 +def analytical_solution(x, t, a): + # 初始条件沿 x - at 平移 + x_shifted = x - a * t + return initial_condition((x_shifted + L) % L) # 周期边界条件 + +def residual(q): + reconstruction(q) + inviscid_flux(up1_2m, up1_2p, flux) + for i in range(nx): + res[i] = -(flux[i + 1] - flux[i]) / dx + +def reconstruction(q): + global il, ir, dd, up1_2m, up1_2p + + # Choose the stencil by ENO method + dd[0, 0:ntcell-1] = q[0:ntcell-1] + + for m in range(1, iorder): + for j in range(0, ntcell-1): + dd[m, j] = dd[m-1, j+1] - dd[m-1, j] + + for i in range(nx + 1): + il[i] = i - 1 + for m in range(1, iorder): + if abs(dd[m, il[i]-1+ishift]) <= abs(dd[m, il[i]+ishift]): + il[i] -= 1 + + for i in range(nx + 1): + ir[i] = i + for m in range(1, iorder): + if abs(dd[m, ir[i]-1+ishift]) <= abs(dd[m, ir[i]+ishift]): + ir[i] -= 1 + + # Reconstruction u(j+1/2) + for i in range(nx + 1): + k1 = il[i] + k2 = ir[i] + l1 = i - k1 + l2 = i - k2 + up1_2m[i] = 0 + up1_2p[i] = 0 + for m in range(iorder): + up1_2m[i] += q[k1 + ishift + m] * coef[l1, m] + up1_2p[i] += q[k2 + ishift + m] * coef[l2, m] + +def inviscid_flux(up1_2m, up1_2p, flux): + iflux = 0 + if iflux == 0: + rusanov_flux(up1_2m, up1_2p, flux) + else: + engquist_osher_flux(up1_2m, up1_2p, flux) + +def engquist_osher_flux(up1_2m, up1_2p, flux): + for i in range(nx + 1): + u_L = up1_2m[i] + u_R = up1_2p[i] + + cp = 0.5 * ( c + abs(c) ) + cm = 0.5 * ( c - abs(c) ) + + flux[i] = cp * uL + cm * u_R + +def rusanov_flux(up1_2m, up1_2p, flux): + for i in range(nx + 1): + u_L = up1_2m[i] + u_R = up1_2p[i] + F_L = c * u_L # 左状态通量 + F_R = c * u_R # 右状态通量 + alpha = abs(c) # 最大波速 + flux[i] = 0.5 * (F_L + F_R) - 0.5 * alpha * (u_R - u_L) + + +def boundary(u): + for i in range(-ighost, 1): + u[ist - 1 + i] = u[ied + i] + for i in range(1, ighost + 2): + u[ied + i] = u[ist - 1 + i] + +def update_oldfield(qn, q): + qn[:] = q[:] + +def init_coef(): + global coef + coef[0] = [ 363.0/140.0, -617.0/140.0, 853.0/140.0, -2341.0/420.0, 667.0/210.0, -43.0/42.0, 1.0/7.0 ] + coef[1] = [ 1.0/7.0, 223.0/140.0, -197.0/140.0, 153.0/140.0, -241.0/420.0, 37.0/210.0, -1.0/42.0 ] + coef[2] = [ -1.0/42.0, 13.0/42.0, 153.0/140.0, -241.0/420.0, 109.0/420.0, -31.0/420.0, 1.0/105.0 ] + coef[3] = [ 1.0/105.0, -19.0/210.0, 107.0/210.0, 319.0/420.0, -101.0/420.0, 5.0/84.0, -1.0/140.0 ] + coef[4] = [ -1.0/140.0, 5.0/84.0, -101.0/420.0, 319.0/420.0, 107.0/210.0, -19.0/210.0, 1.0/105.0 ] + coef[5] = [ 1.0/105.0, -31.0/420.0, 109.0/420.0, -241.0/420.0, 153.0/140.0, 13.0/42.0, -1.0/42.0 ] + coef[6] = [ -1.0/42.0, 37.0/210.0, -241.0/420.0, 153.0/140.0, -197.0/140.0, 223.0/140.0, 1.0/7.0 ] + coef[7] = [ 1.0/7.0, -43.0/42.0, 667.0/210.0, -2341.0/420.0, 853.0/140.0, -617.0/140.0, 363.0/140.0 ] + +def init_mesh(): + global xstart, xend, dx, x, xcc + xstart = 0.0 + xend = L + dx = (xend - xstart) / nx + + for i in range(0, nx+1): + x[i] = xstart + i * dx + + for i in range(0, nx): + xcc[i] = 0.5 * (x[i] + x[i + 1]) + +def init_field(): + global u, un + for i in range(ist, ied + 1): + j = i - ist + if 0.5 <= xcc[j] <= 1.0: + u[i] = 2.0 + else: + u[i] = 1.0 + boundary(u) + update_oldfield(un, u) + +def runge_kutta(): + if rk == 1: + runge_kutta_1() + elif rk == 2: + runge_kutta_2() + else: + runge_kutta_3() + +def runge_kutta_1(): + global u, un, dt + residual(u) + for i in range(nx): + j = i + ishift + u[j] = u[j] + dt * res[i] + boundary(u) + update_oldfield(un, u) + +def runge_kutta_2(): + global u, un, dt + residual(u) + for i in range(nx): + j = i + ishift + u[j] = u[j] + dt * res[i] + boundary(u) + + residual(u) + for i in range(nx): + j = i + ishift + u[j] = 0.5 * un[j] + 0.5 * u[j] + 0.5 * dt * res[i] + boundary(u) + update_oldfield(un, u) + +def runge_kutta_3(): + global u, un, dt + residual(u) + for i in range(nx): + j = i + ishift + u[j] = u[j] + dt * res[i] + boundary(u) + + residual(u) + for i in range(nx): + j = i + ishift + u[j] = 0.75 * un[j] + 0.25 * u[j] + 0.25 * dt * res[i] + boundary(u) + + residual(u) + c1, c2, c3 = 1.0/3.0, 2.0/3.0, 2.0/3.0 + for i in range(nx): + j = i + ishift + u[j] = c1 * un[j] + c2 * u[j] + c3 * dt * res[i] + boundary(u) + update_oldfield(un, u) + +def get_ordinal_numbers(order): + if order == 1: + return 'st' + elif order == 2: + return 'nd' + elif order == 3: + return 'rd' + else: + return 'th' + +def visualize(): + with open('solution.plt', 'w') as f: + for i in range(ist, ied + 1): + j = i - ist + f.write(f"{xcc[j]:20.10e}{u[i]:20.10e}\n") + + # 可视化 + u_numerical = np.copy(u[ist:ied+1]) + print(f'u_numerical.size={u_numerical.size}') + print(f'xcc.size={xcc.size}') + #计算理论解 + u_analytical = analytical_solution(xcc, T, c) + print(f'u_analytical.size={u_analytical.size}') + plt.figure("OneFLOW-CFD Solver", figsize=(10, 6)) + plt.scatter(xcc, u_numerical, facecolor="none", edgecolor="blue", s=20, linewidths=0.5, label=f'Numerical (Rusanov)') + plt.plot(xcc, u_analytical, 'r--', label='Analytical') + plt.xlabel('x') + plt.ylabel('u') + ordinal1 = get_ordinal_numbers(iorder) + ordinal2 = get_ordinal_numbers(rk) + plt.title(f'1D Convection Equation at t = {T:.3f} using {iorder}{ordinal1}-order ENO and {rk}{ordinal2}-order Runge-Kutta methods') + plt.legend() + plt.grid(True, color='gray', linestyle='--', linewidth=0.5, alpha=0.7) + plt.tight_layout() + plt.show() + +# Global constants and variables +rk = 1 +nx = 40 +iorder = 7 +ighost = iorder +ishift = ighost + 1 +ist = 0 + ishift +ied = nx - 1 + ishift +ntcell = nx + 2 * ishift +isize = iorder * (iorder + 1) + +il = np.zeros(nx + 1, dtype=int) +ir = np.zeros(nx + 1, dtype=int) +coef = np.zeros((iorder + 1, iorder)) +dd = np.zeros((iorder, ntcell)) +up1_2m = np.zeros(nx + 1) +up1_2p = np.zeros(nx + 1) +flux = np.zeros(nx + 1) +res = np.zeros(nx) +dt = 0.0 + +# Mesh module variables +xstart = 0.0 +xend = 0.0 +L = 2.0 +dx = 0.0 +x = np.zeros(nx + 1) +xcc = np.zeros(nx) + +# Field module variables +u = np.zeros(ntcell) +un = np.zeros(ntcell) + +def main(): + global dt, T, c + init_coef() + init_mesh() + init_field() + + c = 1.0 + T = 0.625 + dt = .0025 + nt = int(T / dt) + simu_time = T + + t = 0.0 + + while t < simu_time: + runge_kutta() + t += dt + if t + dt > simu_time: + dt = simu_time - t + + print(t) + visualize() + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/example/1d-linear-convection/eno/rusanov/rk1/eno7/01a/plot.py b/example/1d-linear-convection/eno/rusanov/rk1/eno7/01a/plot.py new file mode 100644 index 00000000..e389044c --- /dev/null +++ b/example/1d-linear-convection/eno/rusanov/rk1/eno7/01a/plot.py @@ -0,0 +1,53 @@ +import numpy as np +import matplotlib.pyplot as plt +import csv +import sys + +nvar = len(sys.argv) +print('nvar=',nvar) +print('sys.argv=',sys.argv) + +order = 1 +if nvar >= 2: + var = sys.argv[1] + print('var=',var) + order = int(var) + +print('order=',order) + +x_list = [] +u_list = [] + +with open('solution.plt', newline='') as csvfile: + #readCSV = csv.reader(csvfile, delimiter= ' ') + icount = 0 + for line in csvfile: + # 去除首尾空格,按连续空格分割 + row = line.strip().split() + #print("row=",row) + x_list.append(row[0]) + u_list.append(row[1]) + icount += 1 + +ni = icount +print("ni=",ni) + +#print("x_list=",x_list) + +x = np.zeros( ni ) +u = np.zeros( ni ) + +for i in range(0, ni): + x[i] = float(x_list[i]) + u[i] = float(u_list[i]) + +labelname = 'Eno' + str(order) + +plt.figure("OneFLOW-CFD Solver", figsize=(8, 6), dpi=100) +plt.plot(x, u, "b-", linewidth=1.0, marker = 's', markerfacecolor='None', label=labelname) +plt.xlabel("$x$") +plt.ylabel("$u$") +plt.title("burgers T=1") +plt.legend() +plt.tight_layout() +plt.show(); \ No newline at end of file diff --git a/example/1d-linear-convection/eno/rusanov/rk2/compare/01/plot.py b/example/1d-linear-convection/eno/rusanov/rk2/compare/01/plot.py new file mode 100644 index 00000000..47d83e21 --- /dev/null +++ b/example/1d-linear-convection/eno/rusanov/rk2/compare/01/plot.py @@ -0,0 +1,21 @@ +import numpy as np +import matplotlib.pyplot as plt +import os + +# 设置目录路径,'.' 表示当前目录 +directory = '.' + +# 初始化一个空列表来存储文件名 +solution_files = [] + +# 遍历目录中的所有文件和文件夹 +for filename in os.listdir(directory): + # 检查文件名是否以 "solution" 开头,并且以 ".plt" 结尾 + if filename.startswith("solution") and filename.endswith(".plt"): + # 将匹配的文件名添加到列表中 + solution_files.append(filename) + +# 打印结果 +print("Found the following solution files:") +for file in solution_files: + print(file) \ No newline at end of file diff --git a/example/1d-linear-convection/eno/rusanov/rk2/compare/01a/plot.py b/example/1d-linear-convection/eno/rusanov/rk2/compare/01a/plot.py new file mode 100644 index 00000000..bfc2f944 --- /dev/null +++ b/example/1d-linear-convection/eno/rusanov/rk2/compare/01a/plot.py @@ -0,0 +1,41 @@ +import numpy as np +import matplotlib.pyplot as plt +import os + +# 设置目录路径 +directory = '../' + +# 初始化一个空列表来存储文件名 +solution_files = [] + +# 遍历目录中的所有文件和文件夹 +for filename in os.listdir(directory): + # 检查文件名是否以 "solution" 开头,并且以 ".plt" 结尾 + if filename.startswith("solution") and filename.endswith(".plt"): + # 将匹配的文件名添加到列表中 + solution_files.append(filename) + +# 打印结果 +print("Found the following solution files:") +for file in solution_files: + print(file) + + +def read_solution_file(file_name): + x_list = [] + u_list = [] + + with open(file_name, newline='') as csvfile: + icount = 0 + for line in csvfile: + # 去除首尾空格,按连续空格分割 + row = line.strip().split() + x_list.append(row[0]) + u_list.append(row[1]) + icount += 1 + ni = icount + print("ni=",ni) + +for file in solution_files: + filename= '../' + file + read_solution_file(filename) \ No newline at end of file diff --git a/example/1d-linear-convection/eno/rusanov/rk2/compare/01b/plot.py b/example/1d-linear-convection/eno/rusanov/rk2/compare/01b/plot.py new file mode 100644 index 00000000..52a08e6f --- /dev/null +++ b/example/1d-linear-convection/eno/rusanov/rk2/compare/01b/plot.py @@ -0,0 +1,63 @@ +import numpy as np +import matplotlib.pyplot as plt +import os + +# 设置目录路径 +directory = '../' + +# 初始化一个空列表来存储文件名 +solution_files = [] + +# 遍历目录中的所有文件和文件夹 +for filename in os.listdir(directory): + # 检查文件名是否以 "solution" 开头,并且以 ".plt" 结尾 + if filename.startswith("solution") and filename.endswith(".plt"): + # 将匹配的文件名添加到列表中 + solution_files.append(filename) + +# 打印结果 +print("Found the following solution files:") +for file in solution_files: + print(file) + + +def read_solution_file(file_name): + x_list = [] + u_list = [] + + with open(file_name, newline='') as csvfile: + icount = 0 + for line in csvfile: + # 去除首尾空格,按连续空格分割 + row = line.strip().split() + x_list.append(row[0]) + u_list.append(row[1]) + icount += 1 + ni = icount + print("ni=",ni) + x = np.zeros( ni ) + u = np.zeros( ni ) + + for i in range(0, ni): + x[i] = float(x_list[i]) + u[i] = float(u_list[i]) + return x, u + +plt.figure("OneFLOW-CFD Solver", figsize=(10, 6)) +plt.xlabel('x') +plt.ylabel('u') + +for file in solution_files: + filename = '../' + file + x, u = read_solution_file(filename) + print(f'{x=}') + print(f'{u=}') + + plt.plot(x, u, marker='o', linestyle='-', color='b', markersize=8, linewidth=2, alpha=0.7, label=f'Numerical (Rusanov)') + +T = 0.625 +rk = 2 +plt.legend() +plt.grid(True, color='gray', linestyle='--', linewidth=0.5, alpha=0.7) +plt.tight_layout() +plt.show() diff --git a/example/1d-linear-convection/eno/rusanov/rk2/compare/01c/plot.py b/example/1d-linear-convection/eno/rusanov/rk2/compare/01c/plot.py new file mode 100644 index 00000000..6fb6c243 --- /dev/null +++ b/example/1d-linear-convection/eno/rusanov/rk2/compare/01c/plot.py @@ -0,0 +1,81 @@ +import numpy as np +import matplotlib.pyplot as plt +import os + +# 定义一个包含不同颜色、线形和标记的列表 +styles = [ + {'color': 'b', 'linestyle': '-', 'marker': 'o'}, + {'color': 'g', 'linestyle': '--', 'marker': 's'}, + {'color': 'r', 'linestyle': ':', 'marker': '^'}, + {'color': 'c', 'linestyle': '-', 'marker': 'v'}, + {'color': 'm', 'linestyle': '--', 'marker': '<'}, + {'color': 'y', 'linestyle': ':', 'marker': '>'}, +] + +# 设置目录路径 +directory = '../' + +# 初始化一个空列表来存储文件名 +solution_files = [] + +# 遍历目录中的所有文件和文件夹 +for filename in os.listdir(directory): + # 检查文件名是否以 "solution" 开头,并且以 ".plt" 结尾 + if filename.startswith("solution") and filename.endswith(".plt"): + # 将匹配的文件名添加到列表中 + solution_files.append(filename) + +# 打印结果 +print("Found the following solution files:") +for file in solution_files: + print(file) + + +def read_solution_file(file_name): + x_list = [] + u_list = [] + + with open(file_name, newline='') as csvfile: + icount = 0 + for line in csvfile: + # 去除首尾空格,按连续空格分割 + row = line.strip().split() + x_list.append(row[0]) + u_list.append(row[1]) + icount += 1 + ni = icount + print("ni=",ni) + x = np.zeros( ni ) + u = np.zeros( ni ) + + for i in range(0, ni): + x[i] = float(x_list[i]) + u[i] = float(u_list[i]) + return x, u + +plt.figure("OneFLOW-CFD Solver", figsize=(10, 6)) +plt.xlabel('x') +plt.ylabel('u') + +num_files = len(solution_files) +num_styles = len(styles) + +icount = 0 +for file in solution_files: + filename = '../' + file + x, u = read_solution_file(filename) + print(f'{x=}') + print(f'{u=}') + + idx = icount % num_styles + style = styles[idx] + + plt.plot(x, u, marker=style['marker'], linestyle=style['linestyle'], color=style['color'], markersize=8, linewidth=2, alpha=0.7, label=f'Numerical (Rusanov)') + icount += 1 + +T = 0.625 +rk = 2 +plt.legend() +plt.grid(True, color='gray', linestyle='--', linewidth=0.5, alpha=0.7) +plt.tight_layout() +plt.show() diff --git a/example/1d-linear-convection/eno/rusanov/rk2/compare/01d/plot.py b/example/1d-linear-convection/eno/rusanov/rk2/compare/01d/plot.py new file mode 100644 index 00000000..faf428a7 --- /dev/null +++ b/example/1d-linear-convection/eno/rusanov/rk2/compare/01d/plot.py @@ -0,0 +1,101 @@ +import numpy as np +import matplotlib.pyplot as plt +import os +import re + +# 定义一个包含不同颜色、线形和标记的列表 +# 定义10种不同的样式 +styles = [ + {'color': 'b', 'linestyle': '-', 'marker': 'o'}, + {'color': 'g', 'linestyle': '--', 'marker': 's'}, + {'color': 'r', 'linestyle': ':', 'marker': '^'}, + {'color': 'c', 'linestyle': '-', 'marker': 'v'}, + {'color': 'm', 'linestyle': '--', 'marker': '<'}, + {'color': 'y', 'linestyle': ':', 'marker': '>'}, + {'color': 'k', 'linestyle': '-', 'marker': 'x'}, + {'color': 'orange', 'linestyle': '--', 'marker': 'D'}, + {'color': 'purple', 'linestyle': ':', 'marker': 'p'}, + {'color': 'brown', 'linestyle': '-', 'marker': '*'} +] + +# 设置目录路径 +directory = '../' + +# 初始化一个空列表来存储文件名 +solution_files = [] + +# 遍历目录中的所有文件和文件夹 +for filename in os.listdir(directory): + # 检查文件名是否以 "solution" 开头,并且以 ".plt" 结尾 + if filename.startswith("solution") and filename.endswith(".plt"): + # 将匹配的文件名添加到列表中 + solution_files.append(filename) + +# 打印结果 +print("Found the following solution files:") +for file in solution_files: + print(file) + + +def read_solution_file(file_name): + x_list = [] + u_list = [] + + with open(file_name, newline='') as csvfile: + icount = 0 + for line in csvfile: + # 去除首尾空格,按连续空格分割 + row = line.strip().split() + x_list.append(row[0]) + u_list.append(row[1]) + icount += 1 + ni = icount + print("ni=",ni) + x = np.zeros( ni ) + u = np.zeros( ni ) + + for i in range(0, ni): + x[i] = float(x_list[i]) + u[i] = float(u_list[i]) + return x, u + +plt.figure("OneFLOW-CFD Solver", figsize=(10, 6)) +plt.xlabel('x') +plt.ylabel('u') + +num_files = len(solution_files) +num_styles = len(styles) + +# 初始化一个空列表来存储提取的字符串 +extracted_numbers = [] + +# 遍历文件名列表 +for file in solution_files: + # 使用正则表达式提取 eno 后面的数字 + match = re.search(r'eno(\d+)', file) + if match: + # 将提取的字符串添加到列表中 + extracted_numbers.append('eno' + match.group(1)) + +# 打印结果 +print("Extracted strings:", extracted_numbers) + +icount = 0 +for file in solution_files: + filename = '../' + file + x, u = read_solution_file(filename) + #print(f'{x=}') + #print(f'{u=}') + + idx = icount % num_styles + style = styles[idx] + + plt.plot(x, u, marker=style['marker'], markerfacecolor='none', linestyle=style['linestyle'], color=style['color'], markersize=5, linewidth=1, alpha=1.0, label=f'Numerical (Rusanov)') + icount += 1 + +T = 0.625 +rk = 2 +plt.legend() +plt.grid(True, color='gray', linestyle='--', linewidth=0.5, alpha=0.7) +plt.tight_layout() +plt.show() diff --git a/example/1d-linear-convection/eno/rusanov/rk2/compare/01e/plot.py b/example/1d-linear-convection/eno/rusanov/rk2/compare/01e/plot.py new file mode 100644 index 00000000..f5730ca4 --- /dev/null +++ b/example/1d-linear-convection/eno/rusanov/rk2/compare/01e/plot.py @@ -0,0 +1,101 @@ +import numpy as np +import matplotlib.pyplot as plt +import os +import re + +# 定义一个包含不同颜色、线形和标记的列表 +# 定义10种不同的样式 +styles = [ + {'color': 'black', 'linestyle': '-', 'marker': 'o'}, + {'color': 'blue', 'linestyle': '--', 'marker': 's'}, + {'color': 'black', 'linestyle': '-', 'marker': '^'}, + {'color': 'blue', 'linestyle': '--', 'marker': 'v'}, + {'color': 'black', 'linestyle': '-', 'marker': '<'}, + {'color': 'blue', 'linestyle': '--', 'marker': '>'}, + {'color': 'black', 'linestyle': '-', 'marker': 'D'}, + +] + +# 设置目录路径 +directory = '../' + +# 初始化一个空列表来存储文件名 +solution_files = [] + +# 遍历目录中的所有文件和文件夹 +for filename in os.listdir(directory): + # 检查文件名是否以 "solution" 开头,并且以 ".plt" 结尾 + if filename.startswith("solution") and filename.endswith(".plt"): + # 将匹配的文件名添加到列表中 + solution_files.append(filename) + +# 打印结果 +print("Found the following solution files:") +for file in solution_files: + print(file) + + +def read_solution_file(file_name): + x_list = [] + u_list = [] + + with open(file_name, newline='') as csvfile: + icount = 0 + for line in csvfile: + # 去除首尾空格,按连续空格分割 + row = line.strip().split() + x_list.append(row[0]) + u_list.append(row[1]) + icount += 1 + ni = icount + print("ni=",ni) + x = np.zeros( ni ) + u = np.zeros( ni ) + + for i in range(0, ni): + x[i] = float(x_list[i]) + u[i] = float(u_list[i]) + return x, u + +plt.figure("OneFLOW-CFD Solver", figsize=(10, 6)) +plt.xlabel('x') +plt.ylabel('u') + +num_files = len(solution_files) +num_styles = len(styles) + +# 初始化一个空列表来存储提取的字符串 +extracted_numbers = [] + +# 遍历文件名列表 +for file in solution_files: + # 使用正则表达式提取 eno 后面的数字 + match = re.search(r'eno(\d+)', file) + if match: + # 将提取的字符串添加到列表中 + extracted_numbers.append('eno' + match.group(1)) + +# 打印结果 +print("Extracted strings:", extracted_numbers) + +icount = 0 +for file in solution_files: + filename = '../' + file + x, u = read_solution_file(filename) + #print(f'{x=}') + #print(f'{u=}') + + idx = icount % num_styles + style = styles[idx] + label = extracted_numbers[icount] + + plt.plot(x, u, marker=style['marker'], markerfacecolor='none', linestyle=style['linestyle'], color=style['color'], \ + markersize=5, linewidth=0.5, alpha=1.0, label=f'{label}') + icount += 1 + +T = 0.625 +rk = 2 +plt.legend() +plt.grid(True, color='gray', linestyle='--', linewidth=0.5, alpha=0.7) +plt.tight_layout() +plt.show() diff --git a/example/1d-linear-convection/eno/rusanov/rk2/compare/solution_eno1.plt b/example/1d-linear-convection/eno/rusanov/rk2/compare/solution_eno1.plt new file mode 100644 index 00000000..9c29a307 --- /dev/null +++ b/example/1d-linear-convection/eno/rusanov/rk2/compare/solution_eno1.plt @@ -0,0 +1,40 @@ + 2.5000000000e-02 1.0172847538e+00 + 7.5000000000e-02 1.0093835566e+00 + 1.2500000000e-01 1.0048952587e+00 + 1.7500000000e-01 1.0024569871e+00 + 2.2500000000e-01 1.0011878202e+00 + 2.7500000000e-01 1.0005537376e+00 + 3.2500000000e-01 1.0002491893e+00 + 3.7500000000e-01 1.0001083612e+00 + 4.2500000000e-01 1.0000455791e+00 + 4.7500000000e-01 1.0000185615e+00 + 5.2500000000e-01 1.0000110718e+00 + 5.7500000000e-01 1.0000533246e+00 + 6.2500000000e-01 1.0003435803e+00 + 6.7500000000e-01 1.0015585586e+00 + 7.2500000000e-01 1.0053544574e+00 + 7.7500000000e-01 1.0148393951e+00 + 8.2500000000e-01 1.0345915475e+00 + 8.7500000000e-01 1.0698529083e+00 + 9.2500000000e-01 1.1249384959e+00 + 9.7500000000e-01 1.2014388526e+00 + 1.0250000000e+00 1.2970582836e+00 + 1.0750000000e+00 1.4056777453e+00 + 1.1250000000e+00 1.5185878862e+00 + 1.1750000000e+00 1.6262308404e+00 + 1.2250000000e+00 1.7196398026e+00 + 1.2750000000e+00 1.7911665625e+00 + 1.3250000000e+00 1.8347091333e+00 + 1.3750000000e+00 1.8459892837e+00 + 1.4250000000e+00 1.8232232496e+00 + 1.4750000000e+00 1.7679836132e+00 + 1.5250000000e+00 1.6856458907e+00 + 1.5750000000e+00 1.5848853735e+00 + 1.6250000000e+00 1.4761732748e+00 + 1.6750000000e+00 1.3697536138e+00 + 1.7250000000e+00 1.2738179197e+00 + 1.7750000000e+00 1.1934403048e+00 + 1.8250000000e+00 1.1304501300e+00 + 1.8750000000e+00 1.0840494468e+00 + 1.9250000000e+00 1.0517926754e+00 + 1.9750000000e+00 1.0305589728e+00 diff --git a/example/1d-linear-convection/eno/rusanov/rk2/compare/solution_eno2.plt b/example/1d-linear-convection/eno/rusanov/rk2/compare/solution_eno2.plt new file mode 100644 index 00000000..8d48ba6e --- /dev/null +++ b/example/1d-linear-convection/eno/rusanov/rk2/compare/solution_eno2.plt @@ -0,0 +1,40 @@ + 2.5000000000e-02 1.0003688007e+00 + 7.5000000000e-02 1.0001116883e+00 + 1.2500000000e-01 1.0000321639e+00 + 1.7500000000e-01 1.0000088307e+00 + 2.2500000000e-01 1.0000023168e+00 + 2.7500000000e-01 1.0000005820e+00 + 3.2500000000e-01 1.0000001403e+00 + 3.7500000000e-01 1.0000000325e+00 + 4.2500000000e-01 1.0000000071e+00 + 4.7500000000e-01 1.0000000022e+00 + 5.2500000000e-01 1.0000000090e+00 + 5.7500000000e-01 1.0000002296e+00 + 6.2500000000e-01 1.0000029421e+00 + 6.7500000000e-01 1.0000246760e+00 + 7.2500000000e-01 1.0001523983e+00 + 7.7500000000e-01 1.0007386256e+00 + 8.2500000000e-01 1.0029235086e+00 + 8.7500000000e-01 1.0097093676e+00 + 9.2500000000e-01 1.0275892218e+00 + 9.7500000000e-01 1.0680505074e+00 + 1.0250000000e+00 1.1473027356e+00 + 1.0750000000e+00 1.2821607336e+00 + 1.1250000000e+00 1.4814704301e+00 + 1.1750000000e+00 1.7145058209e+00 + 1.2250000000e+00 1.8675930101e+00 + 1.2750000000e+00 1.9446400283e+00 + 1.3250000000e+00 1.9720624902e+00 + 1.3750000000e+00 1.9734846527e+00 + 1.4250000000e+00 1.9638630546e+00 + 1.4750000000e+00 1.9297465149e+00 + 1.5250000000e+00 1.8538043590e+00 + 1.5750000000e+00 1.7194776176e+00 + 1.6250000000e+00 1.5184692099e+00 + 1.6750000000e+00 1.2852296623e+00 + 1.7250000000e+00 1.1369218051e+00 + 1.7750000000e+00 1.0605943690e+00 + 1.8250000000e+00 1.0248664548e+00 + 1.8750000000e+00 1.0095195511e+00 + 1.9250000000e+00 1.0034167562e+00 + 1.9750000000e+00 1.0011546935e+00 diff --git a/example/1d-linear-convection/eno/rusanov/rk2/compare/solution_eno3.plt b/example/1d-linear-convection/eno/rusanov/rk2/compare/solution_eno3.plt new file mode 100644 index 00000000..276879cd --- /dev/null +++ b/example/1d-linear-convection/eno/rusanov/rk2/compare/solution_eno3.plt @@ -0,0 +1,40 @@ + 2.5000000000e-02 1.0000273486e+00 + 7.5000000000e-02 1.0000056982e+00 + 1.2500000000e-01 1.0000011252e+00 + 1.7500000000e-01 1.0000002112e+00 + 2.2500000000e-01 1.0000000378e+00 + 2.7500000000e-01 1.0000000065e+00 + 3.2500000000e-01 1.0000000011e+00 + 3.7500000000e-01 1.0000000002e+00 + 4.2500000000e-01 1.0000000000e+00 + 4.7500000000e-01 1.0000000000e+00 + 5.2500000000e-01 1.0000000002e+00 + 5.7500000000e-01 1.0000000067e+00 + 6.2500000000e-01 1.0000001266e+00 + 6.7500000000e-01 1.0000015471e+00 + 7.2500000000e-01 1.0000137967e+00 + 7.7500000000e-01 1.0000956013e+00 + 8.2500000000e-01 1.0005350881e+00 + 8.7500000000e-01 1.0024822121e+00 + 9.2500000000e-01 1.0097146127e+00 + 9.7500000000e-01 1.0324796822e+00 + 1.0250000000e+00 1.0935883004e+00 + 1.0750000000e+00 1.2338353972e+00 + 1.1250000000e+00 1.4920508121e+00 + 1.1750000000e+00 1.7619105523e+00 + 1.2250000000e+00 1.9112085534e+00 + 1.2750000000e+00 1.9684328077e+00 + 1.3250000000e+00 1.9930432256e+00 + 1.3750000000e+00 2.0013249100e+00 + 1.4250000000e+00 1.9940382942e+00 + 1.4750000000e+00 1.9668339258e+00 + 1.5250000000e+00 1.9023474581e+00 + 1.5750000000e+00 1.7628821084e+00 + 1.6250000000e+00 1.5095639075e+00 + 1.6750000000e+00 1.2410223012e+00 + 1.7250000000e+00 1.0849832027e+00 + 1.7750000000e+00 1.0269688796e+00 + 1.8250000000e+00 1.0078451293e+00 + 1.8750000000e+00 1.0021105249e+00 + 1.9250000000e+00 1.0005286355e+00 + 1.9750000000e+00 1.0001239718e+00 diff --git a/example/1d-linear-convection/eno/rusanov/rk2/compare/solution_eno4.plt b/example/1d-linear-convection/eno/rusanov/rk2/compare/solution_eno4.plt new file mode 100644 index 00000000..018d84d5 --- /dev/null +++ b/example/1d-linear-convection/eno/rusanov/rk2/compare/solution_eno4.plt @@ -0,0 +1,40 @@ + 2.5000000000e-02 1.0000040261e+00 + 7.5000000000e-02 1.0000006378e+00 + 1.2500000000e-01 1.0000000956e+00 + 1.7500000000e-01 1.0000000136e+00 + 2.2500000000e-01 1.0000000018e+00 + 2.7500000000e-01 1.0000000002e+00 + 3.2500000000e-01 1.0000000000e+00 + 3.7500000000e-01 1.0000000000e+00 + 4.2500000000e-01 1.0000000000e+00 + 4.7500000000e-01 1.0000000000e+00 + 5.2500000000e-01 1.0000000000e+00 + 5.7500000000e-01 1.0000000005e+00 + 6.2500000000e-01 1.0000000122e+00 + 6.7500000000e-01 1.0000001963e+00 + 7.2500000000e-01 1.0000022890e+00 + 7.7500000000e-01 1.0000206338e+00 + 8.2500000000e-01 1.0001493909e+00 + 8.7500000000e-01 1.0008906352e+00 + 9.2500000000e-01 1.0044454627e+00 + 9.7500000000e-01 1.0187794871e+00 + 1.0250000000e+00 1.0675941107e+00 + 1.0750000000e+00 1.2080236482e+00 + 1.1250000000e+00 1.4928190624e+00 + 1.1750000000e+00 1.7915986725e+00 + 1.2250000000e+00 1.9387702219e+00 + 1.2750000000e+00 1.9804313030e+00 + 1.3250000000e+00 1.9957929361e+00 + 1.3750000000e+00 2.0013206212e+00 + 1.4250000000e+00 1.9969496965e+00 + 1.4750000000e+00 1.9789687982e+00 + 1.5250000000e+00 1.9285258054e+00 + 1.5750000000e+00 1.7906856887e+00 + 1.6250000000e+00 1.5097694921e+00 + 1.6750000000e+00 1.2141062951e+00 + 1.7250000000e+00 1.0610801156e+00 + 1.7750000000e+00 1.0150389100e+00 + 1.8250000000e+00 1.0033762088e+00 + 1.8750000000e+00 1.0006977668e+00 + 1.9250000000e+00 1.0001338060e+00 + 1.9750000000e+00 1.0000239578e+00 diff --git a/example/1d-linear-convection/eno/rusanov/rk2/compare/solution_eno5.plt b/example/1d-linear-convection/eno/rusanov/rk2/compare/solution_eno5.plt new file mode 100644 index 00000000..e274d8f1 --- /dev/null +++ b/example/1d-linear-convection/eno/rusanov/rk2/compare/solution_eno5.plt @@ -0,0 +1,40 @@ + 2.5000000000e-02 1.0000008930e+00 + 7.5000000000e-02 1.0000001140e+00 + 1.2500000000e-01 1.0000000138e+00 + 1.7500000000e-01 1.0000000016e+00 + 2.2500000000e-01 1.0000000002e+00 + 2.7500000000e-01 1.0000000000e+00 + 3.2500000000e-01 1.0000000000e+00 + 3.7500000000e-01 1.0000000000e+00 + 4.2500000000e-01 1.0000000000e+00 + 4.7500000000e-01 1.0000000000e+00 + 5.2500000000e-01 1.0000000000e+00 + 5.7500000000e-01 1.0000000001e+00 + 6.2500000000e-01 1.0000000019e+00 + 6.7500000000e-01 1.0000000381e+00 + 7.2500000000e-01 1.0000005486e+00 + 7.7500000000e-01 1.0000060876e+00 + 8.2500000000e-01 1.0000540628e+00 + 8.7500000000e-01 1.0003938697e+00 + 9.2500000000e-01 1.0023937294e+00 + 9.7500000000e-01 1.0122702586e+00 + 1.0250000000e+00 1.0533830874e+00 + 1.0750000000e+00 1.1951087835e+00 + 1.1250000000e+00 1.4961704041e+00 + 1.1750000000e+00 1.7988012962e+00 + 1.2250000000e+00 1.9478339847e+00 + 1.2750000000e+00 1.9932284786e+00 + 1.3250000000e+00 2.0005254393e+00 + 1.3750000000e+00 1.9996607864e+00 + 1.4250000000e+00 2.0005605514e+00 + 1.4750000000e+00 1.9943327548e+00 + 1.5250000000e+00 1.9502236559e+00 + 1.5750000000e+00 1.8011723968e+00 + 1.6250000000e+00 1.5000529372e+00 + 1.6750000000e+00 1.1943159047e+00 + 1.7250000000e+00 1.0478135256e+00 + 1.7750000000e+00 1.0095978619e+00 + 1.8250000000e+00 1.0017526365e+00 + 1.8750000000e+00 1.0002937369e+00 + 1.9250000000e+00 1.0000455696e+00 + 1.9750000000e+00 1.0000065892e+00 diff --git a/example/1d-linear-convection/eno/rusanov/rk2/compare/solution_eno6.plt b/example/1d-linear-convection/eno/rusanov/rk2/compare/solution_eno6.plt new file mode 100644 index 00000000..094159b0 --- /dev/null +++ b/example/1d-linear-convection/eno/rusanov/rk2/compare/solution_eno6.plt @@ -0,0 +1,40 @@ + 2.5000000000e-02 1.0000002599e+00 + 7.5000000000e-02 1.0000000277e+00 + 1.2500000000e-01 1.0000000028e+00 + 1.7500000000e-01 1.0000000003e+00 + 2.2500000000e-01 1.0000000000e+00 + 2.7500000000e-01 1.0000000000e+00 + 3.2500000000e-01 1.0000000000e+00 + 3.7500000000e-01 1.0000000000e+00 + 4.2500000000e-01 1.0000000000e+00 + 4.7500000000e-01 1.0000000000e+00 + 5.2500000000e-01 1.0000000000e+00 + 5.7500000000e-01 1.0000000000e+00 + 6.2500000000e-01 1.0000000004e+00 + 6.7500000000e-01 1.0000000098e+00 + 7.2500000000e-01 1.0000001682e+00 + 7.7500000000e-01 1.0000022168e+00 + 8.2500000000e-01 1.0000233213e+00 + 8.7500000000e-01 1.0002007205e+00 + 9.2500000000e-01 1.0014368137e+00 + 9.7500000000e-01 1.0086483119e+00 + 1.0250000000e+00 1.0440552256e+00 + 1.0750000000e+00 1.1845717739e+00 + 1.1250000000e+00 1.5011326293e+00 + 1.1750000000e+00 1.8117137920e+00 + 1.2250000000e+00 1.9530275553e+00 + 1.2750000000e+00 1.9946120500e+00 + 1.3250000000e+00 2.0008235251e+00 + 1.3750000000e+00 1.9995200414e+00 + 1.4250000000e+00 2.0006979211e+00 + 1.4750000000e+00 1.9963587577e+00 + 1.5250000000e+00 1.9569825550e+00 + 1.5750000000e+00 1.8128165404e+00 + 1.6250000000e+00 1.5016660485e+00 + 1.6750000000e+00 1.1836684523e+00 + 1.7250000000e+00 1.0400748989e+00 + 1.7750000000e+00 1.0067631791e+00 + 1.8250000000e+00 1.0010363227e+00 + 1.8750000000e+00 1.0001456524e+00 + 1.9250000000e+00 1.0000189334e+00 + 1.9750000000e+00 1.0000022922e+00 diff --git a/example/1d-linear-convection/eno/rusanov/rk2/compare/solution_eno7.plt b/example/1d-linear-convection/eno/rusanov/rk2/compare/solution_eno7.plt new file mode 100644 index 00000000..73cec199 --- /dev/null +++ b/example/1d-linear-convection/eno/rusanov/rk2/compare/solution_eno7.plt @@ -0,0 +1,40 @@ + 2.5000000000e-02 1.0000000906e+00 + 7.5000000000e-02 1.0000000083e+00 + 1.2500000000e-01 1.0000000007e+00 + 1.7500000000e-01 1.0000000001e+00 + 2.2500000000e-01 1.0000000000e+00 + 2.7500000000e-01 1.0000000000e+00 + 3.2500000000e-01 1.0000000000e+00 + 3.7500000000e-01 1.0000000000e+00 + 4.2500000000e-01 1.0000000000e+00 + 4.7500000000e-01 1.0000000000e+00 + 5.2500000000e-01 1.0000000000e+00 + 5.7500000000e-01 1.0000000000e+00 + 6.2500000000e-01 1.0000000001e+00 + 6.7500000000e-01 1.0000000031e+00 + 7.2500000000e-01 1.0000000615e+00 + 7.7500000000e-01 1.0000009407e+00 + 8.2500000000e-01 1.0000114765e+00 + 8.7500000000e-01 1.0001143335e+00 + 9.2500000000e-01 1.0009438693e+00 + 9.7500000000e-01 1.0065101112e+00 + 1.0250000000e+00 1.0376199830e+00 + 1.0750000000e+00 1.1726776733e+00 + 1.1250000000e+00 1.4922862541e+00 + 1.1750000000e+00 1.8229424394e+00 + 1.2250000000e+00 1.9686520060e+00 + 1.2750000000e+00 1.9980959374e+00 + 1.3250000000e+00 2.0002057330e+00 + 1.3750000000e+00 1.9998805513e+00 + 1.4250000000e+00 2.0001769367e+00 + 1.4750000000e+00 1.9992143984e+00 + 1.5250000000e+00 1.9724807542e+00 + 1.5750000000e+00 1.8270584852e+00 + 1.6250000000e+00 1.4935177637e+00 + 1.6750000000e+00 1.1688012309e+00 + 1.7250000000e+00 1.0331839378e+00 + 1.7750000000e+00 1.0048865110e+00 + 1.8250000000e+00 1.0006496729e+00 + 1.8750000000e+00 1.0000790337e+00 + 1.9250000000e+00 1.0000088757e+00 + 1.9750000000e+00 1.0000009268e+00 diff --git a/example/1d-linear-convection/eno/rusanov/rk2/eno1-7/01/eno.py b/example/1d-linear-convection/eno/rusanov/rk2/eno1-7/01/eno.py new file mode 100644 index 00000000..b9bda0d6 --- /dev/null +++ b/example/1d-linear-convection/eno/rusanov/rk2/eno1-7/01/eno.py @@ -0,0 +1,360 @@ +import numpy as np +import matplotlib.pyplot as plt + +# 初始条件 +def initial_condition(x): + u0 = np.zeros_like(x) + for i in range(len(x)): + if 0.5 <= x[i] <= 1.0: + u0[i] = 2.0 + else: + u0[i] = 1.0 + return u0 + +# 理论解 +def analytical_solution(x, t, a, L): + # 初始条件沿 x - at 平移 + x_shifted = x - a * t + return initial_condition((x_shifted + L) % L) # 周期边界条件 + +def residual(q, eno): + reconstruction(q, eno) + inviscid_flux(eno.up1_2m, eno.up1_2p, eno.flux, eno) + for i in range(eno.nx): + eno.res[i] = -(eno.flux[i + 1] - eno.flux[i]) / eno.mesh.dx + +def reconstruction(q, eno): + # Choose the stencil by ENO method + eno.dd[0, 0:eno.ntcell-1] = q[0:eno.ntcell-1] + + for m in range(1, eno.iorder): + for j in range(0, eno.ntcell-1): + eno.dd[m, j] = eno.dd[m-1, j+1] - eno.dd[m-1, j] + + for i in range(eno.nx + 1): + eno.il[i] = i - 1 + for m in range(1, eno.iorder): + if abs(eno.dd[m, eno.il[i]-1+eno.ishift]) <= abs(eno.dd[m, eno.il[i]+eno.ishift]): + eno.il[i] -= 1 + + for i in range(eno.nx + 1): + eno.ir[i] = i + for m in range(1, eno.iorder): + if abs(eno.dd[m, eno.ir[i]-1+eno.ishift]) <= abs(eno.dd[m, eno.ir[i]+eno.ishift]): + eno.ir[i] -= 1 + + # Reconstruction u(j+1/2) + for i in range(eno.nx + 1): + k1 = eno.il[i] + k2 = eno.ir[i] + l1 = i - k1 + l2 = i - k2 + eno.up1_2m[i] = 0 + eno.up1_2p[i] = 0 + for m in range(eno.iorder): + eno.up1_2m[i] += q[k1 + eno.ishift + m] * eno.coef[l1, m] + eno.up1_2p[i] += q[k2 + eno.ishift + m] * eno.coef[l2, m] + +fluxnames = [ + 'Rusanov', + 'Engquist-Osher', +] + +def inviscid_flux(up1_2m, up1_2p, flux, eno): + if eno.solver.iflux == 0: + rusanov_flux(up1_2m, up1_2p, flux, eno) + else: + engquist_osher_flux(up1_2m, up1_2p, flux, eno) + +def engquist_osher_flux(up1_2m, up1_2p, flux, eno): + for i in range(eno.nx + 1): + u_L = up1_2m[i] + u_R = up1_2p[i] + + cp = 0.5 * ( eno.solver.c + abs(eno.solver.c) ) + cm = 0.5 * ( eno.solver.c - abs(eno.solver.c) ) + + flux[i] = cp * u_L + cm * u_R + +def rusanov_flux(up1_2m, up1_2p, flux, eno): + for i in range(eno.nx + 1): + u_L = up1_2m[i] + u_R = up1_2p[i] + F_L = eno.solver.c * u_L # 左状态通量 + F_R = eno.solver.c * u_R # 右状态通量 + alpha = abs(eno.solver.c) # 最大波速 + flux[i] = 0.5 * (F_L + F_R) - 0.5 * alpha * (u_R - u_L) + + +def boundary(u, eno): + for i in range(-eno.ighost, 1): + u[eno.ist - 1 + i] = u[eno.ied + i] + for i in range(1, eno.ighost + 2): + u[eno.ied + i] = u[eno.ist - 1 + i] + +def update_oldfield(qn, q): + qn[:] = q[:] + +def init_coef( iorder, coef ): + if iorder == 1: + coef[0] = [1.0] + coef[1] = [1.0] + elif iorder == 2: + coef[0] = [3.0/2.0, -1.0/2.0] + coef[1] = [1.0/2.0, 1.0/2.0] + coef[2] = [-1.0/2.0, 3.0/2.0] + elif iorder == 3: + coef[0] = [ 11.0/6.0, -7.0/6.0, 1.0/3.0 ] + coef[1] = [ 1.0/3.0, 5.0/6.0, -1.0/6.0 ] + coef[2] = [ -1.0/6.0, 5.0/6.0, 1.0/3.0 ] + coef[3] = [ 1.0/3.0, -7.0/6.0, 11.0/6.0 ] + elif iorder == 4: + coef[0] = [ 25.0/12.0, -23.0/12.0, 13.0/12.0, -1.0/4.0 ] + coef[1] = [ 1.0/4.0, 13.0/12.0, -5.0/12.0, 1.0/12.0 ] + coef[2] = [ -1.0/12.0, 7.0/12.0, 7.0/12.0, -1.0/12.0 ] + coef[3] = [ 1.0/12.0, -5.0/12.0, 13.0/12.0, 1.0/4.0 ] + coef[4] = [ -1.0/4.0, 13.0/12.0, -23.0/12.0, 25.0/12.0 ] + elif iorder == 5: + coef[0] = [ 137.0/60.0, -163.0/60.0, 137.0/60.0, -21.0/20.0, 1.0/5.0 ] + coef[1] = [ 1.0/5.0, 77.0/60.0, -43.0/60.0, 17.0/60.0, -1.0/20.0 ] + coef[2] = [ -1.0/20.0, 9.0/20.0, 47.0/60.0, -13.0/60.0, 1.0/30.0 ] + coef[3] = [ 1.0/30.0, -13.0/60.0, 47.0/60.0, 9.0/20.0, -1.0/20.0 ] + coef[4] = [ -1.0/20.0, 17.0/60.0, -43.0/60.0, 77.0/60.0, 1.0/5.0 ] + coef[5] = [ 1.0/5.0, -21.0/20.0, 137.0/60.0, -163.0/60.0, 137.0/60.0 ] + elif iorder == 6: + coef[0] = [ 49.0/20.0, -71.0/20.0, 79.0/20.0, -163.0/60.0, 31.0/30.0, -1.0/6.0 ] + coef[1] = [ 1.0/6.0, 29.0/20.0, -21.0/20.0, 37.0/60.0, -13.0/60.0, 1.0/30.0 ] + coef[2] = [ -1.0/30.0, 11.0/30.0, 19.0/20.0, -23.0/60.0, 7.0/60.0, -1.0/60.0 ] + coef[3] = [ 1.0/60.0, -2.0/15.0, 37.0/60.0, 37.0/60.0, -2.0/15.0, 1.0/60.0 ] + coef[4] = [ -1.0/60.0, 7.0/60.0, -23.0/60.0, 19.0/20.0, 11.0/30.0, -1.0/30.0 ] + coef[5] = [ 1.0/30.0, -13.0/60.0, 37.0/60.0, -21.0/20.0, 29.0/20.0, 1.0/6.0 ] + coef[6] = [ -1.0/6.0, 31.0/30.0, -163.0/60.0, 79.0/20.0, -71.0/20.0, 49.0/20.0 ] + elif iorder == 7: + coef[0] = [ 363.0/140.0, -617.0/140.0, 853.0/140.0, -2341.0/420.0, 667.0/210.0, -43.0/42.0, 1.0/7.0 ] + coef[1] = [ 1.0/7.0, 223.0/140.0, -197.0/140.0, 153.0/140.0, -241.0/420.0, 37.0/210.0, -1.0/42.0 ] + coef[2] = [ -1.0/42.0, 13.0/42.0, 153.0/140.0, -241.0/420.0, 109.0/420.0, -31.0/420.0, 1.0/105.0 ] + coef[3] = [ 1.0/105.0, -19.0/210.0, 107.0/210.0, 319.0/420.0, -101.0/420.0, 5.0/84.0, -1.0/140.0 ] + coef[4] = [ -1.0/140.0, 5.0/84.0, -101.0/420.0, 319.0/420.0, 107.0/210.0, -19.0/210.0, 1.0/105.0 ] + coef[5] = [ 1.0/105.0, -31.0/420.0, 109.0/420.0, -241.0/420.0, 153.0/140.0, 13.0/42.0, -1.0/42.0 ] + coef[6] = [ -1.0/42.0, 37.0/210.0, -241.0/420.0, 153.0/140.0, -197.0/140.0, 223.0/140.0, 1.0/7.0 ] + coef[7] = [ 1.0/7.0, -43.0/42.0, 667.0/210.0, -2341.0/420.0, 853.0/140.0, -617.0/140.0, 363.0/140.0 ] + +def init_field(eno): + for i in range(eno.ist, eno.ied + 1): + j = i - eno.ist + if 0.5 <= eno.mesh.xcc[j] <= 1.0: + eno.u[i] = 2.0 + else: + eno.u[i] = 1.0 + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def runge_kutta(eno): + rk = eno.solver.rk + if rk == 1: + runge_kutta_1(eno) + elif rk == 2: + runge_kutta_2(eno) + else: + runge_kutta_3(eno) + +def runge_kutta_1(eno): + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = eno.u[j] + eno.dt * eno.res[i] + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def runge_kutta_2(eno): + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = eno.u[j] + eno.dt * eno.res[i] + boundary(eno.u, eno) + + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = 0.5 * eno.un[j] + 0.5 * eno.u[j] + 0.5 * eno.dt * eno.res[i] + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def runge_kutta_3(eno): + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = eno.u[j] + eno.dt * eno.res[i] + boundary(eno.u, eno) + + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = 0.75 * eno.un[j] + 0.25 * eno.u[j] + 0.25 * eno.dt * eno.res[i] + boundary(eno.u, eno) + + residual(eno.u, eno) + c1, c2, c3 = 1.0/3.0, 2.0/3.0, 2.0/3.0 + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = c1 * eno.un[j] + c2 * eno.u[j] + c3 * eno.dt * eno.res[i] + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def get_ordinal_numbers(order): + if order == 1: + return 'st' + elif order == 2: + return 'nd' + elif order == 3: + return 'rd' + else: + return 'th' + +def visualize(eno): + with open('solution.plt', 'w') as f: + for i in range(eno.ist, eno.ied + 1): + j = i - eno.ist + f.write(f"{eno.xcc[j]:20.10e}{eno.u[i]:20.10e}\n") + + # 可视化 + u_numerical = np.copy(eno.u[eno.ist:eno.ied+1]) + print(f'u_numerical.size={u_numerical.size}') + print(f'eno.xcc.size={eno.xcc.size}') + #计算理论解 + u_analytical = analytical_solution(eno.mesh.xcc, eno.T, eno.c, eno.L) + print(f'u_analytical.size={u_analytical.size}') + plt.figure("OneFLOW-CFD Solver", figsize=(10, 6)) + plt.scatter(eno.xcc, u_numerical, facecolor="none", edgecolor="blue", s=20, linewidths=0.5, label=f'Numerical (Rusanov)') + plt.plot(eno.xcc, u_analytical, 'r--', label='Analytical') + plt.xlabel('x') + plt.ylabel('u') + ordinal1 = get_ordinal_numbers(eno.iorder) + ordinal2 = get_ordinal_numbers(eno.rk) + plt.title(f'1D Convection Equation at t = {eno.T:.3f} using {eno.iorder}{ordinal1}-order ENO and {eno.rk}{ordinal2}-order Runge-Kutta methods') + plt.legend() + plt.grid(True, color='gray', linestyle='--', linewidth=0.5, alpha=0.7) + plt.tight_layout() + plt.show() + +class Mesh: + def __init__(self): + self.nx = 40 + self.L = 2.0 + self.x = np.zeros(self.nx + 1) + self.xcc = np.zeros(self.nx) + self.init_mesh() + def init_mesh(self): + xstart = 0.0 + xend = self.L + self.dx = (xend - xstart) / self.nx + + for i in range(0, self.nx+1): + self.x[i] = xstart + i * self.dx + + for i in range(0, self.nx): + self.xcc[i] = 0.5 * (self.x[i] + self.x[i + 1]) + +class Solver: + def __init__(self): + self.iflux = 0 + self.rk = 2 + self.c = 1.0 + self.T = 0.625 + +class Eno: + def __init__(self, solver, mesh, iorder): + self.solver = solver + self.mesh = mesh + self.nx = mesh.nx + self.iorder = iorder + self.ighost = iorder + self.ishift = self.ighost + 1 + self.ist = 0 + self.ishift + self.ied = self.nx - 1 + self.ishift + self.ntcell = self.nx + 2 * self.ishift + self.isize = iorder * (iorder + 1) + + self.il = np.zeros(self.nx + 1, dtype=int) + self.ir = np.zeros(self.nx + 1, dtype=int) + self.coef = np.zeros((iorder + 1, iorder)) + self.dd = np.zeros((iorder, self.ntcell)) + self.up1_2m = np.zeros(self.nx + 1) + self.up1_2p = np.zeros(self.nx + 1) + self.flux = np.zeros(self.nx + 1) + self.res = np.zeros(self.nx) + + # Field module variables + self.u = np.zeros(self.ntcell) + self.un = np.zeros(self.ntcell) + + self.dt = .0025 + +def plot_eno_field(solver, xcc, u_list, u_analytical): + # 定义一个包含不同颜色、线形和标记的列表 + styles = [ + {'color': 'black', 'linestyle': '-', 'marker': 'o'}, + {'color': 'blue', 'linestyle': '--', 'marker': 's'}, + {'color': 'black', 'linestyle': '-', 'marker': '^'}, + {'color': 'blue', 'linestyle': '--', 'marker': 'v'}, + {'color': 'black', 'linestyle': '-', 'marker': '<'}, + {'color': 'blue', 'linestyle': '--', 'marker': '>'}, + {'color': 'black', 'linestyle': '-', 'marker': 'D'}, + ] + + n = len(u_list) + num_styles = len(styles) + ordinal = get_ordinal_numbers(solver.rk) + + plt.figure("OneFLOW-CFD Solver", figsize=(10, 6)) + plt.title(f'1D Convection Equation at t = {solver.T:.3f} using [1-7]th-order ENO and {solver.rk}{ordinal}-order Runge-Kutta methods') + for i in range(0, n): + lable = 'Numerical (Rusanov)ENO' + str(i+1) + style = styles[i % num_styles] + plt.plot(xcc, u_list[i], marker=style['marker'], markerfacecolor='none', linestyle=style['linestyle'], color=style['color'], \ + markersize=5, linewidth=0.5, alpha=1.0, label=f'{lable}') + plt.plot(xcc, u_analytical, 'r--', label='Analytical') + plt.xlabel('x') + plt.ylabel('u') + plt.legend() + plt.grid(True, color='gray', linestyle='--', linewidth=0.5, alpha=0.7) + plt.tight_layout() + plt.show() + +def RunEno(solver, mesh, iorder): + eno = Eno(solver, mesh, iorder) + init_coef(eno.iorder, eno.coef) + init_field(eno) + + simu_time = solver.T + t = 0.0 + dt = eno.dt + while t < simu_time: + runge_kutta(eno) + if t + dt > simu_time: + dt = simu_time - t + t += dt + print(f'T={t:.3f},runge_kutta{solver.rk},ENO{eno.iorder},{fluxnames[solver.iflux]} FLUX') + #visualize(eno) + return np.copy(eno.u[eno.ist:eno.ied+1]) + +def performEnoOrderAnalysis(): + iorder_max = 7 + mesh = Mesh() + solver = Solver() + #计算理论解 + u_analytical = analytical_solution(mesh.xcc, solver.T, solver.c, mesh.L) + + u_list = [] + for iorder in range(1, iorder_max+1): + u = RunEno(solver, mesh, iorder) + u_list.append(u) + + plot_eno_field(solver, mesh.xcc, u_list, u_analytical) + +def main(): + performEnoOrderAnalysis() + + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/example/1d-linear-convection/eno/rusanov/rk2/eno1-7/01/plot.py b/example/1d-linear-convection/eno/rusanov/rk2/eno1-7/01/plot.py new file mode 100644 index 00000000..e389044c --- /dev/null +++ b/example/1d-linear-convection/eno/rusanov/rk2/eno1-7/01/plot.py @@ -0,0 +1,53 @@ +import numpy as np +import matplotlib.pyplot as plt +import csv +import sys + +nvar = len(sys.argv) +print('nvar=',nvar) +print('sys.argv=',sys.argv) + +order = 1 +if nvar >= 2: + var = sys.argv[1] + print('var=',var) + order = int(var) + +print('order=',order) + +x_list = [] +u_list = [] + +with open('solution.plt', newline='') as csvfile: + #readCSV = csv.reader(csvfile, delimiter= ' ') + icount = 0 + for line in csvfile: + # 去除首尾空格,按连续空格分割 + row = line.strip().split() + #print("row=",row) + x_list.append(row[0]) + u_list.append(row[1]) + icount += 1 + +ni = icount +print("ni=",ni) + +#print("x_list=",x_list) + +x = np.zeros( ni ) +u = np.zeros( ni ) + +for i in range(0, ni): + x[i] = float(x_list[i]) + u[i] = float(u_list[i]) + +labelname = 'Eno' + str(order) + +plt.figure("OneFLOW-CFD Solver", figsize=(8, 6), dpi=100) +plt.plot(x, u, "b-", linewidth=1.0, marker = 's', markerfacecolor='None', label=labelname) +plt.xlabel("$x$") +plt.ylabel("$u$") +plt.title("burgers T=1") +plt.legend() +plt.tight_layout() +plt.show(); \ No newline at end of file diff --git a/example/1d-linear-convection/eno/rusanov/rk2/eno1/01/eno.py b/example/1d-linear-convection/eno/rusanov/rk2/eno1/01/eno.py new file mode 100644 index 00000000..60802970 --- /dev/null +++ b/example/1d-linear-convection/eno/rusanov/rk2/eno1/01/eno.py @@ -0,0 +1,311 @@ +import numpy as np +import matplotlib.pyplot as plt + +# 初始条件 +def initial_condition(x): + u0 = np.zeros_like(x) + for i in range(len(x)): + if 0.5 <= x[i] <= 1.0: + u0[i] = 2.0 + else: + u0[i] = 1.0 + return u0 + +# 理论解 +def analytical_solution(x, t, a): + # 初始条件沿 x - at 平移 + x_shifted = x - a * t + return initial_condition((x_shifted + L) % L) # 周期边界条件 + +def residual(q): + reconstruction(q) + inviscid_flux(up1_2m, up1_2p, flux) + for i in range(nx): + res[i] = -(flux[i + 1] - flux[i]) / dx + +def reconstruction(q): + global il, ir, dd, up1_2m, up1_2p + + # Choose the stencil by ENO method + dd[0, 0:ntcell-1] = q[0:ntcell-1] + + for m in range(1, iorder): + for j in range(0, ntcell-1): + dd[m, j] = dd[m-1, j+1] - dd[m-1, j] + + for i in range(nx + 1): + il[i] = i - 1 + for m in range(1, iorder): + if abs(dd[m, il[i]-1+ishift]) <= abs(dd[m, il[i]+ishift]): + il[i] -= 1 + + for i in range(nx + 1): + ir[i] = i + for m in range(1, iorder): + if abs(dd[m, ir[i]-1+ishift]) <= abs(dd[m, ir[i]+ishift]): + ir[i] -= 1 + + # Reconstruction u(j+1/2) + for i in range(nx + 1): + k1 = il[i] + k2 = ir[i] + l1 = i - k1 + l2 = i - k2 + up1_2m[i] = 0 + up1_2p[i] = 0 + for m in range(iorder): + up1_2m[i] += q[k1 + ishift + m] * coef[l1, m] + up1_2p[i] += q[k2 + ishift + m] * coef[l2, m] + +def inviscid_flux(up1_2m, up1_2p, flux): + iflux = 0 + if iflux == 0: + rusanov_flux(up1_2m, up1_2p, flux) + else: + engquist_osher_flux(up1_2m, up1_2p, flux) + +def engquist_osher_flux(up1_2m, up1_2p, flux): + for i in range(nx + 1): + u_L = up1_2m[i] + u_R = up1_2p[i] + + cp = 0.5 * ( c + abs(c) ) + cm = 0.5 * ( c - abs(c) ) + + flux[i] = cp * uL + cm * u_R + +def rusanov_flux(up1_2m, up1_2p, flux): + for i in range(nx + 1): + u_L = up1_2m[i] + u_R = up1_2p[i] + F_L = c * u_L # 左状态通量 + F_R = c * u_R # 右状态通量 + alpha = abs(c) # 最大波速 + flux[i] = 0.5 * (F_L + F_R) - 0.5 * alpha * (u_R - u_L) + + +def boundary(u): + for i in range(-ighost, 1): + u[ist - 1 + i] = u[ied + i] + for i in range(1, ighost + 2): + u[ied + i] = u[ist - 1 + i] + +def update_oldfield(qn, q): + qn[:] = q[:] + +def init_coef(): + global coef + if iorder == 1: + coef[0] = [1.0] + coef[1] = [1.0] + elif iorder == 2: + coef[0] = [3.0/2.0, -1.0/2.0] + coef[1] = [1.0/2.0, 1.0/2.0] + coef[2] = [-1.0/2.0, 3.0/2.0] + elif iorder == 3: + coef[0] = [ 11.0/6.0, -7.0/6.0, 1.0/3.0 ] + coef[1] = [ 1.0/3.0, 5.0/6.0, -1.0/6.0 ] + coef[2] = [ -1.0/6.0, 5.0/6.0, 1.0/3.0 ] + coef[3] = [ 1.0/3.0, -7.0/6.0, 11.0/6.0 ] + elif iorder == 4: + coef[0] = [ 25.0/12.0, -23.0/12.0, 13.0/12.0, -1.0/4.0 ] + coef[1] = [ 1.0/4.0, 13.0/12.0, -5.0/12.0, 1.0/12.0 ] + coef[2] = [ -1.0/12.0, 7.0/12.0, 7.0/12.0, -1.0/12.0 ] + coef[3] = [ 1.0/12.0, -5.0/12.0, 13.0/12.0, 1.0/4.0 ] + coef[4] = [ -1.0/4.0, 13.0/12.0, -23.0/12.0, 25.0/12.0 ] + elif iorder == 5: + coef[0] = [ 137.0/60.0, -163.0/60.0, 137.0/60.0, -21.0/20.0, 1.0/5.0 ] + coef[1] = [ 1.0/5.0, 77.0/60.0, -43.0/60.0, 17.0/60.0, -1.0/20.0 ] + coef[2] = [ -1.0/20.0, 9.0/20.0, 47.0/60.0, -13.0/60.0, 1.0/30.0 ] + coef[3] = [ 1.0/30.0, -13.0/60.0, 47.0/60.0, 9.0/20.0, -1.0/20.0 ] + coef[4] = [ -1.0/20.0, 17.0/60.0, -43.0/60.0, 77.0/60.0, 1.0/5.0 ] + coef[5] = [ 1.0/5.0, -21.0/20.0, 137.0/60.0, -163.0/60.0, 137.0/60.0 ] + elif iorder == 6: + coef[0] = [ 49.0/20.0, -71.0/20.0, 79.0/20.0, -163.0/60.0, 31.0/30.0, -1.0/6.0 ] + coef[1] = [ 1.0/6.0, 29.0/20.0, -21.0/20.0, 37.0/60.0, -13.0/60.0, 1.0/30.0 ] + coef[2] = [ -1.0/30.0, 11.0/30.0, 19.0/20.0, -23.0/60.0, 7.0/60.0, -1.0/60.0 ] + coef[3] = [ 1.0/60.0, -2.0/15.0, 37.0/60.0, 37.0/60.0, -2.0/15.0, 1.0/60.0 ] + coef[4] = [ -1.0/60.0, 7.0/60.0, -23.0/60.0, 19.0/20.0, 11.0/30.0, -1.0/30.0 ] + coef[5] = [ 1.0/30.0, -13.0/60.0, 37.0/60.0, -21.0/20.0, 29.0/20.0, 1.0/6.0 ] + coef[6] = [ -1.0/6.0, 31.0/30.0, -163.0/60.0, 79.0/20.0, -71.0/20.0, 49.0/20.0 ] + elif iorder == 7: + coef[0] = [ 363.0/140.0, -617.0/140.0, 853.0/140.0, -2341.0/420.0, 667.0/210.0, -43.0/42.0, 1.0/7.0 ] + coef[1] = [ 1.0/7.0, 223.0/140.0, -197.0/140.0, 153.0/140.0, -241.0/420.0, 37.0/210.0, -1.0/42.0 ] + coef[2] = [ -1.0/42.0, 13.0/42.0, 153.0/140.0, -241.0/420.0, 109.0/420.0, -31.0/420.0, 1.0/105.0 ] + coef[3] = [ 1.0/105.0, -19.0/210.0, 107.0/210.0, 319.0/420.0, -101.0/420.0, 5.0/84.0, -1.0/140.0 ] + coef[4] = [ -1.0/140.0, 5.0/84.0, -101.0/420.0, 319.0/420.0, 107.0/210.0, -19.0/210.0, 1.0/105.0 ] + coef[5] = [ 1.0/105.0, -31.0/420.0, 109.0/420.0, -241.0/420.0, 153.0/140.0, 13.0/42.0, -1.0/42.0 ] + coef[6] = [ -1.0/42.0, 37.0/210.0, -241.0/420.0, 153.0/140.0, -197.0/140.0, 223.0/140.0, 1.0/7.0 ] + coef[7] = [ 1.0/7.0, -43.0/42.0, 667.0/210.0, -2341.0/420.0, 853.0/140.0, -617.0/140.0, 363.0/140.0 ] + +def init_mesh(): + global xstart, xend, dx, x, xcc + xstart = 0.0 + xend = L + dx = (xend - xstart) / nx + + for i in range(0, nx+1): + x[i] = xstart + i * dx + + for i in range(0, nx): + xcc[i] = 0.5 * (x[i] + x[i + 1]) + +def init_field(): + global u, un + for i in range(ist, ied + 1): + j = i - ist + if 0.5 <= xcc[j] <= 1.0: + u[i] = 2.0 + else: + u[i] = 1.0 + boundary(u) + update_oldfield(un, u) + +def runge_kutta(): + if rk == 1: + runge_kutta_1() + elif rk == 2: + runge_kutta_2() + else: + runge_kutta_3() + +def runge_kutta_1(): + global u, un, dt + residual(u) + for i in range(nx): + j = i + ishift + u[j] = u[j] + dt * res[i] + boundary(u) + update_oldfield(un, u) + +def runge_kutta_2(): + global u, un, dt + residual(u) + for i in range(nx): + j = i + ishift + u[j] = u[j] + dt * res[i] + boundary(u) + + residual(u) + for i in range(nx): + j = i + ishift + u[j] = 0.5 * un[j] + 0.5 * u[j] + 0.5 * dt * res[i] + boundary(u) + update_oldfield(un, u) + +def runge_kutta_3(): + global u, un, dt + residual(u) + for i in range(nx): + j = i + ishift + u[j] = u[j] + dt * res[i] + boundary(u) + + residual(u) + for i in range(nx): + j = i + ishift + u[j] = 0.75 * un[j] + 0.25 * u[j] + 0.25 * dt * res[i] + boundary(u) + + residual(u) + c1, c2, c3 = 1.0/3.0, 2.0/3.0, 2.0/3.0 + for i in range(nx): + j = i + ishift + u[j] = c1 * un[j] + c2 * u[j] + c3 * dt * res[i] + boundary(u) + update_oldfield(un, u) + +def get_ordinal_numbers(order): + if order == 1: + return 'st' + elif order == 2: + return 'nd' + elif order == 3: + return 'rd' + else: + return 'th' + +def visualize(): + with open('solution.plt', 'w') as f: + for i in range(ist, ied + 1): + j = i - ist + f.write(f"{xcc[j]:20.10e}{u[i]:20.10e}\n") + + # 可视化 + u_numerical = np.copy(u[ist:ied+1]) + print(f'u_numerical.size={u_numerical.size}') + print(f'xcc.size={xcc.size}') + #计算理论解 + u_analytical = analytical_solution(xcc, T, c) + print(f'u_analytical.size={u_analytical.size}') + plt.figure("OneFLOW-CFD Solver", figsize=(10, 6)) + plt.scatter(xcc, u_numerical, facecolor="none", edgecolor="blue", s=20, linewidths=0.5, label=f'Numerical (Rusanov)') + plt.plot(xcc, u_analytical, 'r--', label='Analytical') + plt.xlabel('x') + plt.ylabel('u') + ordinal1 = get_ordinal_numbers(iorder) + ordinal2 = get_ordinal_numbers(rk) + plt.title(f'1D Convection Equation at t = {T:.3f} using {iorder}{ordinal1}-order ENO and {rk}{ordinal2}-order Runge-Kutta methods') + plt.legend() + plt.grid(True, color='gray', linestyle='--', linewidth=0.5, alpha=0.7) + plt.tight_layout() + plt.show() + +# Global constants and variables +nx = 40 +rk = 2 +iorder = 1 +ighost = iorder +ishift = ighost + 1 +ist = 0 + ishift +ied = nx - 1 + ishift +ntcell = nx + 2 * ishift +isize = iorder * (iorder + 1) + +il = np.zeros(nx + 1, dtype=int) +ir = np.zeros(nx + 1, dtype=int) +coef = np.zeros((iorder + 1, iorder)) +dd = np.zeros((iorder, ntcell)) +up1_2m = np.zeros(nx + 1) +up1_2p = np.zeros(nx + 1) +flux = np.zeros(nx + 1) +res = np.zeros(nx) +dt = 0.0 + +# Mesh module variables +xstart = 0.0 +xend = 0.0 +L = 2.0 +dx = 0.0 +x = np.zeros(nx + 1) +xcc = np.zeros(nx) + +# Field module variables +u = np.zeros(ntcell) +un = np.zeros(ntcell) + +def main(): + global dt, T, c + init_coef() + init_mesh() + init_field() + + c = 1.0 + T = 0.625 + dt = .0025 + nt = int(T / dt) + simu_time = T + + t = 0.0 + + while t < simu_time: + runge_kutta() + t += dt + if t + dt > simu_time: + dt = simu_time - t + + print(t) + visualize() + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/example/1d-linear-convection/eno/rusanov/rk2/eno1/01/plot.py b/example/1d-linear-convection/eno/rusanov/rk2/eno1/01/plot.py new file mode 100644 index 00000000..e389044c --- /dev/null +++ b/example/1d-linear-convection/eno/rusanov/rk2/eno1/01/plot.py @@ -0,0 +1,53 @@ +import numpy as np +import matplotlib.pyplot as plt +import csv +import sys + +nvar = len(sys.argv) +print('nvar=',nvar) +print('sys.argv=',sys.argv) + +order = 1 +if nvar >= 2: + var = sys.argv[1] + print('var=',var) + order = int(var) + +print('order=',order) + +x_list = [] +u_list = [] + +with open('solution.plt', newline='') as csvfile: + #readCSV = csv.reader(csvfile, delimiter= ' ') + icount = 0 + for line in csvfile: + # 去除首尾空格,按连续空格分割 + row = line.strip().split() + #print("row=",row) + x_list.append(row[0]) + u_list.append(row[1]) + icount += 1 + +ni = icount +print("ni=",ni) + +#print("x_list=",x_list) + +x = np.zeros( ni ) +u = np.zeros( ni ) + +for i in range(0, ni): + x[i] = float(x_list[i]) + u[i] = float(u_list[i]) + +labelname = 'Eno' + str(order) + +plt.figure("OneFLOW-CFD Solver", figsize=(8, 6), dpi=100) +plt.plot(x, u, "b-", linewidth=1.0, marker = 's', markerfacecolor='None', label=labelname) +plt.xlabel("$x$") +plt.ylabel("$u$") +plt.title("burgers T=1") +plt.legend() +plt.tight_layout() +plt.show(); \ No newline at end of file diff --git a/example/1d-linear-convection/eno/rusanov/rk2/eno2/01/eno.py b/example/1d-linear-convection/eno/rusanov/rk2/eno2/01/eno.py new file mode 100644 index 00000000..40a1f8c6 --- /dev/null +++ b/example/1d-linear-convection/eno/rusanov/rk2/eno2/01/eno.py @@ -0,0 +1,311 @@ +import numpy as np +import matplotlib.pyplot as plt + +# 初始条件 +def initial_condition(x): + u0 = np.zeros_like(x) + for i in range(len(x)): + if 0.5 <= x[i] <= 1.0: + u0[i] = 2.0 + else: + u0[i] = 1.0 + return u0 + +# 理论解 +def analytical_solution(x, t, a): + # 初始条件沿 x - at 平移 + x_shifted = x - a * t + return initial_condition((x_shifted + L) % L) # 周期边界条件 + +def residual(q): + reconstruction(q) + inviscid_flux(up1_2m, up1_2p, flux) + for i in range(nx): + res[i] = -(flux[i + 1] - flux[i]) / dx + +def reconstruction(q): + global il, ir, dd, up1_2m, up1_2p + + # Choose the stencil by ENO method + dd[0, 0:ntcell-1] = q[0:ntcell-1] + + for m in range(1, iorder): + for j in range(0, ntcell-1): + dd[m, j] = dd[m-1, j+1] - dd[m-1, j] + + for i in range(nx + 1): + il[i] = i - 1 + for m in range(1, iorder): + if abs(dd[m, il[i]-1+ishift]) <= abs(dd[m, il[i]+ishift]): + il[i] -= 1 + + for i in range(nx + 1): + ir[i] = i + for m in range(1, iorder): + if abs(dd[m, ir[i]-1+ishift]) <= abs(dd[m, ir[i]+ishift]): + ir[i] -= 1 + + # Reconstruction u(j+1/2) + for i in range(nx + 1): + k1 = il[i] + k2 = ir[i] + l1 = i - k1 + l2 = i - k2 + up1_2m[i] = 0 + up1_2p[i] = 0 + for m in range(iorder): + up1_2m[i] += q[k1 + ishift + m] * coef[l1, m] + up1_2p[i] += q[k2 + ishift + m] * coef[l2, m] + +def inviscid_flux(up1_2m, up1_2p, flux): + iflux = 0 + if iflux == 0: + rusanov_flux(up1_2m, up1_2p, flux) + else: + engquist_osher_flux(up1_2m, up1_2p, flux) + +def engquist_osher_flux(up1_2m, up1_2p, flux): + for i in range(nx + 1): + u_L = up1_2m[i] + u_R = up1_2p[i] + + cp = 0.5 * ( c + abs(c) ) + cm = 0.5 * ( c - abs(c) ) + + flux[i] = cp * uL + cm * u_R + +def rusanov_flux(up1_2m, up1_2p, flux): + for i in range(nx + 1): + u_L = up1_2m[i] + u_R = up1_2p[i] + F_L = c * u_L # 左状态通量 + F_R = c * u_R # 右状态通量 + alpha = abs(c) # 最大波速 + flux[i] = 0.5 * (F_L + F_R) - 0.5 * alpha * (u_R - u_L) + + +def boundary(u): + for i in range(-ighost, 1): + u[ist - 1 + i] = u[ied + i] + for i in range(1, ighost + 2): + u[ied + i] = u[ist - 1 + i] + +def update_oldfield(qn, q): + qn[:] = q[:] + +def init_coef(): + global coef + if iorder == 1: + coef[0] = [1.0] + coef[1] = [1.0] + elif iorder == 2: + coef[0] = [3.0/2.0, -1.0/2.0] + coef[1] = [1.0/2.0, 1.0/2.0] + coef[2] = [-1.0/2.0, 3.0/2.0] + elif iorder == 3: + coef[0] = [ 11.0/6.0, -7.0/6.0, 1.0/3.0 ] + coef[1] = [ 1.0/3.0, 5.0/6.0, -1.0/6.0 ] + coef[2] = [ -1.0/6.0, 5.0/6.0, 1.0/3.0 ] + coef[3] = [ 1.0/3.0, -7.0/6.0, 11.0/6.0 ] + elif iorder == 4: + coef[0] = [ 25.0/12.0, -23.0/12.0, 13.0/12.0, -1.0/4.0 ] + coef[1] = [ 1.0/4.0, 13.0/12.0, -5.0/12.0, 1.0/12.0 ] + coef[2] = [ -1.0/12.0, 7.0/12.0, 7.0/12.0, -1.0/12.0 ] + coef[3] = [ 1.0/12.0, -5.0/12.0, 13.0/12.0, 1.0/4.0 ] + coef[4] = [ -1.0/4.0, 13.0/12.0, -23.0/12.0, 25.0/12.0 ] + elif iorder == 5: + coef[0] = [ 137.0/60.0, -163.0/60.0, 137.0/60.0, -21.0/20.0, 1.0/5.0 ] + coef[1] = [ 1.0/5.0, 77.0/60.0, -43.0/60.0, 17.0/60.0, -1.0/20.0 ] + coef[2] = [ -1.0/20.0, 9.0/20.0, 47.0/60.0, -13.0/60.0, 1.0/30.0 ] + coef[3] = [ 1.0/30.0, -13.0/60.0, 47.0/60.0, 9.0/20.0, -1.0/20.0 ] + coef[4] = [ -1.0/20.0, 17.0/60.0, -43.0/60.0, 77.0/60.0, 1.0/5.0 ] + coef[5] = [ 1.0/5.0, -21.0/20.0, 137.0/60.0, -163.0/60.0, 137.0/60.0 ] + elif iorder == 6: + coef[0] = [ 49.0/20.0, -71.0/20.0, 79.0/20.0, -163.0/60.0, 31.0/30.0, -1.0/6.0 ] + coef[1] = [ 1.0/6.0, 29.0/20.0, -21.0/20.0, 37.0/60.0, -13.0/60.0, 1.0/30.0 ] + coef[2] = [ -1.0/30.0, 11.0/30.0, 19.0/20.0, -23.0/60.0, 7.0/60.0, -1.0/60.0 ] + coef[3] = [ 1.0/60.0, -2.0/15.0, 37.0/60.0, 37.0/60.0, -2.0/15.0, 1.0/60.0 ] + coef[4] = [ -1.0/60.0, 7.0/60.0, -23.0/60.0, 19.0/20.0, 11.0/30.0, -1.0/30.0 ] + coef[5] = [ 1.0/30.0, -13.0/60.0, 37.0/60.0, -21.0/20.0, 29.0/20.0, 1.0/6.0 ] + coef[6] = [ -1.0/6.0, 31.0/30.0, -163.0/60.0, 79.0/20.0, -71.0/20.0, 49.0/20.0 ] + elif iorder == 7: + coef[0] = [ 363.0/140.0, -617.0/140.0, 853.0/140.0, -2341.0/420.0, 667.0/210.0, -43.0/42.0, 1.0/7.0 ] + coef[1] = [ 1.0/7.0, 223.0/140.0, -197.0/140.0, 153.0/140.0, -241.0/420.0, 37.0/210.0, -1.0/42.0 ] + coef[2] = [ -1.0/42.0, 13.0/42.0, 153.0/140.0, -241.0/420.0, 109.0/420.0, -31.0/420.0, 1.0/105.0 ] + coef[3] = [ 1.0/105.0, -19.0/210.0, 107.0/210.0, 319.0/420.0, -101.0/420.0, 5.0/84.0, -1.0/140.0 ] + coef[4] = [ -1.0/140.0, 5.0/84.0, -101.0/420.0, 319.0/420.0, 107.0/210.0, -19.0/210.0, 1.0/105.0 ] + coef[5] = [ 1.0/105.0, -31.0/420.0, 109.0/420.0, -241.0/420.0, 153.0/140.0, 13.0/42.0, -1.0/42.0 ] + coef[6] = [ -1.0/42.0, 37.0/210.0, -241.0/420.0, 153.0/140.0, -197.0/140.0, 223.0/140.0, 1.0/7.0 ] + coef[7] = [ 1.0/7.0, -43.0/42.0, 667.0/210.0, -2341.0/420.0, 853.0/140.0, -617.0/140.0, 363.0/140.0 ] + +def init_mesh(): + global xstart, xend, dx, x, xcc + xstart = 0.0 + xend = L + dx = (xend - xstart) / nx + + for i in range(0, nx+1): + x[i] = xstart + i * dx + + for i in range(0, nx): + xcc[i] = 0.5 * (x[i] + x[i + 1]) + +def init_field(): + global u, un + for i in range(ist, ied + 1): + j = i - ist + if 0.5 <= xcc[j] <= 1.0: + u[i] = 2.0 + else: + u[i] = 1.0 + boundary(u) + update_oldfield(un, u) + +def runge_kutta(): + if rk == 1: + runge_kutta_1() + elif rk == 2: + runge_kutta_2() + else: + runge_kutta_3() + +def runge_kutta_1(): + global u, un, dt + residual(u) + for i in range(nx): + j = i + ishift + u[j] = u[j] + dt * res[i] + boundary(u) + update_oldfield(un, u) + +def runge_kutta_2(): + global u, un, dt + residual(u) + for i in range(nx): + j = i + ishift + u[j] = u[j] + dt * res[i] + boundary(u) + + residual(u) + for i in range(nx): + j = i + ishift + u[j] = 0.5 * un[j] + 0.5 * u[j] + 0.5 * dt * res[i] + boundary(u) + update_oldfield(un, u) + +def runge_kutta_3(): + global u, un, dt + residual(u) + for i in range(nx): + j = i + ishift + u[j] = u[j] + dt * res[i] + boundary(u) + + residual(u) + for i in range(nx): + j = i + ishift + u[j] = 0.75 * un[j] + 0.25 * u[j] + 0.25 * dt * res[i] + boundary(u) + + residual(u) + c1, c2, c3 = 1.0/3.0, 2.0/3.0, 2.0/3.0 + for i in range(nx): + j = i + ishift + u[j] = c1 * un[j] + c2 * u[j] + c3 * dt * res[i] + boundary(u) + update_oldfield(un, u) + +def get_ordinal_numbers(order): + if order == 1: + return 'st' + elif order == 2: + return 'nd' + elif order == 3: + return 'rd' + else: + return 'th' + +def visualize(): + with open('solution.plt', 'w') as f: + for i in range(ist, ied + 1): + j = i - ist + f.write(f"{xcc[j]:20.10e}{u[i]:20.10e}\n") + + # 可视化 + u_numerical = np.copy(u[ist:ied+1]) + print(f'u_numerical.size={u_numerical.size}') + print(f'xcc.size={xcc.size}') + #计算理论解 + u_analytical = analytical_solution(xcc, T, c) + print(f'u_analytical.size={u_analytical.size}') + plt.figure("OneFLOW-CFD Solver", figsize=(10, 6)) + plt.scatter(xcc, u_numerical, facecolor="none", edgecolor="blue", s=20, linewidths=0.5, label=f'Numerical (Rusanov)') + plt.plot(xcc, u_analytical, 'r--', label='Analytical') + plt.xlabel('x') + plt.ylabel('u') + ordinal1 = get_ordinal_numbers(iorder) + ordinal2 = get_ordinal_numbers(rk) + plt.title(f'1D Convection Equation at t = {T:.3f} using {iorder}{ordinal1}-order ENO and {rk}{ordinal2}-order Runge-Kutta methods') + plt.legend() + plt.grid(True, color='gray', linestyle='--', linewidth=0.5, alpha=0.7) + plt.tight_layout() + plt.show() + +# Global constants and variables +nx = 40 +rk = 2 +iorder = 2 +ighost = iorder +ishift = ighost + 1 +ist = 0 + ishift +ied = nx - 1 + ishift +ntcell = nx + 2 * ishift +isize = iorder * (iorder + 1) + +il = np.zeros(nx + 1, dtype=int) +ir = np.zeros(nx + 1, dtype=int) +coef = np.zeros((iorder + 1, iorder)) +dd = np.zeros((iorder, ntcell)) +up1_2m = np.zeros(nx + 1) +up1_2p = np.zeros(nx + 1) +flux = np.zeros(nx + 1) +res = np.zeros(nx) +dt = 0.0 + +# Mesh module variables +xstart = 0.0 +xend = 0.0 +L = 2.0 +dx = 0.0 +x = np.zeros(nx + 1) +xcc = np.zeros(nx) + +# Field module variables +u = np.zeros(ntcell) +un = np.zeros(ntcell) + +def main(): + global dt, T, c + init_coef() + init_mesh() + init_field() + + c = 1.0 + T = 0.625 + dt = .0025 + nt = int(T / dt) + simu_time = T + + t = 0.0 + + while t < simu_time: + runge_kutta() + t += dt + if t + dt > simu_time: + dt = simu_time - t + + print(t) + visualize() + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/example/1d-linear-convection/eno/rusanov/rk2/eno2/01/plot.py b/example/1d-linear-convection/eno/rusanov/rk2/eno2/01/plot.py new file mode 100644 index 00000000..e389044c --- /dev/null +++ b/example/1d-linear-convection/eno/rusanov/rk2/eno2/01/plot.py @@ -0,0 +1,53 @@ +import numpy as np +import matplotlib.pyplot as plt +import csv +import sys + +nvar = len(sys.argv) +print('nvar=',nvar) +print('sys.argv=',sys.argv) + +order = 1 +if nvar >= 2: + var = sys.argv[1] + print('var=',var) + order = int(var) + +print('order=',order) + +x_list = [] +u_list = [] + +with open('solution.plt', newline='') as csvfile: + #readCSV = csv.reader(csvfile, delimiter= ' ') + icount = 0 + for line in csvfile: + # 去除首尾空格,按连续空格分割 + row = line.strip().split() + #print("row=",row) + x_list.append(row[0]) + u_list.append(row[1]) + icount += 1 + +ni = icount +print("ni=",ni) + +#print("x_list=",x_list) + +x = np.zeros( ni ) +u = np.zeros( ni ) + +for i in range(0, ni): + x[i] = float(x_list[i]) + u[i] = float(u_list[i]) + +labelname = 'Eno' + str(order) + +plt.figure("OneFLOW-CFD Solver", figsize=(8, 6), dpi=100) +plt.plot(x, u, "b-", linewidth=1.0, marker = 's', markerfacecolor='None', label=labelname) +plt.xlabel("$x$") +plt.ylabel("$u$") +plt.title("burgers T=1") +plt.legend() +plt.tight_layout() +plt.show(); \ No newline at end of file diff --git a/example/1d-linear-convection/eno/rusanov/rk2/eno3/01/eno.py b/example/1d-linear-convection/eno/rusanov/rk2/eno3/01/eno.py new file mode 100644 index 00000000..b750ab01 --- /dev/null +++ b/example/1d-linear-convection/eno/rusanov/rk2/eno3/01/eno.py @@ -0,0 +1,311 @@ +import numpy as np +import matplotlib.pyplot as plt + +# 初始条件 +def initial_condition(x): + u0 = np.zeros_like(x) + for i in range(len(x)): + if 0.5 <= x[i] <= 1.0: + u0[i] = 2.0 + else: + u0[i] = 1.0 + return u0 + +# 理论解 +def analytical_solution(x, t, a): + # 初始条件沿 x - at 平移 + x_shifted = x - a * t + return initial_condition((x_shifted + L) % L) # 周期边界条件 + +def residual(q): + reconstruction(q) + inviscid_flux(up1_2m, up1_2p, flux) + for i in range(nx): + res[i] = -(flux[i + 1] - flux[i]) / dx + +def reconstruction(q): + global il, ir, dd, up1_2m, up1_2p + + # Choose the stencil by ENO method + dd[0, 0:ntcell-1] = q[0:ntcell-1] + + for m in range(1, iorder): + for j in range(0, ntcell-1): + dd[m, j] = dd[m-1, j+1] - dd[m-1, j] + + for i in range(nx + 1): + il[i] = i - 1 + for m in range(1, iorder): + if abs(dd[m, il[i]-1+ishift]) <= abs(dd[m, il[i]+ishift]): + il[i] -= 1 + + for i in range(nx + 1): + ir[i] = i + for m in range(1, iorder): + if abs(dd[m, ir[i]-1+ishift]) <= abs(dd[m, ir[i]+ishift]): + ir[i] -= 1 + + # Reconstruction u(j+1/2) + for i in range(nx + 1): + k1 = il[i] + k2 = ir[i] + l1 = i - k1 + l2 = i - k2 + up1_2m[i] = 0 + up1_2p[i] = 0 + for m in range(iorder): + up1_2m[i] += q[k1 + ishift + m] * coef[l1, m] + up1_2p[i] += q[k2 + ishift + m] * coef[l2, m] + +def inviscid_flux(up1_2m, up1_2p, flux): + iflux = 0 + if iflux == 0: + rusanov_flux(up1_2m, up1_2p, flux) + else: + engquist_osher_flux(up1_2m, up1_2p, flux) + +def engquist_osher_flux(up1_2m, up1_2p, flux): + for i in range(nx + 1): + u_L = up1_2m[i] + u_R = up1_2p[i] + + cp = 0.5 * ( c + abs(c) ) + cm = 0.5 * ( c - abs(c) ) + + flux[i] = cp * uL + cm * u_R + +def rusanov_flux(up1_2m, up1_2p, flux): + for i in range(nx + 1): + u_L = up1_2m[i] + u_R = up1_2p[i] + F_L = c * u_L # 左状态通量 + F_R = c * u_R # 右状态通量 + alpha = abs(c) # 最大波速 + flux[i] = 0.5 * (F_L + F_R) - 0.5 * alpha * (u_R - u_L) + + +def boundary(u): + for i in range(-ighost, 1): + u[ist - 1 + i] = u[ied + i] + for i in range(1, ighost + 2): + u[ied + i] = u[ist - 1 + i] + +def update_oldfield(qn, q): + qn[:] = q[:] + +def init_coef(): + global coef + if iorder == 1: + coef[0] = [1.0] + coef[1] = [1.0] + elif iorder == 2: + coef[0] = [3.0/2.0, -1.0/2.0] + coef[1] = [1.0/2.0, 1.0/2.0] + coef[2] = [-1.0/2.0, 3.0/2.0] + elif iorder == 3: + coef[0] = [ 11.0/6.0, -7.0/6.0, 1.0/3.0 ] + coef[1] = [ 1.0/3.0, 5.0/6.0, -1.0/6.0 ] + coef[2] = [ -1.0/6.0, 5.0/6.0, 1.0/3.0 ] + coef[3] = [ 1.0/3.0, -7.0/6.0, 11.0/6.0 ] + elif iorder == 4: + coef[0] = [ 25.0/12.0, -23.0/12.0, 13.0/12.0, -1.0/4.0 ] + coef[1] = [ 1.0/4.0, 13.0/12.0, -5.0/12.0, 1.0/12.0 ] + coef[2] = [ -1.0/12.0, 7.0/12.0, 7.0/12.0, -1.0/12.0 ] + coef[3] = [ 1.0/12.0, -5.0/12.0, 13.0/12.0, 1.0/4.0 ] + coef[4] = [ -1.0/4.0, 13.0/12.0, -23.0/12.0, 25.0/12.0 ] + elif iorder == 5: + coef[0] = [ 137.0/60.0, -163.0/60.0, 137.0/60.0, -21.0/20.0, 1.0/5.0 ] + coef[1] = [ 1.0/5.0, 77.0/60.0, -43.0/60.0, 17.0/60.0, -1.0/20.0 ] + coef[2] = [ -1.0/20.0, 9.0/20.0, 47.0/60.0, -13.0/60.0, 1.0/30.0 ] + coef[3] = [ 1.0/30.0, -13.0/60.0, 47.0/60.0, 9.0/20.0, -1.0/20.0 ] + coef[4] = [ -1.0/20.0, 17.0/60.0, -43.0/60.0, 77.0/60.0, 1.0/5.0 ] + coef[5] = [ 1.0/5.0, -21.0/20.0, 137.0/60.0, -163.0/60.0, 137.0/60.0 ] + elif iorder == 6: + coef[0] = [ 49.0/20.0, -71.0/20.0, 79.0/20.0, -163.0/60.0, 31.0/30.0, -1.0/6.0 ] + coef[1] = [ 1.0/6.0, 29.0/20.0, -21.0/20.0, 37.0/60.0, -13.0/60.0, 1.0/30.0 ] + coef[2] = [ -1.0/30.0, 11.0/30.0, 19.0/20.0, -23.0/60.0, 7.0/60.0, -1.0/60.0 ] + coef[3] = [ 1.0/60.0, -2.0/15.0, 37.0/60.0, 37.0/60.0, -2.0/15.0, 1.0/60.0 ] + coef[4] = [ -1.0/60.0, 7.0/60.0, -23.0/60.0, 19.0/20.0, 11.0/30.0, -1.0/30.0 ] + coef[5] = [ 1.0/30.0, -13.0/60.0, 37.0/60.0, -21.0/20.0, 29.0/20.0, 1.0/6.0 ] + coef[6] = [ -1.0/6.0, 31.0/30.0, -163.0/60.0, 79.0/20.0, -71.0/20.0, 49.0/20.0 ] + elif iorder == 7: + coef[0] = [ 363.0/140.0, -617.0/140.0, 853.0/140.0, -2341.0/420.0, 667.0/210.0, -43.0/42.0, 1.0/7.0 ] + coef[1] = [ 1.0/7.0, 223.0/140.0, -197.0/140.0, 153.0/140.0, -241.0/420.0, 37.0/210.0, -1.0/42.0 ] + coef[2] = [ -1.0/42.0, 13.0/42.0, 153.0/140.0, -241.0/420.0, 109.0/420.0, -31.0/420.0, 1.0/105.0 ] + coef[3] = [ 1.0/105.0, -19.0/210.0, 107.0/210.0, 319.0/420.0, -101.0/420.0, 5.0/84.0, -1.0/140.0 ] + coef[4] = [ -1.0/140.0, 5.0/84.0, -101.0/420.0, 319.0/420.0, 107.0/210.0, -19.0/210.0, 1.0/105.0 ] + coef[5] = [ 1.0/105.0, -31.0/420.0, 109.0/420.0, -241.0/420.0, 153.0/140.0, 13.0/42.0, -1.0/42.0 ] + coef[6] = [ -1.0/42.0, 37.0/210.0, -241.0/420.0, 153.0/140.0, -197.0/140.0, 223.0/140.0, 1.0/7.0 ] + coef[7] = [ 1.0/7.0, -43.0/42.0, 667.0/210.0, -2341.0/420.0, 853.0/140.0, -617.0/140.0, 363.0/140.0 ] + +def init_mesh(): + global xstart, xend, dx, x, xcc + xstart = 0.0 + xend = L + dx = (xend - xstart) / nx + + for i in range(0, nx+1): + x[i] = xstart + i * dx + + for i in range(0, nx): + xcc[i] = 0.5 * (x[i] + x[i + 1]) + +def init_field(): + global u, un + for i in range(ist, ied + 1): + j = i - ist + if 0.5 <= xcc[j] <= 1.0: + u[i] = 2.0 + else: + u[i] = 1.0 + boundary(u) + update_oldfield(un, u) + +def runge_kutta(): + if rk == 1: + runge_kutta_1() + elif rk == 2: + runge_kutta_2() + else: + runge_kutta_3() + +def runge_kutta_1(): + global u, un, dt + residual(u) + for i in range(nx): + j = i + ishift + u[j] = u[j] + dt * res[i] + boundary(u) + update_oldfield(un, u) + +def runge_kutta_2(): + global u, un, dt + residual(u) + for i in range(nx): + j = i + ishift + u[j] = u[j] + dt * res[i] + boundary(u) + + residual(u) + for i in range(nx): + j = i + ishift + u[j] = 0.5 * un[j] + 0.5 * u[j] + 0.5 * dt * res[i] + boundary(u) + update_oldfield(un, u) + +def runge_kutta_3(): + global u, un, dt + residual(u) + for i in range(nx): + j = i + ishift + u[j] = u[j] + dt * res[i] + boundary(u) + + residual(u) + for i in range(nx): + j = i + ishift + u[j] = 0.75 * un[j] + 0.25 * u[j] + 0.25 * dt * res[i] + boundary(u) + + residual(u) + c1, c2, c3 = 1.0/3.0, 2.0/3.0, 2.0/3.0 + for i in range(nx): + j = i + ishift + u[j] = c1 * un[j] + c2 * u[j] + c3 * dt * res[i] + boundary(u) + update_oldfield(un, u) + +def get_ordinal_numbers(order): + if order == 1: + return 'st' + elif order == 2: + return 'nd' + elif order == 3: + return 'rd' + else: + return 'th' + +def visualize(): + with open('solution.plt', 'w') as f: + for i in range(ist, ied + 1): + j = i - ist + f.write(f"{xcc[j]:20.10e}{u[i]:20.10e}\n") + + # 可视化 + u_numerical = np.copy(u[ist:ied+1]) + print(f'u_numerical.size={u_numerical.size}') + print(f'xcc.size={xcc.size}') + #计算理论解 + u_analytical = analytical_solution(xcc, T, c) + print(f'u_analytical.size={u_analytical.size}') + plt.figure("OneFLOW-CFD Solver", figsize=(10, 6)) + plt.scatter(xcc, u_numerical, facecolor="none", edgecolor="blue", s=20, linewidths=0.5, label=f'Numerical (Rusanov)') + plt.plot(xcc, u_analytical, 'r--', label='Analytical') + plt.xlabel('x') + plt.ylabel('u') + ordinal1 = get_ordinal_numbers(iorder) + ordinal2 = get_ordinal_numbers(rk) + plt.title(f'1D Convection Equation at t = {T:.3f} using {iorder}{ordinal1}-order ENO and {rk}{ordinal2}-order Runge-Kutta methods') + plt.legend() + plt.grid(True, color='gray', linestyle='--', linewidth=0.5, alpha=0.7) + plt.tight_layout() + plt.show() + +# Global constants and variables +nx = 40 +rk = 2 +iorder = 3 +ighost = iorder +ishift = ighost + 1 +ist = 0 + ishift +ied = nx - 1 + ishift +ntcell = nx + 2 * ishift +isize = iorder * (iorder + 1) + +il = np.zeros(nx + 1, dtype=int) +ir = np.zeros(nx + 1, dtype=int) +coef = np.zeros((iorder + 1, iorder)) +dd = np.zeros((iorder, ntcell)) +up1_2m = np.zeros(nx + 1) +up1_2p = np.zeros(nx + 1) +flux = np.zeros(nx + 1) +res = np.zeros(nx) +dt = 0.0 + +# Mesh module variables +xstart = 0.0 +xend = 0.0 +L = 2.0 +dx = 0.0 +x = np.zeros(nx + 1) +xcc = np.zeros(nx) + +# Field module variables +u = np.zeros(ntcell) +un = np.zeros(ntcell) + +def main(): + global dt, T, c + init_coef() + init_mesh() + init_field() + + c = 1.0 + T = 0.625 + dt = .0025 + nt = int(T / dt) + simu_time = T + + t = 0.0 + + while t < simu_time: + runge_kutta() + t += dt + if t + dt > simu_time: + dt = simu_time - t + + print(t) + visualize() + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/example/1d-linear-convection/eno/rusanov/rk2/eno3/01/plot.py b/example/1d-linear-convection/eno/rusanov/rk2/eno3/01/plot.py new file mode 100644 index 00000000..e389044c --- /dev/null +++ b/example/1d-linear-convection/eno/rusanov/rk2/eno3/01/plot.py @@ -0,0 +1,53 @@ +import numpy as np +import matplotlib.pyplot as plt +import csv +import sys + +nvar = len(sys.argv) +print('nvar=',nvar) +print('sys.argv=',sys.argv) + +order = 1 +if nvar >= 2: + var = sys.argv[1] + print('var=',var) + order = int(var) + +print('order=',order) + +x_list = [] +u_list = [] + +with open('solution.plt', newline='') as csvfile: + #readCSV = csv.reader(csvfile, delimiter= ' ') + icount = 0 + for line in csvfile: + # 去除首尾空格,按连续空格分割 + row = line.strip().split() + #print("row=",row) + x_list.append(row[0]) + u_list.append(row[1]) + icount += 1 + +ni = icount +print("ni=",ni) + +#print("x_list=",x_list) + +x = np.zeros( ni ) +u = np.zeros( ni ) + +for i in range(0, ni): + x[i] = float(x_list[i]) + u[i] = float(u_list[i]) + +labelname = 'Eno' + str(order) + +plt.figure("OneFLOW-CFD Solver", figsize=(8, 6), dpi=100) +plt.plot(x, u, "b-", linewidth=1.0, marker = 's', markerfacecolor='None', label=labelname) +plt.xlabel("$x$") +plt.ylabel("$u$") +plt.title("burgers T=1") +plt.legend() +plt.tight_layout() +plt.show(); \ No newline at end of file diff --git a/example/1d-linear-convection/eno/rusanov/rk2/eno4/01/eno.py b/example/1d-linear-convection/eno/rusanov/rk2/eno4/01/eno.py new file mode 100644 index 00000000..d99cf46f --- /dev/null +++ b/example/1d-linear-convection/eno/rusanov/rk2/eno4/01/eno.py @@ -0,0 +1,311 @@ +import numpy as np +import matplotlib.pyplot as plt + +# 初始条件 +def initial_condition(x): + u0 = np.zeros_like(x) + for i in range(len(x)): + if 0.5 <= x[i] <= 1.0: + u0[i] = 2.0 + else: + u0[i] = 1.0 + return u0 + +# 理论解 +def analytical_solution(x, t, a): + # 初始条件沿 x - at 平移 + x_shifted = x - a * t + return initial_condition((x_shifted + L) % L) # 周期边界条件 + +def residual(q): + reconstruction(q) + inviscid_flux(up1_2m, up1_2p, flux) + for i in range(nx): + res[i] = -(flux[i + 1] - flux[i]) / dx + +def reconstruction(q): + global il, ir, dd, up1_2m, up1_2p + + # Choose the stencil by ENO method + dd[0, 0:ntcell-1] = q[0:ntcell-1] + + for m in range(1, iorder): + for j in range(0, ntcell-1): + dd[m, j] = dd[m-1, j+1] - dd[m-1, j] + + for i in range(nx + 1): + il[i] = i - 1 + for m in range(1, iorder): + if abs(dd[m, il[i]-1+ishift]) <= abs(dd[m, il[i]+ishift]): + il[i] -= 1 + + for i in range(nx + 1): + ir[i] = i + for m in range(1, iorder): + if abs(dd[m, ir[i]-1+ishift]) <= abs(dd[m, ir[i]+ishift]): + ir[i] -= 1 + + # Reconstruction u(j+1/2) + for i in range(nx + 1): + k1 = il[i] + k2 = ir[i] + l1 = i - k1 + l2 = i - k2 + up1_2m[i] = 0 + up1_2p[i] = 0 + for m in range(iorder): + up1_2m[i] += q[k1 + ishift + m] * coef[l1, m] + up1_2p[i] += q[k2 + ishift + m] * coef[l2, m] + +def inviscid_flux(up1_2m, up1_2p, flux): + iflux = 0 + if iflux == 0: + rusanov_flux(up1_2m, up1_2p, flux) + else: + engquist_osher_flux(up1_2m, up1_2p, flux) + +def engquist_osher_flux(up1_2m, up1_2p, flux): + for i in range(nx + 1): + u_L = up1_2m[i] + u_R = up1_2p[i] + + cp = 0.5 * ( c + abs(c) ) + cm = 0.5 * ( c - abs(c) ) + + flux[i] = cp * uL + cm * u_R + +def rusanov_flux(up1_2m, up1_2p, flux): + for i in range(nx + 1): + u_L = up1_2m[i] + u_R = up1_2p[i] + F_L = c * u_L # 左状态通量 + F_R = c * u_R # 右状态通量 + alpha = abs(c) # 最大波速 + flux[i] = 0.5 * (F_L + F_R) - 0.5 * alpha * (u_R - u_L) + + +def boundary(u): + for i in range(-ighost, 1): + u[ist - 1 + i] = u[ied + i] + for i in range(1, ighost + 2): + u[ied + i] = u[ist - 1 + i] + +def update_oldfield(qn, q): + qn[:] = q[:] + +def init_coef(): + global coef + if iorder == 1: + coef[0] = [1.0] + coef[1] = [1.0] + elif iorder == 2: + coef[0] = [3.0/2.0, -1.0/2.0] + coef[1] = [1.0/2.0, 1.0/2.0] + coef[2] = [-1.0/2.0, 3.0/2.0] + elif iorder == 3: + coef[0] = [ 11.0/6.0, -7.0/6.0, 1.0/3.0 ] + coef[1] = [ 1.0/3.0, 5.0/6.0, -1.0/6.0 ] + coef[2] = [ -1.0/6.0, 5.0/6.0, 1.0/3.0 ] + coef[3] = [ 1.0/3.0, -7.0/6.0, 11.0/6.0 ] + elif iorder == 4: + coef[0] = [ 25.0/12.0, -23.0/12.0, 13.0/12.0, -1.0/4.0 ] + coef[1] = [ 1.0/4.0, 13.0/12.0, -5.0/12.0, 1.0/12.0 ] + coef[2] = [ -1.0/12.0, 7.0/12.0, 7.0/12.0, -1.0/12.0 ] + coef[3] = [ 1.0/12.0, -5.0/12.0, 13.0/12.0, 1.0/4.0 ] + coef[4] = [ -1.0/4.0, 13.0/12.0, -23.0/12.0, 25.0/12.0 ] + elif iorder == 5: + coef[0] = [ 137.0/60.0, -163.0/60.0, 137.0/60.0, -21.0/20.0, 1.0/5.0 ] + coef[1] = [ 1.0/5.0, 77.0/60.0, -43.0/60.0, 17.0/60.0, -1.0/20.0 ] + coef[2] = [ -1.0/20.0, 9.0/20.0, 47.0/60.0, -13.0/60.0, 1.0/30.0 ] + coef[3] = [ 1.0/30.0, -13.0/60.0, 47.0/60.0, 9.0/20.0, -1.0/20.0 ] + coef[4] = [ -1.0/20.0, 17.0/60.0, -43.0/60.0, 77.0/60.0, 1.0/5.0 ] + coef[5] = [ 1.0/5.0, -21.0/20.0, 137.0/60.0, -163.0/60.0, 137.0/60.0 ] + elif iorder == 6: + coef[0] = [ 49.0/20.0, -71.0/20.0, 79.0/20.0, -163.0/60.0, 31.0/30.0, -1.0/6.0 ] + coef[1] = [ 1.0/6.0, 29.0/20.0, -21.0/20.0, 37.0/60.0, -13.0/60.0, 1.0/30.0 ] + coef[2] = [ -1.0/30.0, 11.0/30.0, 19.0/20.0, -23.0/60.0, 7.0/60.0, -1.0/60.0 ] + coef[3] = [ 1.0/60.0, -2.0/15.0, 37.0/60.0, 37.0/60.0, -2.0/15.0, 1.0/60.0 ] + coef[4] = [ -1.0/60.0, 7.0/60.0, -23.0/60.0, 19.0/20.0, 11.0/30.0, -1.0/30.0 ] + coef[5] = [ 1.0/30.0, -13.0/60.0, 37.0/60.0, -21.0/20.0, 29.0/20.0, 1.0/6.0 ] + coef[6] = [ -1.0/6.0, 31.0/30.0, -163.0/60.0, 79.0/20.0, -71.0/20.0, 49.0/20.0 ] + elif iorder == 7: + coef[0] = [ 363.0/140.0, -617.0/140.0, 853.0/140.0, -2341.0/420.0, 667.0/210.0, -43.0/42.0, 1.0/7.0 ] + coef[1] = [ 1.0/7.0, 223.0/140.0, -197.0/140.0, 153.0/140.0, -241.0/420.0, 37.0/210.0, -1.0/42.0 ] + coef[2] = [ -1.0/42.0, 13.0/42.0, 153.0/140.0, -241.0/420.0, 109.0/420.0, -31.0/420.0, 1.0/105.0 ] + coef[3] = [ 1.0/105.0, -19.0/210.0, 107.0/210.0, 319.0/420.0, -101.0/420.0, 5.0/84.0, -1.0/140.0 ] + coef[4] = [ -1.0/140.0, 5.0/84.0, -101.0/420.0, 319.0/420.0, 107.0/210.0, -19.0/210.0, 1.0/105.0 ] + coef[5] = [ 1.0/105.0, -31.0/420.0, 109.0/420.0, -241.0/420.0, 153.0/140.0, 13.0/42.0, -1.0/42.0 ] + coef[6] = [ -1.0/42.0, 37.0/210.0, -241.0/420.0, 153.0/140.0, -197.0/140.0, 223.0/140.0, 1.0/7.0 ] + coef[7] = [ 1.0/7.0, -43.0/42.0, 667.0/210.0, -2341.0/420.0, 853.0/140.0, -617.0/140.0, 363.0/140.0 ] + +def init_mesh(): + global xstart, xend, dx, x, xcc + xstart = 0.0 + xend = L + dx = (xend - xstart) / nx + + for i in range(0, nx+1): + x[i] = xstart + i * dx + + for i in range(0, nx): + xcc[i] = 0.5 * (x[i] + x[i + 1]) + +def init_field(): + global u, un + for i in range(ist, ied + 1): + j = i - ist + if 0.5 <= xcc[j] <= 1.0: + u[i] = 2.0 + else: + u[i] = 1.0 + boundary(u) + update_oldfield(un, u) + +def runge_kutta(): + if rk == 1: + runge_kutta_1() + elif rk == 2: + runge_kutta_2() + else: + runge_kutta_3() + +def runge_kutta_1(): + global u, un, dt + residual(u) + for i in range(nx): + j = i + ishift + u[j] = u[j] + dt * res[i] + boundary(u) + update_oldfield(un, u) + +def runge_kutta_2(): + global u, un, dt + residual(u) + for i in range(nx): + j = i + ishift + u[j] = u[j] + dt * res[i] + boundary(u) + + residual(u) + for i in range(nx): + j = i + ishift + u[j] = 0.5 * un[j] + 0.5 * u[j] + 0.5 * dt * res[i] + boundary(u) + update_oldfield(un, u) + +def runge_kutta_3(): + global u, un, dt + residual(u) + for i in range(nx): + j = i + ishift + u[j] = u[j] + dt * res[i] + boundary(u) + + residual(u) + for i in range(nx): + j = i + ishift + u[j] = 0.75 * un[j] + 0.25 * u[j] + 0.25 * dt * res[i] + boundary(u) + + residual(u) + c1, c2, c3 = 1.0/3.0, 2.0/3.0, 2.0/3.0 + for i in range(nx): + j = i + ishift + u[j] = c1 * un[j] + c2 * u[j] + c3 * dt * res[i] + boundary(u) + update_oldfield(un, u) + +def get_ordinal_numbers(order): + if order == 1: + return 'st' + elif order == 2: + return 'nd' + elif order == 3: + return 'rd' + else: + return 'th' + +def visualize(): + with open('solution.plt', 'w') as f: + for i in range(ist, ied + 1): + j = i - ist + f.write(f"{xcc[j]:20.10e}{u[i]:20.10e}\n") + + # 可视化 + u_numerical = np.copy(u[ist:ied+1]) + print(f'u_numerical.size={u_numerical.size}') + print(f'xcc.size={xcc.size}') + #计算理论解 + u_analytical = analytical_solution(xcc, T, c) + print(f'u_analytical.size={u_analytical.size}') + plt.figure("OneFLOW-CFD Solver", figsize=(10, 6)) + plt.scatter(xcc, u_numerical, facecolor="none", edgecolor="blue", s=20, linewidths=0.5, label=f'Numerical (Rusanov)') + plt.plot(xcc, u_analytical, 'r--', label='Analytical') + plt.xlabel('x') + plt.ylabel('u') + ordinal1 = get_ordinal_numbers(iorder) + ordinal2 = get_ordinal_numbers(rk) + plt.title(f'1D Convection Equation at t = {T:.3f} using {iorder}{ordinal1}-order ENO and {rk}{ordinal2}-order Runge-Kutta methods') + plt.legend() + plt.grid(True, color='gray', linestyle='--', linewidth=0.5, alpha=0.7) + plt.tight_layout() + plt.show() + +# Global constants and variables +nx = 40 +rk = 2 +iorder = 4 +ighost = iorder +ishift = ighost + 1 +ist = 0 + ishift +ied = nx - 1 + ishift +ntcell = nx + 2 * ishift +isize = iorder * (iorder + 1) + +il = np.zeros(nx + 1, dtype=int) +ir = np.zeros(nx + 1, dtype=int) +coef = np.zeros((iorder + 1, iorder)) +dd = np.zeros((iorder, ntcell)) +up1_2m = np.zeros(nx + 1) +up1_2p = np.zeros(nx + 1) +flux = np.zeros(nx + 1) +res = np.zeros(nx) +dt = 0.0 + +# Mesh module variables +xstart = 0.0 +xend = 0.0 +L = 2.0 +dx = 0.0 +x = np.zeros(nx + 1) +xcc = np.zeros(nx) + +# Field module variables +u = np.zeros(ntcell) +un = np.zeros(ntcell) + +def main(): + global dt, T, c + init_coef() + init_mesh() + init_field() + + c = 1.0 + T = 0.625 + dt = .0025 + nt = int(T / dt) + simu_time = T + + t = 0.0 + + while t < simu_time: + runge_kutta() + t += dt + if t + dt > simu_time: + dt = simu_time - t + + print(t) + visualize() + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/example/1d-linear-convection/eno/rusanov/rk2/eno4/01/plot.py b/example/1d-linear-convection/eno/rusanov/rk2/eno4/01/plot.py new file mode 100644 index 00000000..e389044c --- /dev/null +++ b/example/1d-linear-convection/eno/rusanov/rk2/eno4/01/plot.py @@ -0,0 +1,53 @@ +import numpy as np +import matplotlib.pyplot as plt +import csv +import sys + +nvar = len(sys.argv) +print('nvar=',nvar) +print('sys.argv=',sys.argv) + +order = 1 +if nvar >= 2: + var = sys.argv[1] + print('var=',var) + order = int(var) + +print('order=',order) + +x_list = [] +u_list = [] + +with open('solution.plt', newline='') as csvfile: + #readCSV = csv.reader(csvfile, delimiter= ' ') + icount = 0 + for line in csvfile: + # 去除首尾空格,按连续空格分割 + row = line.strip().split() + #print("row=",row) + x_list.append(row[0]) + u_list.append(row[1]) + icount += 1 + +ni = icount +print("ni=",ni) + +#print("x_list=",x_list) + +x = np.zeros( ni ) +u = np.zeros( ni ) + +for i in range(0, ni): + x[i] = float(x_list[i]) + u[i] = float(u_list[i]) + +labelname = 'Eno' + str(order) + +plt.figure("OneFLOW-CFD Solver", figsize=(8, 6), dpi=100) +plt.plot(x, u, "b-", linewidth=1.0, marker = 's', markerfacecolor='None', label=labelname) +plt.xlabel("$x$") +plt.ylabel("$u$") +plt.title("burgers T=1") +plt.legend() +plt.tight_layout() +plt.show(); \ No newline at end of file diff --git a/example/1d-linear-convection/eno/rusanov/rk2/eno5/01/eno.py b/example/1d-linear-convection/eno/rusanov/rk2/eno5/01/eno.py new file mode 100644 index 00000000..def88546 --- /dev/null +++ b/example/1d-linear-convection/eno/rusanov/rk2/eno5/01/eno.py @@ -0,0 +1,311 @@ +import numpy as np +import matplotlib.pyplot as plt + +# 初始条件 +def initial_condition(x): + u0 = np.zeros_like(x) + for i in range(len(x)): + if 0.5 <= x[i] <= 1.0: + u0[i] = 2.0 + else: + u0[i] = 1.0 + return u0 + +# 理论解 +def analytical_solution(x, t, a): + # 初始条件沿 x - at 平移 + x_shifted = x - a * t + return initial_condition((x_shifted + L) % L) # 周期边界条件 + +def residual(q): + reconstruction(q) + inviscid_flux(up1_2m, up1_2p, flux) + for i in range(nx): + res[i] = -(flux[i + 1] - flux[i]) / dx + +def reconstruction(q): + global il, ir, dd, up1_2m, up1_2p + + # Choose the stencil by ENO method + dd[0, 0:ntcell-1] = q[0:ntcell-1] + + for m in range(1, iorder): + for j in range(0, ntcell-1): + dd[m, j] = dd[m-1, j+1] - dd[m-1, j] + + for i in range(nx + 1): + il[i] = i - 1 + for m in range(1, iorder): + if abs(dd[m, il[i]-1+ishift]) <= abs(dd[m, il[i]+ishift]): + il[i] -= 1 + + for i in range(nx + 1): + ir[i] = i + for m in range(1, iorder): + if abs(dd[m, ir[i]-1+ishift]) <= abs(dd[m, ir[i]+ishift]): + ir[i] -= 1 + + # Reconstruction u(j+1/2) + for i in range(nx + 1): + k1 = il[i] + k2 = ir[i] + l1 = i - k1 + l2 = i - k2 + up1_2m[i] = 0 + up1_2p[i] = 0 + for m in range(iorder): + up1_2m[i] += q[k1 + ishift + m] * coef[l1, m] + up1_2p[i] += q[k2 + ishift + m] * coef[l2, m] + +def inviscid_flux(up1_2m, up1_2p, flux): + iflux = 0 + if iflux == 0: + rusanov_flux(up1_2m, up1_2p, flux) + else: + engquist_osher_flux(up1_2m, up1_2p, flux) + +def engquist_osher_flux(up1_2m, up1_2p, flux): + for i in range(nx + 1): + u_L = up1_2m[i] + u_R = up1_2p[i] + + cp = 0.5 * ( c + abs(c) ) + cm = 0.5 * ( c - abs(c) ) + + flux[i] = cp * uL + cm * u_R + +def rusanov_flux(up1_2m, up1_2p, flux): + for i in range(nx + 1): + u_L = up1_2m[i] + u_R = up1_2p[i] + F_L = c * u_L # 左状态通量 + F_R = c * u_R # 右状态通量 + alpha = abs(c) # 最大波速 + flux[i] = 0.5 * (F_L + F_R) - 0.5 * alpha * (u_R - u_L) + + +def boundary(u): + for i in range(-ighost, 1): + u[ist - 1 + i] = u[ied + i] + for i in range(1, ighost + 2): + u[ied + i] = u[ist - 1 + i] + +def update_oldfield(qn, q): + qn[:] = q[:] + +def init_coef(): + global coef + if iorder == 1: + coef[0] = [1.0] + coef[1] = [1.0] + elif iorder == 2: + coef[0] = [3.0/2.0, -1.0/2.0] + coef[1] = [1.0/2.0, 1.0/2.0] + coef[2] = [-1.0/2.0, 3.0/2.0] + elif iorder == 3: + coef[0] = [ 11.0/6.0, -7.0/6.0, 1.0/3.0 ] + coef[1] = [ 1.0/3.0, 5.0/6.0, -1.0/6.0 ] + coef[2] = [ -1.0/6.0, 5.0/6.0, 1.0/3.0 ] + coef[3] = [ 1.0/3.0, -7.0/6.0, 11.0/6.0 ] + elif iorder == 4: + coef[0] = [ 25.0/12.0, -23.0/12.0, 13.0/12.0, -1.0/4.0 ] + coef[1] = [ 1.0/4.0, 13.0/12.0, -5.0/12.0, 1.0/12.0 ] + coef[2] = [ -1.0/12.0, 7.0/12.0, 7.0/12.0, -1.0/12.0 ] + coef[3] = [ 1.0/12.0, -5.0/12.0, 13.0/12.0, 1.0/4.0 ] + coef[4] = [ -1.0/4.0, 13.0/12.0, -23.0/12.0, 25.0/12.0 ] + elif iorder == 5: + coef[0] = [ 137.0/60.0, -163.0/60.0, 137.0/60.0, -21.0/20.0, 1.0/5.0 ] + coef[1] = [ 1.0/5.0, 77.0/60.0, -43.0/60.0, 17.0/60.0, -1.0/20.0 ] + coef[2] = [ -1.0/20.0, 9.0/20.0, 47.0/60.0, -13.0/60.0, 1.0/30.0 ] + coef[3] = [ 1.0/30.0, -13.0/60.0, 47.0/60.0, 9.0/20.0, -1.0/20.0 ] + coef[4] = [ -1.0/20.0, 17.0/60.0, -43.0/60.0, 77.0/60.0, 1.0/5.0 ] + coef[5] = [ 1.0/5.0, -21.0/20.0, 137.0/60.0, -163.0/60.0, 137.0/60.0 ] + elif iorder == 6: + coef[0] = [ 49.0/20.0, -71.0/20.0, 79.0/20.0, -163.0/60.0, 31.0/30.0, -1.0/6.0 ] + coef[1] = [ 1.0/6.0, 29.0/20.0, -21.0/20.0, 37.0/60.0, -13.0/60.0, 1.0/30.0 ] + coef[2] = [ -1.0/30.0, 11.0/30.0, 19.0/20.0, -23.0/60.0, 7.0/60.0, -1.0/60.0 ] + coef[3] = [ 1.0/60.0, -2.0/15.0, 37.0/60.0, 37.0/60.0, -2.0/15.0, 1.0/60.0 ] + coef[4] = [ -1.0/60.0, 7.0/60.0, -23.0/60.0, 19.0/20.0, 11.0/30.0, -1.0/30.0 ] + coef[5] = [ 1.0/30.0, -13.0/60.0, 37.0/60.0, -21.0/20.0, 29.0/20.0, 1.0/6.0 ] + coef[6] = [ -1.0/6.0, 31.0/30.0, -163.0/60.0, 79.0/20.0, -71.0/20.0, 49.0/20.0 ] + elif iorder == 7: + coef[0] = [ 363.0/140.0, -617.0/140.0, 853.0/140.0, -2341.0/420.0, 667.0/210.0, -43.0/42.0, 1.0/7.0 ] + coef[1] = [ 1.0/7.0, 223.0/140.0, -197.0/140.0, 153.0/140.0, -241.0/420.0, 37.0/210.0, -1.0/42.0 ] + coef[2] = [ -1.0/42.0, 13.0/42.0, 153.0/140.0, -241.0/420.0, 109.0/420.0, -31.0/420.0, 1.0/105.0 ] + coef[3] = [ 1.0/105.0, -19.0/210.0, 107.0/210.0, 319.0/420.0, -101.0/420.0, 5.0/84.0, -1.0/140.0 ] + coef[4] = [ -1.0/140.0, 5.0/84.0, -101.0/420.0, 319.0/420.0, 107.0/210.0, -19.0/210.0, 1.0/105.0 ] + coef[5] = [ 1.0/105.0, -31.0/420.0, 109.0/420.0, -241.0/420.0, 153.0/140.0, 13.0/42.0, -1.0/42.0 ] + coef[6] = [ -1.0/42.0, 37.0/210.0, -241.0/420.0, 153.0/140.0, -197.0/140.0, 223.0/140.0, 1.0/7.0 ] + coef[7] = [ 1.0/7.0, -43.0/42.0, 667.0/210.0, -2341.0/420.0, 853.0/140.0, -617.0/140.0, 363.0/140.0 ] + +def init_mesh(): + global xstart, xend, dx, x, xcc + xstart = 0.0 + xend = L + dx = (xend - xstart) / nx + + for i in range(0, nx+1): + x[i] = xstart + i * dx + + for i in range(0, nx): + xcc[i] = 0.5 * (x[i] + x[i + 1]) + +def init_field(): + global u, un + for i in range(ist, ied + 1): + j = i - ist + if 0.5 <= xcc[j] <= 1.0: + u[i] = 2.0 + else: + u[i] = 1.0 + boundary(u) + update_oldfield(un, u) + +def runge_kutta(): + if rk == 1: + runge_kutta_1() + elif rk == 2: + runge_kutta_2() + else: + runge_kutta_3() + +def runge_kutta_1(): + global u, un, dt + residual(u) + for i in range(nx): + j = i + ishift + u[j] = u[j] + dt * res[i] + boundary(u) + update_oldfield(un, u) + +def runge_kutta_2(): + global u, un, dt + residual(u) + for i in range(nx): + j = i + ishift + u[j] = u[j] + dt * res[i] + boundary(u) + + residual(u) + for i in range(nx): + j = i + ishift + u[j] = 0.5 * un[j] + 0.5 * u[j] + 0.5 * dt * res[i] + boundary(u) + update_oldfield(un, u) + +def runge_kutta_3(): + global u, un, dt + residual(u) + for i in range(nx): + j = i + ishift + u[j] = u[j] + dt * res[i] + boundary(u) + + residual(u) + for i in range(nx): + j = i + ishift + u[j] = 0.75 * un[j] + 0.25 * u[j] + 0.25 * dt * res[i] + boundary(u) + + residual(u) + c1, c2, c3 = 1.0/3.0, 2.0/3.0, 2.0/3.0 + for i in range(nx): + j = i + ishift + u[j] = c1 * un[j] + c2 * u[j] + c3 * dt * res[i] + boundary(u) + update_oldfield(un, u) + +def get_ordinal_numbers(order): + if order == 1: + return 'st' + elif order == 2: + return 'nd' + elif order == 3: + return 'rd' + else: + return 'th' + +def visualize(): + with open('solution.plt', 'w') as f: + for i in range(ist, ied + 1): + j = i - ist + f.write(f"{xcc[j]:20.10e}{u[i]:20.10e}\n") + + # 可视化 + u_numerical = np.copy(u[ist:ied+1]) + print(f'u_numerical.size={u_numerical.size}') + print(f'xcc.size={xcc.size}') + #计算理论解 + u_analytical = analytical_solution(xcc, T, c) + print(f'u_analytical.size={u_analytical.size}') + plt.figure("OneFLOW-CFD Solver", figsize=(10, 6)) + plt.scatter(xcc, u_numerical, facecolor="none", edgecolor="blue", s=20, linewidths=0.5, label=f'Numerical (Rusanov)') + plt.plot(xcc, u_analytical, 'r--', label='Analytical') + plt.xlabel('x') + plt.ylabel('u') + ordinal1 = get_ordinal_numbers(iorder) + ordinal2 = get_ordinal_numbers(rk) + plt.title(f'1D Convection Equation at t = {T:.3f} using {iorder}{ordinal1}-order ENO and {rk}{ordinal2}-order Runge-Kutta methods') + plt.legend() + plt.grid(True, color='gray', linestyle='--', linewidth=0.5, alpha=0.7) + plt.tight_layout() + plt.show() + +# Global constants and variables +nx = 40 +rk = 2 +iorder = 5 +ighost = iorder +ishift = ighost + 1 +ist = 0 + ishift +ied = nx - 1 + ishift +ntcell = nx + 2 * ishift +isize = iorder * (iorder + 1) + +il = np.zeros(nx + 1, dtype=int) +ir = np.zeros(nx + 1, dtype=int) +coef = np.zeros((iorder + 1, iorder)) +dd = np.zeros((iorder, ntcell)) +up1_2m = np.zeros(nx + 1) +up1_2p = np.zeros(nx + 1) +flux = np.zeros(nx + 1) +res = np.zeros(nx) +dt = 0.0 + +# Mesh module variables +xstart = 0.0 +xend = 0.0 +L = 2.0 +dx = 0.0 +x = np.zeros(nx + 1) +xcc = np.zeros(nx) + +# Field module variables +u = np.zeros(ntcell) +un = np.zeros(ntcell) + +def main(): + global dt, T, c + init_coef() + init_mesh() + init_field() + + c = 1.0 + T = 0.625 + dt = .0025 + nt = int(T / dt) + simu_time = T + + t = 0.0 + + while t < simu_time: + runge_kutta() + t += dt + if t + dt > simu_time: + dt = simu_time - t + + print(t) + visualize() + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/example/1d-linear-convection/eno/rusanov/rk2/eno5/01/plot.py b/example/1d-linear-convection/eno/rusanov/rk2/eno5/01/plot.py new file mode 100644 index 00000000..e389044c --- /dev/null +++ b/example/1d-linear-convection/eno/rusanov/rk2/eno5/01/plot.py @@ -0,0 +1,53 @@ +import numpy as np +import matplotlib.pyplot as plt +import csv +import sys + +nvar = len(sys.argv) +print('nvar=',nvar) +print('sys.argv=',sys.argv) + +order = 1 +if nvar >= 2: + var = sys.argv[1] + print('var=',var) + order = int(var) + +print('order=',order) + +x_list = [] +u_list = [] + +with open('solution.plt', newline='') as csvfile: + #readCSV = csv.reader(csvfile, delimiter= ' ') + icount = 0 + for line in csvfile: + # 去除首尾空格,按连续空格分割 + row = line.strip().split() + #print("row=",row) + x_list.append(row[0]) + u_list.append(row[1]) + icount += 1 + +ni = icount +print("ni=",ni) + +#print("x_list=",x_list) + +x = np.zeros( ni ) +u = np.zeros( ni ) + +for i in range(0, ni): + x[i] = float(x_list[i]) + u[i] = float(u_list[i]) + +labelname = 'Eno' + str(order) + +plt.figure("OneFLOW-CFD Solver", figsize=(8, 6), dpi=100) +plt.plot(x, u, "b-", linewidth=1.0, marker = 's', markerfacecolor='None', label=labelname) +plt.xlabel("$x$") +plt.ylabel("$u$") +plt.title("burgers T=1") +plt.legend() +plt.tight_layout() +plt.show(); \ No newline at end of file diff --git a/example/1d-linear-convection/eno/rusanov/rk2/eno6/01/eno.py b/example/1d-linear-convection/eno/rusanov/rk2/eno6/01/eno.py new file mode 100644 index 00000000..1381a8aa --- /dev/null +++ b/example/1d-linear-convection/eno/rusanov/rk2/eno6/01/eno.py @@ -0,0 +1,311 @@ +import numpy as np +import matplotlib.pyplot as plt + +# 初始条件 +def initial_condition(x): + u0 = np.zeros_like(x) + for i in range(len(x)): + if 0.5 <= x[i] <= 1.0: + u0[i] = 2.0 + else: + u0[i] = 1.0 + return u0 + +# 理论解 +def analytical_solution(x, t, a): + # 初始条件沿 x - at 平移 + x_shifted = x - a * t + return initial_condition((x_shifted + L) % L) # 周期边界条件 + +def residual(q): + reconstruction(q) + inviscid_flux(up1_2m, up1_2p, flux) + for i in range(nx): + res[i] = -(flux[i + 1] - flux[i]) / dx + +def reconstruction(q): + global il, ir, dd, up1_2m, up1_2p + + # Choose the stencil by ENO method + dd[0, 0:ntcell-1] = q[0:ntcell-1] + + for m in range(1, iorder): + for j in range(0, ntcell-1): + dd[m, j] = dd[m-1, j+1] - dd[m-1, j] + + for i in range(nx + 1): + il[i] = i - 1 + for m in range(1, iorder): + if abs(dd[m, il[i]-1+ishift]) <= abs(dd[m, il[i]+ishift]): + il[i] -= 1 + + for i in range(nx + 1): + ir[i] = i + for m in range(1, iorder): + if abs(dd[m, ir[i]-1+ishift]) <= abs(dd[m, ir[i]+ishift]): + ir[i] -= 1 + + # Reconstruction u(j+1/2) + for i in range(nx + 1): + k1 = il[i] + k2 = ir[i] + l1 = i - k1 + l2 = i - k2 + up1_2m[i] = 0 + up1_2p[i] = 0 + for m in range(iorder): + up1_2m[i] += q[k1 + ishift + m] * coef[l1, m] + up1_2p[i] += q[k2 + ishift + m] * coef[l2, m] + +def inviscid_flux(up1_2m, up1_2p, flux): + iflux = 0 + if iflux == 0: + rusanov_flux(up1_2m, up1_2p, flux) + else: + engquist_osher_flux(up1_2m, up1_2p, flux) + +def engquist_osher_flux(up1_2m, up1_2p, flux): + for i in range(nx + 1): + u_L = up1_2m[i] + u_R = up1_2p[i] + + cp = 0.5 * ( c + abs(c) ) + cm = 0.5 * ( c - abs(c) ) + + flux[i] = cp * uL + cm * u_R + +def rusanov_flux(up1_2m, up1_2p, flux): + for i in range(nx + 1): + u_L = up1_2m[i] + u_R = up1_2p[i] + F_L = c * u_L # 左状态通量 + F_R = c * u_R # 右状态通量 + alpha = abs(c) # 最大波速 + flux[i] = 0.5 * (F_L + F_R) - 0.5 * alpha * (u_R - u_L) + + +def boundary(u): + for i in range(-ighost, 1): + u[ist - 1 + i] = u[ied + i] + for i in range(1, ighost + 2): + u[ied + i] = u[ist - 1 + i] + +def update_oldfield(qn, q): + qn[:] = q[:] + +def init_coef(): + global coef + if iorder == 1: + coef[0] = [1.0] + coef[1] = [1.0] + elif iorder == 2: + coef[0] = [3.0/2.0, -1.0/2.0] + coef[1] = [1.0/2.0, 1.0/2.0] + coef[2] = [-1.0/2.0, 3.0/2.0] + elif iorder == 3: + coef[0] = [ 11.0/6.0, -7.0/6.0, 1.0/3.0 ] + coef[1] = [ 1.0/3.0, 5.0/6.0, -1.0/6.0 ] + coef[2] = [ -1.0/6.0, 5.0/6.0, 1.0/3.0 ] + coef[3] = [ 1.0/3.0, -7.0/6.0, 11.0/6.0 ] + elif iorder == 4: + coef[0] = [ 25.0/12.0, -23.0/12.0, 13.0/12.0, -1.0/4.0 ] + coef[1] = [ 1.0/4.0, 13.0/12.0, -5.0/12.0, 1.0/12.0 ] + coef[2] = [ -1.0/12.0, 7.0/12.0, 7.0/12.0, -1.0/12.0 ] + coef[3] = [ 1.0/12.0, -5.0/12.0, 13.0/12.0, 1.0/4.0 ] + coef[4] = [ -1.0/4.0, 13.0/12.0, -23.0/12.0, 25.0/12.0 ] + elif iorder == 5: + coef[0] = [ 137.0/60.0, -163.0/60.0, 137.0/60.0, -21.0/20.0, 1.0/5.0 ] + coef[1] = [ 1.0/5.0, 77.0/60.0, -43.0/60.0, 17.0/60.0, -1.0/20.0 ] + coef[2] = [ -1.0/20.0, 9.0/20.0, 47.0/60.0, -13.0/60.0, 1.0/30.0 ] + coef[3] = [ 1.0/30.0, -13.0/60.0, 47.0/60.0, 9.0/20.0, -1.0/20.0 ] + coef[4] = [ -1.0/20.0, 17.0/60.0, -43.0/60.0, 77.0/60.0, 1.0/5.0 ] + coef[5] = [ 1.0/5.0, -21.0/20.0, 137.0/60.0, -163.0/60.0, 137.0/60.0 ] + elif iorder == 6: + coef[0] = [ 49.0/20.0, -71.0/20.0, 79.0/20.0, -163.0/60.0, 31.0/30.0, -1.0/6.0 ] + coef[1] = [ 1.0/6.0, 29.0/20.0, -21.0/20.0, 37.0/60.0, -13.0/60.0, 1.0/30.0 ] + coef[2] = [ -1.0/30.0, 11.0/30.0, 19.0/20.0, -23.0/60.0, 7.0/60.0, -1.0/60.0 ] + coef[3] = [ 1.0/60.0, -2.0/15.0, 37.0/60.0, 37.0/60.0, -2.0/15.0, 1.0/60.0 ] + coef[4] = [ -1.0/60.0, 7.0/60.0, -23.0/60.0, 19.0/20.0, 11.0/30.0, -1.0/30.0 ] + coef[5] = [ 1.0/30.0, -13.0/60.0, 37.0/60.0, -21.0/20.0, 29.0/20.0, 1.0/6.0 ] + coef[6] = [ -1.0/6.0, 31.0/30.0, -163.0/60.0, 79.0/20.0, -71.0/20.0, 49.0/20.0 ] + elif iorder == 7: + coef[0] = [ 363.0/140.0, -617.0/140.0, 853.0/140.0, -2341.0/420.0, 667.0/210.0, -43.0/42.0, 1.0/7.0 ] + coef[1] = [ 1.0/7.0, 223.0/140.0, -197.0/140.0, 153.0/140.0, -241.0/420.0, 37.0/210.0, -1.0/42.0 ] + coef[2] = [ -1.0/42.0, 13.0/42.0, 153.0/140.0, -241.0/420.0, 109.0/420.0, -31.0/420.0, 1.0/105.0 ] + coef[3] = [ 1.0/105.0, -19.0/210.0, 107.0/210.0, 319.0/420.0, -101.0/420.0, 5.0/84.0, -1.0/140.0 ] + coef[4] = [ -1.0/140.0, 5.0/84.0, -101.0/420.0, 319.0/420.0, 107.0/210.0, -19.0/210.0, 1.0/105.0 ] + coef[5] = [ 1.0/105.0, -31.0/420.0, 109.0/420.0, -241.0/420.0, 153.0/140.0, 13.0/42.0, -1.0/42.0 ] + coef[6] = [ -1.0/42.0, 37.0/210.0, -241.0/420.0, 153.0/140.0, -197.0/140.0, 223.0/140.0, 1.0/7.0 ] + coef[7] = [ 1.0/7.0, -43.0/42.0, 667.0/210.0, -2341.0/420.0, 853.0/140.0, -617.0/140.0, 363.0/140.0 ] + +def init_mesh(): + global xstart, xend, dx, x, xcc + xstart = 0.0 + xend = L + dx = (xend - xstart) / nx + + for i in range(0, nx+1): + x[i] = xstart + i * dx + + for i in range(0, nx): + xcc[i] = 0.5 * (x[i] + x[i + 1]) + +def init_field(): + global u, un + for i in range(ist, ied + 1): + j = i - ist + if 0.5 <= xcc[j] <= 1.0: + u[i] = 2.0 + else: + u[i] = 1.0 + boundary(u) + update_oldfield(un, u) + +def runge_kutta(): + if rk == 1: + runge_kutta_1() + elif rk == 2: + runge_kutta_2() + else: + runge_kutta_3() + +def runge_kutta_1(): + global u, un, dt + residual(u) + for i in range(nx): + j = i + ishift + u[j] = u[j] + dt * res[i] + boundary(u) + update_oldfield(un, u) + +def runge_kutta_2(): + global u, un, dt + residual(u) + for i in range(nx): + j = i + ishift + u[j] = u[j] + dt * res[i] + boundary(u) + + residual(u) + for i in range(nx): + j = i + ishift + u[j] = 0.5 * un[j] + 0.5 * u[j] + 0.5 * dt * res[i] + boundary(u) + update_oldfield(un, u) + +def runge_kutta_3(): + global u, un, dt + residual(u) + for i in range(nx): + j = i + ishift + u[j] = u[j] + dt * res[i] + boundary(u) + + residual(u) + for i in range(nx): + j = i + ishift + u[j] = 0.75 * un[j] + 0.25 * u[j] + 0.25 * dt * res[i] + boundary(u) + + residual(u) + c1, c2, c3 = 1.0/3.0, 2.0/3.0, 2.0/3.0 + for i in range(nx): + j = i + ishift + u[j] = c1 * un[j] + c2 * u[j] + c3 * dt * res[i] + boundary(u) + update_oldfield(un, u) + +def get_ordinal_numbers(order): + if order == 1: + return 'st' + elif order == 2: + return 'nd' + elif order == 3: + return 'rd' + else: + return 'th' + +def visualize(): + with open('solution.plt', 'w') as f: + for i in range(ist, ied + 1): + j = i - ist + f.write(f"{xcc[j]:20.10e}{u[i]:20.10e}\n") + + # 可视化 + u_numerical = np.copy(u[ist:ied+1]) + print(f'u_numerical.size={u_numerical.size}') + print(f'xcc.size={xcc.size}') + #计算理论解 + u_analytical = analytical_solution(xcc, T, c) + print(f'u_analytical.size={u_analytical.size}') + plt.figure("OneFLOW-CFD Solver", figsize=(10, 6)) + plt.scatter(xcc, u_numerical, facecolor="none", edgecolor="blue", s=20, linewidths=0.5, label=f'Numerical (Rusanov)') + plt.plot(xcc, u_analytical, 'r--', label='Analytical') + plt.xlabel('x') + plt.ylabel('u') + ordinal1 = get_ordinal_numbers(iorder) + ordinal2 = get_ordinal_numbers(rk) + plt.title(f'1D Convection Equation at t = {T:.3f} using {iorder}{ordinal1}-order ENO and {rk}{ordinal2}-order Runge-Kutta methods') + plt.legend() + plt.grid(True, color='gray', linestyle='--', linewidth=0.5, alpha=0.7) + plt.tight_layout() + plt.show() + +# Global constants and variables +nx = 40 +rk = 2 +iorder = 6 +ighost = iorder +ishift = ighost + 1 +ist = 0 + ishift +ied = nx - 1 + ishift +ntcell = nx + 2 * ishift +isize = iorder * (iorder + 1) + +il = np.zeros(nx + 1, dtype=int) +ir = np.zeros(nx + 1, dtype=int) +coef = np.zeros((iorder + 1, iorder)) +dd = np.zeros((iorder, ntcell)) +up1_2m = np.zeros(nx + 1) +up1_2p = np.zeros(nx + 1) +flux = np.zeros(nx + 1) +res = np.zeros(nx) +dt = 0.0 + +# Mesh module variables +xstart = 0.0 +xend = 0.0 +L = 2.0 +dx = 0.0 +x = np.zeros(nx + 1) +xcc = np.zeros(nx) + +# Field module variables +u = np.zeros(ntcell) +un = np.zeros(ntcell) + +def main(): + global dt, T, c + init_coef() + init_mesh() + init_field() + + c = 1.0 + T = 0.625 + dt = .0025 + nt = int(T / dt) + simu_time = T + + t = 0.0 + + while t < simu_time: + runge_kutta() + t += dt + if t + dt > simu_time: + dt = simu_time - t + + print(t) + visualize() + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/example/1d-linear-convection/eno/rusanov/rk2/eno6/01/plot.py b/example/1d-linear-convection/eno/rusanov/rk2/eno6/01/plot.py new file mode 100644 index 00000000..e389044c --- /dev/null +++ b/example/1d-linear-convection/eno/rusanov/rk2/eno6/01/plot.py @@ -0,0 +1,53 @@ +import numpy as np +import matplotlib.pyplot as plt +import csv +import sys + +nvar = len(sys.argv) +print('nvar=',nvar) +print('sys.argv=',sys.argv) + +order = 1 +if nvar >= 2: + var = sys.argv[1] + print('var=',var) + order = int(var) + +print('order=',order) + +x_list = [] +u_list = [] + +with open('solution.plt', newline='') as csvfile: + #readCSV = csv.reader(csvfile, delimiter= ' ') + icount = 0 + for line in csvfile: + # 去除首尾空格,按连续空格分割 + row = line.strip().split() + #print("row=",row) + x_list.append(row[0]) + u_list.append(row[1]) + icount += 1 + +ni = icount +print("ni=",ni) + +#print("x_list=",x_list) + +x = np.zeros( ni ) +u = np.zeros( ni ) + +for i in range(0, ni): + x[i] = float(x_list[i]) + u[i] = float(u_list[i]) + +labelname = 'Eno' + str(order) + +plt.figure("OneFLOW-CFD Solver", figsize=(8, 6), dpi=100) +plt.plot(x, u, "b-", linewidth=1.0, marker = 's', markerfacecolor='None', label=labelname) +plt.xlabel("$x$") +plt.ylabel("$u$") +plt.title("burgers T=1") +plt.legend() +plt.tight_layout() +plt.show(); \ No newline at end of file diff --git a/example/1d-linear-convection/eno/rusanov/rk2/eno7/01/eno.py b/example/1d-linear-convection/eno/rusanov/rk2/eno7/01/eno.py new file mode 100644 index 00000000..a80f611e --- /dev/null +++ b/example/1d-linear-convection/eno/rusanov/rk2/eno7/01/eno.py @@ -0,0 +1,311 @@ +import numpy as np +import matplotlib.pyplot as plt + +# 初始条件 +def initial_condition(x): + u0 = np.zeros_like(x) + for i in range(len(x)): + if 0.5 <= x[i] <= 1.0: + u0[i] = 2.0 + else: + u0[i] = 1.0 + return u0 + +# 理论解 +def analytical_solution(x, t, a): + # 初始条件沿 x - at 平移 + x_shifted = x - a * t + return initial_condition((x_shifted + L) % L) # 周期边界条件 + +def residual(q): + reconstruction(q) + inviscid_flux(up1_2m, up1_2p, flux) + for i in range(nx): + res[i] = -(flux[i + 1] - flux[i]) / dx + +def reconstruction(q): + global il, ir, dd, up1_2m, up1_2p + + # Choose the stencil by ENO method + dd[0, 0:ntcell-1] = q[0:ntcell-1] + + for m in range(1, iorder): + for j in range(0, ntcell-1): + dd[m, j] = dd[m-1, j+1] - dd[m-1, j] + + for i in range(nx + 1): + il[i] = i - 1 + for m in range(1, iorder): + if abs(dd[m, il[i]-1+ishift]) <= abs(dd[m, il[i]+ishift]): + il[i] -= 1 + + for i in range(nx + 1): + ir[i] = i + for m in range(1, iorder): + if abs(dd[m, ir[i]-1+ishift]) <= abs(dd[m, ir[i]+ishift]): + ir[i] -= 1 + + # Reconstruction u(j+1/2) + for i in range(nx + 1): + k1 = il[i] + k2 = ir[i] + l1 = i - k1 + l2 = i - k2 + up1_2m[i] = 0 + up1_2p[i] = 0 + for m in range(iorder): + up1_2m[i] += q[k1 + ishift + m] * coef[l1, m] + up1_2p[i] += q[k2 + ishift + m] * coef[l2, m] + +def inviscid_flux(up1_2m, up1_2p, flux): + iflux = 0 + if iflux == 0: + rusanov_flux(up1_2m, up1_2p, flux) + else: + engquist_osher_flux(up1_2m, up1_2p, flux) + +def engquist_osher_flux(up1_2m, up1_2p, flux): + for i in range(nx + 1): + u_L = up1_2m[i] + u_R = up1_2p[i] + + cp = 0.5 * ( c + abs(c) ) + cm = 0.5 * ( c - abs(c) ) + + flux[i] = cp * uL + cm * u_R + +def rusanov_flux(up1_2m, up1_2p, flux): + for i in range(nx + 1): + u_L = up1_2m[i] + u_R = up1_2p[i] + F_L = c * u_L # 左状态通量 + F_R = c * u_R # 右状态通量 + alpha = abs(c) # 最大波速 + flux[i] = 0.5 * (F_L + F_R) - 0.5 * alpha * (u_R - u_L) + + +def boundary(u): + for i in range(-ighost, 1): + u[ist - 1 + i] = u[ied + i] + for i in range(1, ighost + 2): + u[ied + i] = u[ist - 1 + i] + +def update_oldfield(qn, q): + qn[:] = q[:] + +def init_coef(): + global coef + if iorder == 1: + coef[0] = [1.0] + coef[1] = [1.0] + elif iorder == 2: + coef[0] = [3.0/2.0, -1.0/2.0] + coef[1] = [1.0/2.0, 1.0/2.0] + coef[2] = [-1.0/2.0, 3.0/2.0] + elif iorder == 3: + coef[0] = [ 11.0/6.0, -7.0/6.0, 1.0/3.0 ] + coef[1] = [ 1.0/3.0, 5.0/6.0, -1.0/6.0 ] + coef[2] = [ -1.0/6.0, 5.0/6.0, 1.0/3.0 ] + coef[3] = [ 1.0/3.0, -7.0/6.0, 11.0/6.0 ] + elif iorder == 4: + coef[0] = [ 25.0/12.0, -23.0/12.0, 13.0/12.0, -1.0/4.0 ] + coef[1] = [ 1.0/4.0, 13.0/12.0, -5.0/12.0, 1.0/12.0 ] + coef[2] = [ -1.0/12.0, 7.0/12.0, 7.0/12.0, -1.0/12.0 ] + coef[3] = [ 1.0/12.0, -5.0/12.0, 13.0/12.0, 1.0/4.0 ] + coef[4] = [ -1.0/4.0, 13.0/12.0, -23.0/12.0, 25.0/12.0 ] + elif iorder == 5: + coef[0] = [ 137.0/60.0, -163.0/60.0, 137.0/60.0, -21.0/20.0, 1.0/5.0 ] + coef[1] = [ 1.0/5.0, 77.0/60.0, -43.0/60.0, 17.0/60.0, -1.0/20.0 ] + coef[2] = [ -1.0/20.0, 9.0/20.0, 47.0/60.0, -13.0/60.0, 1.0/30.0 ] + coef[3] = [ 1.0/30.0, -13.0/60.0, 47.0/60.0, 9.0/20.0, -1.0/20.0 ] + coef[4] = [ -1.0/20.0, 17.0/60.0, -43.0/60.0, 77.0/60.0, 1.0/5.0 ] + coef[5] = [ 1.0/5.0, -21.0/20.0, 137.0/60.0, -163.0/60.0, 137.0/60.0 ] + elif iorder == 6: + coef[0] = [ 49.0/20.0, -71.0/20.0, 79.0/20.0, -163.0/60.0, 31.0/30.0, -1.0/6.0 ] + coef[1] = [ 1.0/6.0, 29.0/20.0, -21.0/20.0, 37.0/60.0, -13.0/60.0, 1.0/30.0 ] + coef[2] = [ -1.0/30.0, 11.0/30.0, 19.0/20.0, -23.0/60.0, 7.0/60.0, -1.0/60.0 ] + coef[3] = [ 1.0/60.0, -2.0/15.0, 37.0/60.0, 37.0/60.0, -2.0/15.0, 1.0/60.0 ] + coef[4] = [ -1.0/60.0, 7.0/60.0, -23.0/60.0, 19.0/20.0, 11.0/30.0, -1.0/30.0 ] + coef[5] = [ 1.0/30.0, -13.0/60.0, 37.0/60.0, -21.0/20.0, 29.0/20.0, 1.0/6.0 ] + coef[6] = [ -1.0/6.0, 31.0/30.0, -163.0/60.0, 79.0/20.0, -71.0/20.0, 49.0/20.0 ] + elif iorder == 7: + coef[0] = [ 363.0/140.0, -617.0/140.0, 853.0/140.0, -2341.0/420.0, 667.0/210.0, -43.0/42.0, 1.0/7.0 ] + coef[1] = [ 1.0/7.0, 223.0/140.0, -197.0/140.0, 153.0/140.0, -241.0/420.0, 37.0/210.0, -1.0/42.0 ] + coef[2] = [ -1.0/42.0, 13.0/42.0, 153.0/140.0, -241.0/420.0, 109.0/420.0, -31.0/420.0, 1.0/105.0 ] + coef[3] = [ 1.0/105.0, -19.0/210.0, 107.0/210.0, 319.0/420.0, -101.0/420.0, 5.0/84.0, -1.0/140.0 ] + coef[4] = [ -1.0/140.0, 5.0/84.0, -101.0/420.0, 319.0/420.0, 107.0/210.0, -19.0/210.0, 1.0/105.0 ] + coef[5] = [ 1.0/105.0, -31.0/420.0, 109.0/420.0, -241.0/420.0, 153.0/140.0, 13.0/42.0, -1.0/42.0 ] + coef[6] = [ -1.0/42.0, 37.0/210.0, -241.0/420.0, 153.0/140.0, -197.0/140.0, 223.0/140.0, 1.0/7.0 ] + coef[7] = [ 1.0/7.0, -43.0/42.0, 667.0/210.0, -2341.0/420.0, 853.0/140.0, -617.0/140.0, 363.0/140.0 ] + +def init_mesh(): + global xstart, xend, dx, x, xcc + xstart = 0.0 + xend = L + dx = (xend - xstart) / nx + + for i in range(0, nx+1): + x[i] = xstart + i * dx + + for i in range(0, nx): + xcc[i] = 0.5 * (x[i] + x[i + 1]) + +def init_field(): + global u, un + for i in range(ist, ied + 1): + j = i - ist + if 0.5 <= xcc[j] <= 1.0: + u[i] = 2.0 + else: + u[i] = 1.0 + boundary(u) + update_oldfield(un, u) + +def runge_kutta(): + if rk == 1: + runge_kutta_1() + elif rk == 2: + runge_kutta_2() + else: + runge_kutta_3() + +def runge_kutta_1(): + global u, un, dt + residual(u) + for i in range(nx): + j = i + ishift + u[j] = u[j] + dt * res[i] + boundary(u) + update_oldfield(un, u) + +def runge_kutta_2(): + global u, un, dt + residual(u) + for i in range(nx): + j = i + ishift + u[j] = u[j] + dt * res[i] + boundary(u) + + residual(u) + for i in range(nx): + j = i + ishift + u[j] = 0.5 * un[j] + 0.5 * u[j] + 0.5 * dt * res[i] + boundary(u) + update_oldfield(un, u) + +def runge_kutta_3(): + global u, un, dt + residual(u) + for i in range(nx): + j = i + ishift + u[j] = u[j] + dt * res[i] + boundary(u) + + residual(u) + for i in range(nx): + j = i + ishift + u[j] = 0.75 * un[j] + 0.25 * u[j] + 0.25 * dt * res[i] + boundary(u) + + residual(u) + c1, c2, c3 = 1.0/3.0, 2.0/3.0, 2.0/3.0 + for i in range(nx): + j = i + ishift + u[j] = c1 * un[j] + c2 * u[j] + c3 * dt * res[i] + boundary(u) + update_oldfield(un, u) + +def get_ordinal_numbers(order): + if order == 1: + return 'st' + elif order == 2: + return 'nd' + elif order == 3: + return 'rd' + else: + return 'th' + +def visualize(): + with open('solution.plt', 'w') as f: + for i in range(ist, ied + 1): + j = i - ist + f.write(f"{xcc[j]:20.10e}{u[i]:20.10e}\n") + + # 可视化 + u_numerical = np.copy(u[ist:ied+1]) + print(f'u_numerical.size={u_numerical.size}') + print(f'xcc.size={xcc.size}') + #计算理论解 + u_analytical = analytical_solution(xcc, T, c) + print(f'u_analytical.size={u_analytical.size}') + plt.figure("OneFLOW-CFD Solver", figsize=(10, 6)) + plt.scatter(xcc, u_numerical, facecolor="none", edgecolor="blue", s=20, linewidths=0.5, label=f'Numerical (Rusanov)') + plt.plot(xcc, u_analytical, 'r--', label='Analytical') + plt.xlabel('x') + plt.ylabel('u') + ordinal1 = get_ordinal_numbers(iorder) + ordinal2 = get_ordinal_numbers(rk) + plt.title(f'1D Convection Equation at t = {T:.3f} using {iorder}{ordinal1}-order ENO and {rk}{ordinal2}-order Runge-Kutta methods') + plt.legend() + plt.grid(True, color='gray', linestyle='--', linewidth=0.5, alpha=0.7) + plt.tight_layout() + plt.show() + +# Global constants and variables +nx = 40 +rk = 2 +iorder = 7 +ighost = iorder +ishift = ighost + 1 +ist = 0 + ishift +ied = nx - 1 + ishift +ntcell = nx + 2 * ishift +isize = iorder * (iorder + 1) + +il = np.zeros(nx + 1, dtype=int) +ir = np.zeros(nx + 1, dtype=int) +coef = np.zeros((iorder + 1, iorder)) +dd = np.zeros((iorder, ntcell)) +up1_2m = np.zeros(nx + 1) +up1_2p = np.zeros(nx + 1) +flux = np.zeros(nx + 1) +res = np.zeros(nx) +dt = 0.0 + +# Mesh module variables +xstart = 0.0 +xend = 0.0 +L = 2.0 +dx = 0.0 +x = np.zeros(nx + 1) +xcc = np.zeros(nx) + +# Field module variables +u = np.zeros(ntcell) +un = np.zeros(ntcell) + +def main(): + global dt, T, c + init_coef() + init_mesh() + init_field() + + c = 1.0 + T = 0.625 + dt = .0025 + nt = int(T / dt) + simu_time = T + + t = 0.0 + + while t < simu_time: + runge_kutta() + t += dt + if t + dt > simu_time: + dt = simu_time - t + + print(t) + visualize() + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/example/1d-linear-convection/eno/rusanov/rk2/eno7/01/plot.py b/example/1d-linear-convection/eno/rusanov/rk2/eno7/01/plot.py new file mode 100644 index 00000000..e389044c --- /dev/null +++ b/example/1d-linear-convection/eno/rusanov/rk2/eno7/01/plot.py @@ -0,0 +1,53 @@ +import numpy as np +import matplotlib.pyplot as plt +import csv +import sys + +nvar = len(sys.argv) +print('nvar=',nvar) +print('sys.argv=',sys.argv) + +order = 1 +if nvar >= 2: + var = sys.argv[1] + print('var=',var) + order = int(var) + +print('order=',order) + +x_list = [] +u_list = [] + +with open('solution.plt', newline='') as csvfile: + #readCSV = csv.reader(csvfile, delimiter= ' ') + icount = 0 + for line in csvfile: + # 去除首尾空格,按连续空格分割 + row = line.strip().split() + #print("row=",row) + x_list.append(row[0]) + u_list.append(row[1]) + icount += 1 + +ni = icount +print("ni=",ni) + +#print("x_list=",x_list) + +x = np.zeros( ni ) +u = np.zeros( ni ) + +for i in range(0, ni): + x[i] = float(x_list[i]) + u[i] = float(u_list[i]) + +labelname = 'Eno' + str(order) + +plt.figure("OneFLOW-CFD Solver", figsize=(8, 6), dpi=100) +plt.plot(x, u, "b-", linewidth=1.0, marker = 's', markerfacecolor='None', label=labelname) +plt.xlabel("$x$") +plt.ylabel("$u$") +plt.title("burgers T=1") +plt.legend() +plt.tight_layout() +plt.show(); \ No newline at end of file diff --git a/example/1d-linear-convection/eno/rusanov/rk3/eno1-7/01/eno.py b/example/1d-linear-convection/eno/rusanov/rk3/eno1-7/01/eno.py new file mode 100644 index 00000000..fafd3675 --- /dev/null +++ b/example/1d-linear-convection/eno/rusanov/rk3/eno1-7/01/eno.py @@ -0,0 +1,302 @@ +import numpy as np +import matplotlib.pyplot as plt + +# 初始条件 +def initial_condition(x): + u0 = np.zeros_like(x) + for i in range(len(x)): + if 0.5 <= x[i] <= 1.0: + u0[i] = 2.0 + else: + u0[i] = 1.0 + return u0 + +# 理论解 +def analytical_solution(x, t, a, L): + # 初始条件沿 x - at 平移 + x_shifted = x - a * t + return initial_condition((x_shifted + L) % L) # 周期边界条件 + +def residual(q, eno): + reconstruction(q, eno) + inviscid_flux(eno.up1_2m, eno.up1_2p, eno.flux, eno) + for i in range(eno.nx): + eno.res[i] = -(eno.flux[i + 1] - eno.flux[i]) / eno.dx + +def reconstruction(q, eno): + # Choose the stencil by ENO method + eno.dd[0, 0:eno.ntcell-1] = q[0:eno.ntcell-1] + + for m in range(1, eno.iorder): + for j in range(0, eno.ntcell-1): + eno.dd[m, j] = eno.dd[m-1, j+1] - eno.dd[m-1, j] + + for i in range(eno.nx + 1): + eno.il[i] = i - 1 + for m in range(1, eno.iorder): + if abs(dd[m, eno.il[i]-1+eno.ishift]) <= abs(dd[m, eno.il[i]+eno.ishift]): + eno.il[i] -= 1 + + for i in range(eno.nx + 1): + eno.ir[i] = i + for m in range(1, eno.iorder): + if abs(dd[m, eno.ir[i]-1+eno.ishift]) <= abs(dd[m, ir[i]+eno.ishift]): + eno.ir[i] -= 1 + + # Reconstruction u(j+1/2) + for i in range(eno.nx + 1): + k1 = eno.il[i] + k2 = eno.ir[i] + l1 = i - k1 + l2 = i - k2 + eno.up1_2m[i] = 0 + eno.up1_2p[i] = 0 + for m in range(eno.iorder): + eno.up1_2m[i] += q[k1 + eno.ishift + m] * eno.coef[l1, m] + eno.up1_2p[i] += q[k2 + eno.ishift + m] * eno.coef[l2, m] + +def inviscid_flux(up1_2m, up1_2p, flux, eno): + iflux = 0 + if iflux == 0: + rusanov_flux(up1_2m, up1_2p, flux, eno) + else: + engquist_osher_flux(up1_2m, up1_2p, flux, eno) + +def engquist_osher_flux(up1_2m, up1_2p, flux, eno): + for i in range(eno.nx + 1): + u_L = up1_2m[i] + u_R = up1_2p[i] + + cp = 0.5 * ( eno.c + abs(eno.c) ) + cm = 0.5 * ( eno.c - abs(eno.c) ) + + flux[i] = cp * uL + cm * u_R + +def rusanov_flux(up1_2m, up1_2p, flux, eno): + for i in range(eno.nx + 1): + u_L = up1_2m[i] + u_R = up1_2p[i] + F_L = eno.c * u_L # 左状态通量 + F_R = eno.c * u_R # 右状态通量 + alpha = abs(eno.c) # 最大波速 + flux[i] = 0.5 * (F_L + F_R) - 0.5 * alpha * (u_R - u_L) + + +def boundary(u, eno): + for i in range(-eno.ighost, 1): + u[eno.ist - 1 + i] = u[eno.ied + i] + for i in range(1, eno.ighost + 2): + u[eno.ied + i] = u[eno.ist - 1 + i] + +def update_oldfield(qn, q): + qn[:] = q[:] + +def init_coef( iorder, coef ): + if iorder == 1: + coef[0] = [1.0] + coef[1] = [1.0] + elif iorder == 2: + coef[0] = [3.0/2.0, -1.0/2.0] + coef[1] = [1.0/2.0, 1.0/2.0] + coef[2] = [-1.0/2.0, 3.0/2.0] + elif iorder == 3: + coef[0] = [ 11.0/6.0, -7.0/6.0, 1.0/3.0 ] + coef[1] = [ 1.0/3.0, 5.0/6.0, -1.0/6.0 ] + coef[2] = [ -1.0/6.0, 5.0/6.0, 1.0/3.0 ] + coef[3] = [ 1.0/3.0, -7.0/6.0, 11.0/6.0 ] + elif iorder == 4: + coef[0] = [ 25.0/12.0, -23.0/12.0, 13.0/12.0, -1.0/4.0 ] + coef[1] = [ 1.0/4.0, 13.0/12.0, -5.0/12.0, 1.0/12.0 ] + coef[2] = [ -1.0/12.0, 7.0/12.0, 7.0/12.0, -1.0/12.0 ] + coef[3] = [ 1.0/12.0, -5.0/12.0, 13.0/12.0, 1.0/4.0 ] + coef[4] = [ -1.0/4.0, 13.0/12.0, -23.0/12.0, 25.0/12.0 ] + elif iorder == 5: + coef[0] = [ 137.0/60.0, -163.0/60.0, 137.0/60.0, -21.0/20.0, 1.0/5.0 ] + coef[1] = [ 1.0/5.0, 77.0/60.0, -43.0/60.0, 17.0/60.0, -1.0/20.0 ] + coef[2] = [ -1.0/20.0, 9.0/20.0, 47.0/60.0, -13.0/60.0, 1.0/30.0 ] + coef[3] = [ 1.0/30.0, -13.0/60.0, 47.0/60.0, 9.0/20.0, -1.0/20.0 ] + coef[4] = [ -1.0/20.0, 17.0/60.0, -43.0/60.0, 77.0/60.0, 1.0/5.0 ] + coef[5] = [ 1.0/5.0, -21.0/20.0, 137.0/60.0, -163.0/60.0, 137.0/60.0 ] + elif iorder == 6: + coef[0] = [ 49.0/20.0, -71.0/20.0, 79.0/20.0, -163.0/60.0, 31.0/30.0, -1.0/6.0 ] + coef[1] = [ 1.0/6.0, 29.0/20.0, -21.0/20.0, 37.0/60.0, -13.0/60.0, 1.0/30.0 ] + coef[2] = [ -1.0/30.0, 11.0/30.0, 19.0/20.0, -23.0/60.0, 7.0/60.0, -1.0/60.0 ] + coef[3] = [ 1.0/60.0, -2.0/15.0, 37.0/60.0, 37.0/60.0, -2.0/15.0, 1.0/60.0 ] + coef[4] = [ -1.0/60.0, 7.0/60.0, -23.0/60.0, 19.0/20.0, 11.0/30.0, -1.0/30.0 ] + coef[5] = [ 1.0/30.0, -13.0/60.0, 37.0/60.0, -21.0/20.0, 29.0/20.0, 1.0/6.0 ] + coef[6] = [ -1.0/6.0, 31.0/30.0, -163.0/60.0, 79.0/20.0, -71.0/20.0, 49.0/20.0 ] + elif iorder == 7: + coef[0] = [ 363.0/140.0, -617.0/140.0, 853.0/140.0, -2341.0/420.0, 667.0/210.0, -43.0/42.0, 1.0/7.0 ] + coef[1] = [ 1.0/7.0, 223.0/140.0, -197.0/140.0, 153.0/140.0, -241.0/420.0, 37.0/210.0, -1.0/42.0 ] + coef[2] = [ -1.0/42.0, 13.0/42.0, 153.0/140.0, -241.0/420.0, 109.0/420.0, -31.0/420.0, 1.0/105.0 ] + coef[3] = [ 1.0/105.0, -19.0/210.0, 107.0/210.0, 319.0/420.0, -101.0/420.0, 5.0/84.0, -1.0/140.0 ] + coef[4] = [ -1.0/140.0, 5.0/84.0, -101.0/420.0, 319.0/420.0, 107.0/210.0, -19.0/210.0, 1.0/105.0 ] + coef[5] = [ 1.0/105.0, -31.0/420.0, 109.0/420.0, -241.0/420.0, 153.0/140.0, 13.0/42.0, -1.0/42.0 ] + coef[6] = [ -1.0/42.0, 37.0/210.0, -241.0/420.0, 153.0/140.0, -197.0/140.0, 223.0/140.0, 1.0/7.0 ] + coef[7] = [ 1.0/7.0, -43.0/42.0, 667.0/210.0, -2341.0/420.0, 853.0/140.0, -617.0/140.0, 363.0/140.0 ] + +def init_field(eno): + for i in range(eno.ist, eno.ied + 1): + j = i - eno.ist + if 0.5 <= eno.xcc[j] <= 1.0: + eno.u[i] = 2.0 + else: + eno.u[i] = 1.0 + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def runge_kutta(eno): + rk = eno.rk + if rk == 1: + runge_kutta_1(eno) + elif rk == 2: + runge_kutta_2(eno) + else: + runge_kutta_3(eno) + +def runge_kutta_1(eno): + global u, un, dt + residual(u, eno) + for i in range(nx): + j = i + ishift + u[j] = u[j] + dt * res[i] + boundary(u) + update_oldfield(un, u) + +def runge_kutta_2(eno): + #global u, un, dt + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = eno.u[j] + eno.dt * eno.res[i] + boundary(eno.u, eno) + + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = 0.5 * eno.un[j] + 0.5 * eno.u[j] + 0.5 * eno.dt * eno.res[i] + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def runge_kutta_3(eno): + global u, un, dt + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = eno.u[j] + eno.dt * eno.res[i] + boundary(eno.u, eno) + + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = 0.75 * eno.un[j] + 0.25 * eno.u[j] + 0.25 * eno.dt * eno.res[i] + boundary(eno.u, eno) + + residual(eno.u, eno) + c1, c2, c3 = 1.0/3.0, 2.0/3.0, 2.0/3.0 + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = c1 * eno.un[j] + c2 * eno.u[j] + c3 * eno.dt * eno.res[i] + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def get_ordinal_numbers(order): + if order == 1: + return 'st' + elif order == 2: + return 'nd' + elif order == 3: + return 'rd' + else: + return 'th' + +def visualize(eno): + with open('solution.plt', 'w') as f: + for i in range(eno.ist, eno.ied + 1): + j = i - eno.ist + f.write(f"{eno.xcc[j]:20.10e}{eno.u[i]:20.10e}\n") + + # 可视化 + u_numerical = np.copy(eno.u[eno.ist:eno.ied+1]) + print(f'u_numerical.size={u_numerical.size}') + print(f'eno.xcc.size={eno.xcc.size}') + #计算理论解 + u_analytical = analytical_solution(eno.xcc, eno.T, eno.c, eno.L) + print(f'u_analytical.size={u_analytical.size}') + plt.figure("OneFLOW-CFD Solver", figsize=(10, 6)) + plt.scatter(eno.xcc, u_numerical, facecolor="none", edgecolor="blue", s=20, linewidths=0.5, label=f'Numerical (Rusanov)') + plt.plot(eno.xcc, u_analytical, 'r--', label='Analytical') + plt.xlabel('x') + plt.ylabel('u') + ordinal1 = get_ordinal_numbers(eno.iorder) + ordinal2 = get_ordinal_numbers(eno.rk) + plt.title(f'1D Convection Equation at t = {eno.T:.3f} using {eno.iorder}{ordinal1}-order ENO and {eno.rk}{ordinal2}-order Runge-Kutta methods') + plt.legend() + plt.grid(True, color='gray', linestyle='--', linewidth=0.5, alpha=0.7) + plt.tight_layout() + plt.show() + +class Eno: + def __init__(self, iorder): + self.nx = 40 + self.rk = 2 + self.iorder = iorder + self.ighost = iorder + self.ishift = self.ighost + 1 + self.ist = 0 + self.ishift + self.ied = self.nx - 1 + self.ishift + self.ntcell = self.nx + 2 * self.ishift + self.isize = iorder * (iorder + 1) + + self.il = np.zeros(self.nx + 1, dtype=int) + self.ir = np.zeros(self.nx + 1, dtype=int) + self.coef = np.zeros((iorder + 1, iorder)) + self.dd = np.zeros((iorder, self.ntcell)) + self.up1_2m = np.zeros(self.nx + 1) + self.up1_2p = np.zeros(self.nx + 1) + self.flux = np.zeros(self.nx + 1) + self.res = np.zeros(self.nx) + self.L = 2.0 + self.x = np.zeros(self.nx + 1) + self.xcc = np.zeros(self.nx) + + # Field module variables + self.u = np.zeros(self.ntcell) + self.un = np.zeros(self.ntcell) + + self.c = 1.0 + self.T = 0.625 + self.dt = .0025 + def init_mesh(self): + xstart = 0.0 + xend = self.L + self.dx = (xend - xstart) / self.nx + + for i in range(0, self.nx+1): + self.x[i] = xstart + i * self.dx + + for i in range(0, self.nx): + self.xcc[i] = 0.5 * (self.x[i] + self.x[i + 1]) +def main(): + iorder = 1 + eno = Eno(iorder) + + init_coef(eno.iorder, eno.coef) + eno.init_mesh() + init_field(eno) + nt = int(eno.T / eno.dt) + simu_time = eno.T + + t = 0.0 + + while t < simu_time: + runge_kutta(eno) + t += eno.dt + if t + eno.dt > simu_time: + dt = simu_time - t + + print(t) + visualize(eno) + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/example/1d-linear-convection/eno/rusanov/rk3/eno1-7/01/plot.py b/example/1d-linear-convection/eno/rusanov/rk3/eno1-7/01/plot.py new file mode 100644 index 00000000..e389044c --- /dev/null +++ b/example/1d-linear-convection/eno/rusanov/rk3/eno1-7/01/plot.py @@ -0,0 +1,53 @@ +import numpy as np +import matplotlib.pyplot as plt +import csv +import sys + +nvar = len(sys.argv) +print('nvar=',nvar) +print('sys.argv=',sys.argv) + +order = 1 +if nvar >= 2: + var = sys.argv[1] + print('var=',var) + order = int(var) + +print('order=',order) + +x_list = [] +u_list = [] + +with open('solution.plt', newline='') as csvfile: + #readCSV = csv.reader(csvfile, delimiter= ' ') + icount = 0 + for line in csvfile: + # 去除首尾空格,按连续空格分割 + row = line.strip().split() + #print("row=",row) + x_list.append(row[0]) + u_list.append(row[1]) + icount += 1 + +ni = icount +print("ni=",ni) + +#print("x_list=",x_list) + +x = np.zeros( ni ) +u = np.zeros( ni ) + +for i in range(0, ni): + x[i] = float(x_list[i]) + u[i] = float(u_list[i]) + +labelname = 'Eno' + str(order) + +plt.figure("OneFLOW-CFD Solver", figsize=(8, 6), dpi=100) +plt.plot(x, u, "b-", linewidth=1.0, marker = 's', markerfacecolor='None', label=labelname) +plt.xlabel("$x$") +plt.ylabel("$u$") +plt.title("burgers T=1") +plt.legend() +plt.tight_layout() +plt.show(); \ No newline at end of file diff --git a/example/1d-linear-convection/eno/rusanov/rk3/eno1-7/01a/eno.py b/example/1d-linear-convection/eno/rusanov/rk3/eno1-7/01a/eno.py new file mode 100644 index 00000000..830c3941 --- /dev/null +++ b/example/1d-linear-convection/eno/rusanov/rk3/eno1-7/01a/eno.py @@ -0,0 +1,306 @@ +import numpy as np +import matplotlib.pyplot as plt + +# 初始条件 +def initial_condition(x): + u0 = np.zeros_like(x) + for i in range(len(x)): + if 0.5 <= x[i] <= 1.0: + u0[i] = 2.0 + else: + u0[i] = 1.0 + return u0 + +# 理论解 +def analytical_solution(x, t, a, L): + # 初始条件沿 x - at 平移 + x_shifted = x - a * t + return initial_condition((x_shifted + L) % L) # 周期边界条件 + +def residual(q, eno): + reconstruction(q, eno) + inviscid_flux(eno.up1_2m, eno.up1_2p, eno.flux, eno) + for i in range(eno.nx): + eno.res[i] = -(eno.flux[i + 1] - eno.flux[i]) / eno.dx + +def reconstruction(q, eno): + # Choose the stencil by ENO method + eno.dd[0, 0:eno.ntcell-1] = q[0:eno.ntcell-1] + + for m in range(1, eno.iorder): + for j in range(0, eno.ntcell-1): + eno.dd[m, j] = eno.dd[m-1, j+1] - eno.dd[m-1, j] + + for i in range(eno.nx + 1): + eno.il[i] = i - 1 + for m in range(1, eno.iorder): + if abs(dd[m, eno.il[i]-1+eno.ishift]) <= abs(dd[m, eno.il[i]+eno.ishift]): + eno.il[i] -= 1 + + for i in range(eno.nx + 1): + eno.ir[i] = i + for m in range(1, eno.iorder): + if abs(dd[m, eno.ir[i]-1+eno.ishift]) <= abs(dd[m, ir[i]+eno.ishift]): + eno.ir[i] -= 1 + + # Reconstruction u(j+1/2) + for i in range(eno.nx + 1): + k1 = eno.il[i] + k2 = eno.ir[i] + l1 = i - k1 + l2 = i - k2 + eno.up1_2m[i] = 0 + eno.up1_2p[i] = 0 + for m in range(eno.iorder): + eno.up1_2m[i] += q[k1 + eno.ishift + m] * eno.coef[l1, m] + eno.up1_2p[i] += q[k2 + eno.ishift + m] * eno.coef[l2, m] + +def inviscid_flux(up1_2m, up1_2p, flux, eno): + iflux = 0 + if iflux == 0: + rusanov_flux(up1_2m, up1_2p, flux, eno) + else: + engquist_osher_flux(up1_2m, up1_2p, flux, eno) + +def engquist_osher_flux(up1_2m, up1_2p, flux, eno): + for i in range(eno.nx + 1): + u_L = up1_2m[i] + u_R = up1_2p[i] + + cp = 0.5 * ( eno.c + abs(eno.c) ) + cm = 0.5 * ( eno.c - abs(eno.c) ) + + flux[i] = cp * uL + cm * u_R + +def rusanov_flux(up1_2m, up1_2p, flux, eno): + for i in range(eno.nx + 1): + u_L = up1_2m[i] + u_R = up1_2p[i] + F_L = eno.c * u_L # 左状态通量 + F_R = eno.c * u_R # 右状态通量 + alpha = abs(eno.c) # 最大波速 + flux[i] = 0.5 * (F_L + F_R) - 0.5 * alpha * (u_R - u_L) + + +def boundary(u, eno): + for i in range(-eno.ighost, 1): + u[eno.ist - 1 + i] = u[eno.ied + i] + for i in range(1, eno.ighost + 2): + u[eno.ied + i] = u[eno.ist - 1 + i] + +def update_oldfield(qn, q): + qn[:] = q[:] + +def init_coef( iorder, coef ): + if iorder == 1: + coef[0] = [1.0] + coef[1] = [1.0] + elif iorder == 2: + coef[0] = [3.0/2.0, -1.0/2.0] + coef[1] = [1.0/2.0, 1.0/2.0] + coef[2] = [-1.0/2.0, 3.0/2.0] + elif iorder == 3: + coef[0] = [ 11.0/6.0, -7.0/6.0, 1.0/3.0 ] + coef[1] = [ 1.0/3.0, 5.0/6.0, -1.0/6.0 ] + coef[2] = [ -1.0/6.0, 5.0/6.0, 1.0/3.0 ] + coef[3] = [ 1.0/3.0, -7.0/6.0, 11.0/6.0 ] + elif iorder == 4: + coef[0] = [ 25.0/12.0, -23.0/12.0, 13.0/12.0, -1.0/4.0 ] + coef[1] = [ 1.0/4.0, 13.0/12.0, -5.0/12.0, 1.0/12.0 ] + coef[2] = [ -1.0/12.0, 7.0/12.0, 7.0/12.0, -1.0/12.0 ] + coef[3] = [ 1.0/12.0, -5.0/12.0, 13.0/12.0, 1.0/4.0 ] + coef[4] = [ -1.0/4.0, 13.0/12.0, -23.0/12.0, 25.0/12.0 ] + elif iorder == 5: + coef[0] = [ 137.0/60.0, -163.0/60.0, 137.0/60.0, -21.0/20.0, 1.0/5.0 ] + coef[1] = [ 1.0/5.0, 77.0/60.0, -43.0/60.0, 17.0/60.0, -1.0/20.0 ] + coef[2] = [ -1.0/20.0, 9.0/20.0, 47.0/60.0, -13.0/60.0, 1.0/30.0 ] + coef[3] = [ 1.0/30.0, -13.0/60.0, 47.0/60.0, 9.0/20.0, -1.0/20.0 ] + coef[4] = [ -1.0/20.0, 17.0/60.0, -43.0/60.0, 77.0/60.0, 1.0/5.0 ] + coef[5] = [ 1.0/5.0, -21.0/20.0, 137.0/60.0, -163.0/60.0, 137.0/60.0 ] + elif iorder == 6: + coef[0] = [ 49.0/20.0, -71.0/20.0, 79.0/20.0, -163.0/60.0, 31.0/30.0, -1.0/6.0 ] + coef[1] = [ 1.0/6.0, 29.0/20.0, -21.0/20.0, 37.0/60.0, -13.0/60.0, 1.0/30.0 ] + coef[2] = [ -1.0/30.0, 11.0/30.0, 19.0/20.0, -23.0/60.0, 7.0/60.0, -1.0/60.0 ] + coef[3] = [ 1.0/60.0, -2.0/15.0, 37.0/60.0, 37.0/60.0, -2.0/15.0, 1.0/60.0 ] + coef[4] = [ -1.0/60.0, 7.0/60.0, -23.0/60.0, 19.0/20.0, 11.0/30.0, -1.0/30.0 ] + coef[5] = [ 1.0/30.0, -13.0/60.0, 37.0/60.0, -21.0/20.0, 29.0/20.0, 1.0/6.0 ] + coef[6] = [ -1.0/6.0, 31.0/30.0, -163.0/60.0, 79.0/20.0, -71.0/20.0, 49.0/20.0 ] + elif iorder == 7: + coef[0] = [ 363.0/140.0, -617.0/140.0, 853.0/140.0, -2341.0/420.0, 667.0/210.0, -43.0/42.0, 1.0/7.0 ] + coef[1] = [ 1.0/7.0, 223.0/140.0, -197.0/140.0, 153.0/140.0, -241.0/420.0, 37.0/210.0, -1.0/42.0 ] + coef[2] = [ -1.0/42.0, 13.0/42.0, 153.0/140.0, -241.0/420.0, 109.0/420.0, -31.0/420.0, 1.0/105.0 ] + coef[3] = [ 1.0/105.0, -19.0/210.0, 107.0/210.0, 319.0/420.0, -101.0/420.0, 5.0/84.0, -1.0/140.0 ] + coef[4] = [ -1.0/140.0, 5.0/84.0, -101.0/420.0, 319.0/420.0, 107.0/210.0, -19.0/210.0, 1.0/105.0 ] + coef[5] = [ 1.0/105.0, -31.0/420.0, 109.0/420.0, -241.0/420.0, 153.0/140.0, 13.0/42.0, -1.0/42.0 ] + coef[6] = [ -1.0/42.0, 37.0/210.0, -241.0/420.0, 153.0/140.0, -197.0/140.0, 223.0/140.0, 1.0/7.0 ] + coef[7] = [ 1.0/7.0, -43.0/42.0, 667.0/210.0, -2341.0/420.0, 853.0/140.0, -617.0/140.0, 363.0/140.0 ] + +def init_field(eno): + for i in range(eno.ist, eno.ied + 1): + j = i - eno.ist + if 0.5 <= eno.xcc[j] <= 1.0: + eno.u[i] = 2.0 + else: + eno.u[i] = 1.0 + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def runge_kutta(eno): + rk = eno.rk + if rk == 1: + runge_kutta_1(eno) + elif rk == 2: + runge_kutta_2(eno) + else: + runge_kutta_3(eno) + +def runge_kutta_1(eno): + global u, un, dt + residual(u, eno) + for i in range(nx): + j = i + ishift + u[j] = u[j] + dt * res[i] + boundary(u) + update_oldfield(un, u) + +def runge_kutta_2(eno): + #global u, un, dt + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = eno.u[j] + eno.dt * eno.res[i] + boundary(eno.u, eno) + + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = 0.5 * eno.un[j] + 0.5 * eno.u[j] + 0.5 * eno.dt * eno.res[i] + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def runge_kutta_3(eno): + global u, un, dt + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = eno.u[j] + eno.dt * eno.res[i] + boundary(eno.u, eno) + + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = 0.75 * eno.un[j] + 0.25 * eno.u[j] + 0.25 * eno.dt * eno.res[i] + boundary(eno.u, eno) + + residual(eno.u, eno) + c1, c2, c3 = 1.0/3.0, 2.0/3.0, 2.0/3.0 + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = c1 * eno.un[j] + c2 * eno.u[j] + c3 * eno.dt * eno.res[i] + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def get_ordinal_numbers(order): + if order == 1: + return 'st' + elif order == 2: + return 'nd' + elif order == 3: + return 'rd' + else: + return 'th' + +def visualize(eno): + with open('solution.plt', 'w') as f: + for i in range(eno.ist, eno.ied + 1): + j = i - eno.ist + f.write(f"{eno.xcc[j]:20.10e}{eno.u[i]:20.10e}\n") + + # 可视化 + u_numerical = np.copy(eno.u[eno.ist:eno.ied+1]) + print(f'u_numerical.size={u_numerical.size}') + print(f'eno.xcc.size={eno.xcc.size}') + #计算理论解 + u_analytical = analytical_solution(eno.xcc, eno.T, eno.c, eno.L) + print(f'u_analytical.size={u_analytical.size}') + plt.figure("OneFLOW-CFD Solver", figsize=(10, 6)) + plt.scatter(eno.xcc, u_numerical, facecolor="none", edgecolor="blue", s=20, linewidths=0.5, label=f'Numerical (Rusanov)') + plt.plot(eno.xcc, u_analytical, 'r--', label='Analytical') + plt.xlabel('x') + plt.ylabel('u') + ordinal1 = get_ordinal_numbers(eno.iorder) + ordinal2 = get_ordinal_numbers(eno.rk) + plt.title(f'1D Convection Equation at t = {eno.T:.3f} using {eno.iorder}{ordinal1}-order ENO and {eno.rk}{ordinal2}-order Runge-Kutta methods') + plt.legend() + plt.grid(True, color='gray', linestyle='--', linewidth=0.5, alpha=0.7) + plt.tight_layout() + plt.show() + +class Eno: + def __init__(self, iorder): + self.nx = 40 + self.rk = 2 + self.iorder = iorder + self.ighost = iorder + self.ishift = self.ighost + 1 + self.ist = 0 + self.ishift + self.ied = self.nx - 1 + self.ishift + self.ntcell = self.nx + 2 * self.ishift + self.isize = iorder * (iorder + 1) + + self.il = np.zeros(self.nx + 1, dtype=int) + self.ir = np.zeros(self.nx + 1, dtype=int) + self.coef = np.zeros((iorder + 1, iorder)) + self.dd = np.zeros((iorder, self.ntcell)) + self.up1_2m = np.zeros(self.nx + 1) + self.up1_2p = np.zeros(self.nx + 1) + self.flux = np.zeros(self.nx + 1) + self.res = np.zeros(self.nx) + self.L = 2.0 + self.x = np.zeros(self.nx + 1) + self.xcc = np.zeros(self.nx) + + # Field module variables + self.u = np.zeros(self.ntcell) + self.un = np.zeros(self.ntcell) + + self.c = 1.0 + self.T = 0.625 + self.dt = .0025 + def init_mesh(self): + xstart = 0.0 + xend = self.L + self.dx = (xend - xstart) / self.nx + + for i in range(0, self.nx+1): + self.x[i] = xstart + i * self.dx + + for i in range(0, self.nx): + self.xcc[i] = 0.5 * (self.x[i] + self.x[i + 1]) + +def RunEno(iorder): + eno = Eno(iorder) + init_coef(eno.iorder, eno.coef) + eno.init_mesh() + init_field(eno) + + nt = int(eno.T / eno.dt) + simu_time = eno.T + + t = 0.0 + + while t < simu_time: + runge_kutta(eno) + t += eno.dt + if t + eno.dt > simu_time: + dt = simu_time - t + + print(t) + visualize(eno) + +def main(): + iorder = 1 + RunEno(iorder) + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/example/1d-linear-convection/eno/rusanov/rk3/eno1-7/01a/plot.py b/example/1d-linear-convection/eno/rusanov/rk3/eno1-7/01a/plot.py new file mode 100644 index 00000000..e389044c --- /dev/null +++ b/example/1d-linear-convection/eno/rusanov/rk3/eno1-7/01a/plot.py @@ -0,0 +1,53 @@ +import numpy as np +import matplotlib.pyplot as plt +import csv +import sys + +nvar = len(sys.argv) +print('nvar=',nvar) +print('sys.argv=',sys.argv) + +order = 1 +if nvar >= 2: + var = sys.argv[1] + print('var=',var) + order = int(var) + +print('order=',order) + +x_list = [] +u_list = [] + +with open('solution.plt', newline='') as csvfile: + #readCSV = csv.reader(csvfile, delimiter= ' ') + icount = 0 + for line in csvfile: + # 去除首尾空格,按连续空格分割 + row = line.strip().split() + #print("row=",row) + x_list.append(row[0]) + u_list.append(row[1]) + icount += 1 + +ni = icount +print("ni=",ni) + +#print("x_list=",x_list) + +x = np.zeros( ni ) +u = np.zeros( ni ) + +for i in range(0, ni): + x[i] = float(x_list[i]) + u[i] = float(u_list[i]) + +labelname = 'Eno' + str(order) + +plt.figure("OneFLOW-CFD Solver", figsize=(8, 6), dpi=100) +plt.plot(x, u, "b-", linewidth=1.0, marker = 's', markerfacecolor='None', label=labelname) +plt.xlabel("$x$") +plt.ylabel("$u$") +plt.title("burgers T=1") +plt.legend() +plt.tight_layout() +plt.show(); \ No newline at end of file diff --git a/example/1d-linear-convection/eno/rusanov/rk3/eno1-7/01b/eno.py b/example/1d-linear-convection/eno/rusanov/rk3/eno1-7/01b/eno.py new file mode 100644 index 00000000..4c8b5972 --- /dev/null +++ b/example/1d-linear-convection/eno/rusanov/rk3/eno1-7/01b/eno.py @@ -0,0 +1,307 @@ +import numpy as np +import matplotlib.pyplot as plt + +# 初始条件 +def initial_condition(x): + u0 = np.zeros_like(x) + for i in range(len(x)): + if 0.5 <= x[i] <= 1.0: + u0[i] = 2.0 + else: + u0[i] = 1.0 + return u0 + +# 理论解 +def analytical_solution(x, t, a, L): + # 初始条件沿 x - at 平移 + x_shifted = x - a * t + return initial_condition((x_shifted + L) % L) # 周期边界条件 + +def residual(q, eno): + reconstruction(q, eno) + inviscid_flux(eno.up1_2m, eno.up1_2p, eno.flux, eno) + for i in range(eno.nx): + eno.res[i] = -(eno.flux[i + 1] - eno.flux[i]) / eno.dx + +def reconstruction(q, eno): + # Choose the stencil by ENO method + eno.dd[0, 0:eno.ntcell-1] = q[0:eno.ntcell-1] + + for m in range(1, eno.iorder): + for j in range(0, eno.ntcell-1): + eno.dd[m, j] = eno.dd[m-1, j+1] - eno.dd[m-1, j] + + for i in range(eno.nx + 1): + eno.il[i] = i - 1 + for m in range(1, eno.iorder): + if abs(eno.dd[m, eno.il[i]-1+eno.ishift]) <= abs(eno.dd[m, eno.il[i]+eno.ishift]): + eno.il[i] -= 1 + + for i in range(eno.nx + 1): + eno.ir[i] = i + for m in range(1, eno.iorder): + if abs(eno.dd[m, eno.ir[i]-1+eno.ishift]) <= abs(eno.dd[m, eno.ir[i]+eno.ishift]): + eno.ir[i] -= 1 + + # Reconstruction u(j+1/2) + for i in range(eno.nx + 1): + k1 = eno.il[i] + k2 = eno.ir[i] + l1 = i - k1 + l2 = i - k2 + eno.up1_2m[i] = 0 + eno.up1_2p[i] = 0 + for m in range(eno.iorder): + eno.up1_2m[i] += q[k1 + eno.ishift + m] * eno.coef[l1, m] + eno.up1_2p[i] += q[k2 + eno.ishift + m] * eno.coef[l2, m] + +def inviscid_flux(up1_2m, up1_2p, flux, eno): + iflux = 0 + if iflux == 0: + rusanov_flux(up1_2m, up1_2p, flux, eno) + else: + engquist_osher_flux(up1_2m, up1_2p, flux, eno) + +def engquist_osher_flux(up1_2m, up1_2p, flux, eno): + for i in range(eno.nx + 1): + u_L = up1_2m[i] + u_R = up1_2p[i] + + cp = 0.5 * ( eno.c + abs(eno.c) ) + cm = 0.5 * ( eno.c - abs(eno.c) ) + + flux[i] = cp * uL + cm * u_R + +def rusanov_flux(up1_2m, up1_2p, flux, eno): + for i in range(eno.nx + 1): + u_L = up1_2m[i] + u_R = up1_2p[i] + F_L = eno.c * u_L # 左状态通量 + F_R = eno.c * u_R # 右状态通量 + alpha = abs(eno.c) # 最大波速 + flux[i] = 0.5 * (F_L + F_R) - 0.5 * alpha * (u_R - u_L) + + +def boundary(u, eno): + for i in range(-eno.ighost, 1): + u[eno.ist - 1 + i] = u[eno.ied + i] + for i in range(1, eno.ighost + 2): + u[eno.ied + i] = u[eno.ist - 1 + i] + +def update_oldfield(qn, q): + qn[:] = q[:] + +def init_coef( iorder, coef ): + if iorder == 1: + coef[0] = [1.0] + coef[1] = [1.0] + elif iorder == 2: + coef[0] = [3.0/2.0, -1.0/2.0] + coef[1] = [1.0/2.0, 1.0/2.0] + coef[2] = [-1.0/2.0, 3.0/2.0] + elif iorder == 3: + coef[0] = [ 11.0/6.0, -7.0/6.0, 1.0/3.0 ] + coef[1] = [ 1.0/3.0, 5.0/6.0, -1.0/6.0 ] + coef[2] = [ -1.0/6.0, 5.0/6.0, 1.0/3.0 ] + coef[3] = [ 1.0/3.0, -7.0/6.0, 11.0/6.0 ] + elif iorder == 4: + coef[0] = [ 25.0/12.0, -23.0/12.0, 13.0/12.0, -1.0/4.0 ] + coef[1] = [ 1.0/4.0, 13.0/12.0, -5.0/12.0, 1.0/12.0 ] + coef[2] = [ -1.0/12.0, 7.0/12.0, 7.0/12.0, -1.0/12.0 ] + coef[3] = [ 1.0/12.0, -5.0/12.0, 13.0/12.0, 1.0/4.0 ] + coef[4] = [ -1.0/4.0, 13.0/12.0, -23.0/12.0, 25.0/12.0 ] + elif iorder == 5: + coef[0] = [ 137.0/60.0, -163.0/60.0, 137.0/60.0, -21.0/20.0, 1.0/5.0 ] + coef[1] = [ 1.0/5.0, 77.0/60.0, -43.0/60.0, 17.0/60.0, -1.0/20.0 ] + coef[2] = [ -1.0/20.0, 9.0/20.0, 47.0/60.0, -13.0/60.0, 1.0/30.0 ] + coef[3] = [ 1.0/30.0, -13.0/60.0, 47.0/60.0, 9.0/20.0, -1.0/20.0 ] + coef[4] = [ -1.0/20.0, 17.0/60.0, -43.0/60.0, 77.0/60.0, 1.0/5.0 ] + coef[5] = [ 1.0/5.0, -21.0/20.0, 137.0/60.0, -163.0/60.0, 137.0/60.0 ] + elif iorder == 6: + coef[0] = [ 49.0/20.0, -71.0/20.0, 79.0/20.0, -163.0/60.0, 31.0/30.0, -1.0/6.0 ] + coef[1] = [ 1.0/6.0, 29.0/20.0, -21.0/20.0, 37.0/60.0, -13.0/60.0, 1.0/30.0 ] + coef[2] = [ -1.0/30.0, 11.0/30.0, 19.0/20.0, -23.0/60.0, 7.0/60.0, -1.0/60.0 ] + coef[3] = [ 1.0/60.0, -2.0/15.0, 37.0/60.0, 37.0/60.0, -2.0/15.0, 1.0/60.0 ] + coef[4] = [ -1.0/60.0, 7.0/60.0, -23.0/60.0, 19.0/20.0, 11.0/30.0, -1.0/30.0 ] + coef[5] = [ 1.0/30.0, -13.0/60.0, 37.0/60.0, -21.0/20.0, 29.0/20.0, 1.0/6.0 ] + coef[6] = [ -1.0/6.0, 31.0/30.0, -163.0/60.0, 79.0/20.0, -71.0/20.0, 49.0/20.0 ] + elif iorder == 7: + coef[0] = [ 363.0/140.0, -617.0/140.0, 853.0/140.0, -2341.0/420.0, 667.0/210.0, -43.0/42.0, 1.0/7.0 ] + coef[1] = [ 1.0/7.0, 223.0/140.0, -197.0/140.0, 153.0/140.0, -241.0/420.0, 37.0/210.0, -1.0/42.0 ] + coef[2] = [ -1.0/42.0, 13.0/42.0, 153.0/140.0, -241.0/420.0, 109.0/420.0, -31.0/420.0, 1.0/105.0 ] + coef[3] = [ 1.0/105.0, -19.0/210.0, 107.0/210.0, 319.0/420.0, -101.0/420.0, 5.0/84.0, -1.0/140.0 ] + coef[4] = [ -1.0/140.0, 5.0/84.0, -101.0/420.0, 319.0/420.0, 107.0/210.0, -19.0/210.0, 1.0/105.0 ] + coef[5] = [ 1.0/105.0, -31.0/420.0, 109.0/420.0, -241.0/420.0, 153.0/140.0, 13.0/42.0, -1.0/42.0 ] + coef[6] = [ -1.0/42.0, 37.0/210.0, -241.0/420.0, 153.0/140.0, -197.0/140.0, 223.0/140.0, 1.0/7.0 ] + coef[7] = [ 1.0/7.0, -43.0/42.0, 667.0/210.0, -2341.0/420.0, 853.0/140.0, -617.0/140.0, 363.0/140.0 ] + +def init_field(eno): + for i in range(eno.ist, eno.ied + 1): + j = i - eno.ist + if 0.5 <= eno.xcc[j] <= 1.0: + eno.u[i] = 2.0 + else: + eno.u[i] = 1.0 + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def runge_kutta(eno): + rk = eno.rk + if rk == 1: + runge_kutta_1(eno) + elif rk == 2: + runge_kutta_2(eno) + else: + runge_kutta_3(eno) + +def runge_kutta_1(eno): + global u, un, dt + residual(u, eno) + for i in range(nx): + j = i + ishift + u[j] = u[j] + dt * res[i] + boundary(u) + update_oldfield(un, u) + +def runge_kutta_2(eno): + #global u, un, dt + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = eno.u[j] + eno.dt * eno.res[i] + boundary(eno.u, eno) + + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = 0.5 * eno.un[j] + 0.5 * eno.u[j] + 0.5 * eno.dt * eno.res[i] + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def runge_kutta_3(eno): + global u, un, dt + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = eno.u[j] + eno.dt * eno.res[i] + boundary(eno.u, eno) + + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = 0.75 * eno.un[j] + 0.25 * eno.u[j] + 0.25 * eno.dt * eno.res[i] + boundary(eno.u, eno) + + residual(eno.u, eno) + c1, c2, c3 = 1.0/3.0, 2.0/3.0, 2.0/3.0 + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = c1 * eno.un[j] + c2 * eno.u[j] + c3 * eno.dt * eno.res[i] + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def get_ordinal_numbers(order): + if order == 1: + return 'st' + elif order == 2: + return 'nd' + elif order == 3: + return 'rd' + else: + return 'th' + +def visualize(eno): + with open('solution.plt', 'w') as f: + for i in range(eno.ist, eno.ied + 1): + j = i - eno.ist + f.write(f"{eno.xcc[j]:20.10e}{eno.u[i]:20.10e}\n") + + # 可视化 + u_numerical = np.copy(eno.u[eno.ist:eno.ied+1]) + print(f'u_numerical.size={u_numerical.size}') + print(f'eno.xcc.size={eno.xcc.size}') + #计算理论解 + u_analytical = analytical_solution(eno.xcc, eno.T, eno.c, eno.L) + print(f'u_analytical.size={u_analytical.size}') + plt.figure("OneFLOW-CFD Solver", figsize=(10, 6)) + plt.scatter(eno.xcc, u_numerical, facecolor="none", edgecolor="blue", s=20, linewidths=0.5, label=f'Numerical (Rusanov)') + plt.plot(eno.xcc, u_analytical, 'r--', label='Analytical') + plt.xlabel('x') + plt.ylabel('u') + ordinal1 = get_ordinal_numbers(eno.iorder) + ordinal2 = get_ordinal_numbers(eno.rk) + plt.title(f'1D Convection Equation at t = {eno.T:.3f} using {eno.iorder}{ordinal1}-order ENO and {eno.rk}{ordinal2}-order Runge-Kutta methods') + plt.legend() + plt.grid(True, color='gray', linestyle='--', linewidth=0.5, alpha=0.7) + plt.tight_layout() + plt.show() + +class Eno: + def __init__(self, iorder): + self.nx = 40 + self.rk = 2 + self.iorder = iorder + self.ighost = iorder + self.ishift = self.ighost + 1 + self.ist = 0 + self.ishift + self.ied = self.nx - 1 + self.ishift + self.ntcell = self.nx + 2 * self.ishift + self.isize = iorder * (iorder + 1) + + self.il = np.zeros(self.nx + 1, dtype=int) + self.ir = np.zeros(self.nx + 1, dtype=int) + self.coef = np.zeros((iorder + 1, iorder)) + self.dd = np.zeros((iorder, self.ntcell)) + self.up1_2m = np.zeros(self.nx + 1) + self.up1_2p = np.zeros(self.nx + 1) + self.flux = np.zeros(self.nx + 1) + self.res = np.zeros(self.nx) + self.L = 2.0 + self.x = np.zeros(self.nx + 1) + self.xcc = np.zeros(self.nx) + + # Field module variables + self.u = np.zeros(self.ntcell) + self.un = np.zeros(self.ntcell) + + self.c = 1.0 + self.T = 0.625 + self.dt = .0025 + def init_mesh(self): + xstart = 0.0 + xend = self.L + self.dx = (xend - xstart) / self.nx + + for i in range(0, self.nx+1): + self.x[i] = xstart + i * self.dx + + for i in range(0, self.nx): + self.xcc[i] = 0.5 * (self.x[i] + self.x[i + 1]) + +def RunEno(iorder): + eno = Eno(iorder) + init_coef(eno.iorder, eno.coef) + eno.init_mesh() + init_field(eno) + + nt = int(eno.T / eno.dt) + simu_time = eno.T + + t = 0.0 + + while t < simu_time: + runge_kutta(eno) + t += eno.dt + if t + eno.dt > simu_time: + dt = simu_time - t + + print(t) + visualize(eno) + +def main(): + iorder = 7 + print(f'{iorder=}') + RunEno(iorder) + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/example/1d-linear-convection/eno/rusanov/rk3/eno1-7/01b/plot.py b/example/1d-linear-convection/eno/rusanov/rk3/eno1-7/01b/plot.py new file mode 100644 index 00000000..e389044c --- /dev/null +++ b/example/1d-linear-convection/eno/rusanov/rk3/eno1-7/01b/plot.py @@ -0,0 +1,53 @@ +import numpy as np +import matplotlib.pyplot as plt +import csv +import sys + +nvar = len(sys.argv) +print('nvar=',nvar) +print('sys.argv=',sys.argv) + +order = 1 +if nvar >= 2: + var = sys.argv[1] + print('var=',var) + order = int(var) + +print('order=',order) + +x_list = [] +u_list = [] + +with open('solution.plt', newline='') as csvfile: + #readCSV = csv.reader(csvfile, delimiter= ' ') + icount = 0 + for line in csvfile: + # 去除首尾空格,按连续空格分割 + row = line.strip().split() + #print("row=",row) + x_list.append(row[0]) + u_list.append(row[1]) + icount += 1 + +ni = icount +print("ni=",ni) + +#print("x_list=",x_list) + +x = np.zeros( ni ) +u = np.zeros( ni ) + +for i in range(0, ni): + x[i] = float(x_list[i]) + u[i] = float(u_list[i]) + +labelname = 'Eno' + str(order) + +plt.figure("OneFLOW-CFD Solver", figsize=(8, 6), dpi=100) +plt.plot(x, u, "b-", linewidth=1.0, marker = 's', markerfacecolor='None', label=labelname) +plt.xlabel("$x$") +plt.ylabel("$u$") +plt.title("burgers T=1") +plt.legend() +plt.tight_layout() +plt.show(); \ No newline at end of file diff --git a/example/1d-linear-convection/eno/rusanov/rk3/eno1-7/01c/eno.py b/example/1d-linear-convection/eno/rusanov/rk3/eno1-7/01c/eno.py new file mode 100644 index 00000000..3008915c --- /dev/null +++ b/example/1d-linear-convection/eno/rusanov/rk3/eno1-7/01c/eno.py @@ -0,0 +1,313 @@ +import numpy as np +import matplotlib.pyplot as plt + +# 初始条件 +def initial_condition(x): + u0 = np.zeros_like(x) + for i in range(len(x)): + if 0.5 <= x[i] <= 1.0: + u0[i] = 2.0 + else: + u0[i] = 1.0 + return u0 + +# 理论解 +def analytical_solution(x, t, a, L): + # 初始条件沿 x - at 平移 + x_shifted = x - a * t + return initial_condition((x_shifted + L) % L) # 周期边界条件 + +def residual(q, eno): + reconstruction(q, eno) + inviscid_flux(eno.up1_2m, eno.up1_2p, eno.flux, eno) + for i in range(eno.nx): + eno.res[i] = -(eno.flux[i + 1] - eno.flux[i]) / eno.dx + +def reconstruction(q, eno): + # Choose the stencil by ENO method + eno.dd[0, 0:eno.ntcell-1] = q[0:eno.ntcell-1] + + for m in range(1, eno.iorder): + for j in range(0, eno.ntcell-1): + eno.dd[m, j] = eno.dd[m-1, j+1] - eno.dd[m-1, j] + + for i in range(eno.nx + 1): + eno.il[i] = i - 1 + for m in range(1, eno.iorder): + if abs(eno.dd[m, eno.il[i]-1+eno.ishift]) <= abs(eno.dd[m, eno.il[i]+eno.ishift]): + eno.il[i] -= 1 + + for i in range(eno.nx + 1): + eno.ir[i] = i + for m in range(1, eno.iorder): + if abs(eno.dd[m, eno.ir[i]-1+eno.ishift]) <= abs(eno.dd[m, eno.ir[i]+eno.ishift]): + eno.ir[i] -= 1 + + # Reconstruction u(j+1/2) + for i in range(eno.nx + 1): + k1 = eno.il[i] + k2 = eno.ir[i] + l1 = i - k1 + l2 = i - k2 + eno.up1_2m[i] = 0 + eno.up1_2p[i] = 0 + for m in range(eno.iorder): + eno.up1_2m[i] += q[k1 + eno.ishift + m] * eno.coef[l1, m] + eno.up1_2p[i] += q[k2 + eno.ishift + m] * eno.coef[l2, m] + +def inviscid_flux(up1_2m, up1_2p, flux, eno): + iflux = 0 + if iflux == 0: + rusanov_flux(up1_2m, up1_2p, flux, eno) + else: + engquist_osher_flux(up1_2m, up1_2p, flux, eno) + +def engquist_osher_flux(up1_2m, up1_2p, flux, eno): + for i in range(eno.nx + 1): + u_L = up1_2m[i] + u_R = up1_2p[i] + + cp = 0.5 * ( eno.c + abs(eno.c) ) + cm = 0.5 * ( eno.c - abs(eno.c) ) + + flux[i] = cp * uL + cm * u_R + +def rusanov_flux(up1_2m, up1_2p, flux, eno): + for i in range(eno.nx + 1): + u_L = up1_2m[i] + u_R = up1_2p[i] + F_L = eno.c * u_L # 左状态通量 + F_R = eno.c * u_R # 右状态通量 + alpha = abs(eno.c) # 最大波速 + flux[i] = 0.5 * (F_L + F_R) - 0.5 * alpha * (u_R - u_L) + + +def boundary(u, eno): + for i in range(-eno.ighost, 1): + u[eno.ist - 1 + i] = u[eno.ied + i] + for i in range(1, eno.ighost + 2): + u[eno.ied + i] = u[eno.ist - 1 + i] + +def update_oldfield(qn, q): + qn[:] = q[:] + +def init_coef( iorder, coef ): + if iorder == 1: + coef[0] = [1.0] + coef[1] = [1.0] + elif iorder == 2: + coef[0] = [3.0/2.0, -1.0/2.0] + coef[1] = [1.0/2.0, 1.0/2.0] + coef[2] = [-1.0/2.0, 3.0/2.0] + elif iorder == 3: + coef[0] = [ 11.0/6.0, -7.0/6.0, 1.0/3.0 ] + coef[1] = [ 1.0/3.0, 5.0/6.0, -1.0/6.0 ] + coef[2] = [ -1.0/6.0, 5.0/6.0, 1.0/3.0 ] + coef[3] = [ 1.0/3.0, -7.0/6.0, 11.0/6.0 ] + elif iorder == 4: + coef[0] = [ 25.0/12.0, -23.0/12.0, 13.0/12.0, -1.0/4.0 ] + coef[1] = [ 1.0/4.0, 13.0/12.0, -5.0/12.0, 1.0/12.0 ] + coef[2] = [ -1.0/12.0, 7.0/12.0, 7.0/12.0, -1.0/12.0 ] + coef[3] = [ 1.0/12.0, -5.0/12.0, 13.0/12.0, 1.0/4.0 ] + coef[4] = [ -1.0/4.0, 13.0/12.0, -23.0/12.0, 25.0/12.0 ] + elif iorder == 5: + coef[0] = [ 137.0/60.0, -163.0/60.0, 137.0/60.0, -21.0/20.0, 1.0/5.0 ] + coef[1] = [ 1.0/5.0, 77.0/60.0, -43.0/60.0, 17.0/60.0, -1.0/20.0 ] + coef[2] = [ -1.0/20.0, 9.0/20.0, 47.0/60.0, -13.0/60.0, 1.0/30.0 ] + coef[3] = [ 1.0/30.0, -13.0/60.0, 47.0/60.0, 9.0/20.0, -1.0/20.0 ] + coef[4] = [ -1.0/20.0, 17.0/60.0, -43.0/60.0, 77.0/60.0, 1.0/5.0 ] + coef[5] = [ 1.0/5.0, -21.0/20.0, 137.0/60.0, -163.0/60.0, 137.0/60.0 ] + elif iorder == 6: + coef[0] = [ 49.0/20.0, -71.0/20.0, 79.0/20.0, -163.0/60.0, 31.0/30.0, -1.0/6.0 ] + coef[1] = [ 1.0/6.0, 29.0/20.0, -21.0/20.0, 37.0/60.0, -13.0/60.0, 1.0/30.0 ] + coef[2] = [ -1.0/30.0, 11.0/30.0, 19.0/20.0, -23.0/60.0, 7.0/60.0, -1.0/60.0 ] + coef[3] = [ 1.0/60.0, -2.0/15.0, 37.0/60.0, 37.0/60.0, -2.0/15.0, 1.0/60.0 ] + coef[4] = [ -1.0/60.0, 7.0/60.0, -23.0/60.0, 19.0/20.0, 11.0/30.0, -1.0/30.0 ] + coef[5] = [ 1.0/30.0, -13.0/60.0, 37.0/60.0, -21.0/20.0, 29.0/20.0, 1.0/6.0 ] + coef[6] = [ -1.0/6.0, 31.0/30.0, -163.0/60.0, 79.0/20.0, -71.0/20.0, 49.0/20.0 ] + elif iorder == 7: + coef[0] = [ 363.0/140.0, -617.0/140.0, 853.0/140.0, -2341.0/420.0, 667.0/210.0, -43.0/42.0, 1.0/7.0 ] + coef[1] = [ 1.0/7.0, 223.0/140.0, -197.0/140.0, 153.0/140.0, -241.0/420.0, 37.0/210.0, -1.0/42.0 ] + coef[2] = [ -1.0/42.0, 13.0/42.0, 153.0/140.0, -241.0/420.0, 109.0/420.0, -31.0/420.0, 1.0/105.0 ] + coef[3] = [ 1.0/105.0, -19.0/210.0, 107.0/210.0, 319.0/420.0, -101.0/420.0, 5.0/84.0, -1.0/140.0 ] + coef[4] = [ -1.0/140.0, 5.0/84.0, -101.0/420.0, 319.0/420.0, 107.0/210.0, -19.0/210.0, 1.0/105.0 ] + coef[5] = [ 1.0/105.0, -31.0/420.0, 109.0/420.0, -241.0/420.0, 153.0/140.0, 13.0/42.0, -1.0/42.0 ] + coef[6] = [ -1.0/42.0, 37.0/210.0, -241.0/420.0, 153.0/140.0, -197.0/140.0, 223.0/140.0, 1.0/7.0 ] + coef[7] = [ 1.0/7.0, -43.0/42.0, 667.0/210.0, -2341.0/420.0, 853.0/140.0, -617.0/140.0, 363.0/140.0 ] + +def init_field(eno): + for i in range(eno.ist, eno.ied + 1): + j = i - eno.ist + if 0.5 <= eno.xcc[j] <= 1.0: + eno.u[i] = 2.0 + else: + eno.u[i] = 1.0 + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def runge_kutta(eno): + rk = eno.rk + if rk == 1: + runge_kutta_1(eno) + elif rk == 2: + runge_kutta_2(eno) + else: + runge_kutta_3(eno) + +def runge_kutta_1(eno): + global u, un, dt + residual(u, eno) + for i in range(nx): + j = i + ishift + u[j] = u[j] + dt * res[i] + boundary(u) + update_oldfield(un, u) + +def runge_kutta_2(eno): + #global u, un, dt + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = eno.u[j] + eno.dt * eno.res[i] + boundary(eno.u, eno) + + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = 0.5 * eno.un[j] + 0.5 * eno.u[j] + 0.5 * eno.dt * eno.res[i] + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def runge_kutta_3(eno): + global u, un, dt + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = eno.u[j] + eno.dt * eno.res[i] + boundary(eno.u, eno) + + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = 0.75 * eno.un[j] + 0.25 * eno.u[j] + 0.25 * eno.dt * eno.res[i] + boundary(eno.u, eno) + + residual(eno.u, eno) + c1, c2, c3 = 1.0/3.0, 2.0/3.0, 2.0/3.0 + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = c1 * eno.un[j] + c2 * eno.u[j] + c3 * eno.dt * eno.res[i] + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def get_ordinal_numbers(order): + if order == 1: + return 'st' + elif order == 2: + return 'nd' + elif order == 3: + return 'rd' + else: + return 'th' + +def visualize(eno): + with open('solution.plt', 'w') as f: + for i in range(eno.ist, eno.ied + 1): + j = i - eno.ist + f.write(f"{eno.xcc[j]:20.10e}{eno.u[i]:20.10e}\n") + + # 可视化 + u_numerical = np.copy(eno.u[eno.ist:eno.ied+1]) + print(f'u_numerical.size={u_numerical.size}') + print(f'eno.xcc.size={eno.xcc.size}') + #计算理论解 + u_analytical = analytical_solution(eno.xcc, eno.T, eno.c, eno.L) + print(f'u_analytical.size={u_analytical.size}') + plt.figure("OneFLOW-CFD Solver", figsize=(10, 6)) + plt.scatter(eno.xcc, u_numerical, facecolor="none", edgecolor="blue", s=20, linewidths=0.5, label=f'Numerical (Rusanov)') + plt.plot(eno.xcc, u_analytical, 'r--', label='Analytical') + plt.xlabel('x') + plt.ylabel('u') + ordinal1 = get_ordinal_numbers(eno.iorder) + ordinal2 = get_ordinal_numbers(eno.rk) + plt.title(f'1D Convection Equation at t = {eno.T:.3f} using {eno.iorder}{ordinal1}-order ENO and {eno.rk}{ordinal2}-order Runge-Kutta methods') + plt.legend() + plt.grid(True, color='gray', linestyle='--', linewidth=0.5, alpha=0.7) + plt.tight_layout() + plt.show() + +class Eno: + def __init__(self, iorder): + self.nx = 40 + self.rk = 2 + self.iorder = iorder + self.ighost = iorder + self.ishift = self.ighost + 1 + self.ist = 0 + self.ishift + self.ied = self.nx - 1 + self.ishift + self.ntcell = self.nx + 2 * self.ishift + self.isize = iorder * (iorder + 1) + + self.il = np.zeros(self.nx + 1, dtype=int) + self.ir = np.zeros(self.nx + 1, dtype=int) + self.coef = np.zeros((iorder + 1, iorder)) + self.dd = np.zeros((iorder, self.ntcell)) + self.up1_2m = np.zeros(self.nx + 1) + self.up1_2p = np.zeros(self.nx + 1) + self.flux = np.zeros(self.nx + 1) + self.res = np.zeros(self.nx) + self.L = 2.0 + self.x = np.zeros(self.nx + 1) + self.xcc = np.zeros(self.nx) + + # Field module variables + self.u = np.zeros(self.ntcell) + self.un = np.zeros(self.ntcell) + + self.c = 1.0 + self.T = 0.625 + self.dt = .0025 + def init_mesh(self): + xstart = 0.0 + xend = self.L + self.dx = (xend - xstart) / self.nx + + for i in range(0, self.nx+1): + self.x[i] = xstart + i * self.dx + + for i in range(0, self.nx): + self.xcc[i] = 0.5 * (self.x[i] + self.x[i + 1]) + +def RunEno(iorder): + eno = Eno(iorder) + init_coef(eno.iorder, eno.coef) + eno.init_mesh() + init_field(eno) + + nt = int(eno.T / eno.dt) + simu_time = eno.T + + t = 0.0 + + while t < simu_time: + runge_kutta(eno) + t += eno.dt + if t + eno.dt > simu_time: + dt = simu_time - t + + print(t) + visualize(eno) + return eno.xcc, np.copy(eno.u[eno.ist:eno.ied+1]) + +def main(): + iorder_max = 7 + xcc_list = [] + u_list = [] + for iorder in range(1, iorder_max+1): + xcc, u = RunEno(iorder) + xcc_list.append(xcc) + u_list.append(u) + + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/example/1d-linear-convection/eno/rusanov/rk3/eno1-7/01c/plot.py b/example/1d-linear-convection/eno/rusanov/rk3/eno1-7/01c/plot.py new file mode 100644 index 00000000..e389044c --- /dev/null +++ b/example/1d-linear-convection/eno/rusanov/rk3/eno1-7/01c/plot.py @@ -0,0 +1,53 @@ +import numpy as np +import matplotlib.pyplot as plt +import csv +import sys + +nvar = len(sys.argv) +print('nvar=',nvar) +print('sys.argv=',sys.argv) + +order = 1 +if nvar >= 2: + var = sys.argv[1] + print('var=',var) + order = int(var) + +print('order=',order) + +x_list = [] +u_list = [] + +with open('solution.plt', newline='') as csvfile: + #readCSV = csv.reader(csvfile, delimiter= ' ') + icount = 0 + for line in csvfile: + # 去除首尾空格,按连续空格分割 + row = line.strip().split() + #print("row=",row) + x_list.append(row[0]) + u_list.append(row[1]) + icount += 1 + +ni = icount +print("ni=",ni) + +#print("x_list=",x_list) + +x = np.zeros( ni ) +u = np.zeros( ni ) + +for i in range(0, ni): + x[i] = float(x_list[i]) + u[i] = float(u_list[i]) + +labelname = 'Eno' + str(order) + +plt.figure("OneFLOW-CFD Solver", figsize=(8, 6), dpi=100) +plt.plot(x, u, "b-", linewidth=1.0, marker = 's', markerfacecolor='None', label=labelname) +plt.xlabel("$x$") +plt.ylabel("$u$") +plt.title("burgers T=1") +plt.legend() +plt.tight_layout() +plt.show(); \ No newline at end of file diff --git a/example/1d-linear-convection/eno/rusanov/rk3/eno1-7/01d/eno.py b/example/1d-linear-convection/eno/rusanov/rk3/eno1-7/01d/eno.py new file mode 100644 index 00000000..3ad91b98 --- /dev/null +++ b/example/1d-linear-convection/eno/rusanov/rk3/eno1-7/01d/eno.py @@ -0,0 +1,328 @@ +import numpy as np +import matplotlib.pyplot as plt + +# 初始条件 +def initial_condition(x): + u0 = np.zeros_like(x) + for i in range(len(x)): + if 0.5 <= x[i] <= 1.0: + u0[i] = 2.0 + else: + u0[i] = 1.0 + return u0 + +# 理论解 +def analytical_solution(x, t, a, L): + # 初始条件沿 x - at 平移 + x_shifted = x - a * t + return initial_condition((x_shifted + L) % L) # 周期边界条件 + +def residual(q, eno): + reconstruction(q, eno) + inviscid_flux(eno.up1_2m, eno.up1_2p, eno.flux, eno) + for i in range(eno.nx): + eno.res[i] = -(eno.flux[i + 1] - eno.flux[i]) / eno.dx + +def reconstruction(q, eno): + # Choose the stencil by ENO method + eno.dd[0, 0:eno.ntcell-1] = q[0:eno.ntcell-1] + + for m in range(1, eno.iorder): + for j in range(0, eno.ntcell-1): + eno.dd[m, j] = eno.dd[m-1, j+1] - eno.dd[m-1, j] + + for i in range(eno.nx + 1): + eno.il[i] = i - 1 + for m in range(1, eno.iorder): + if abs(eno.dd[m, eno.il[i]-1+eno.ishift]) <= abs(eno.dd[m, eno.il[i]+eno.ishift]): + eno.il[i] -= 1 + + for i in range(eno.nx + 1): + eno.ir[i] = i + for m in range(1, eno.iorder): + if abs(eno.dd[m, eno.ir[i]-1+eno.ishift]) <= abs(eno.dd[m, eno.ir[i]+eno.ishift]): + eno.ir[i] -= 1 + + # Reconstruction u(j+1/2) + for i in range(eno.nx + 1): + k1 = eno.il[i] + k2 = eno.ir[i] + l1 = i - k1 + l2 = i - k2 + eno.up1_2m[i] = 0 + eno.up1_2p[i] = 0 + for m in range(eno.iorder): + eno.up1_2m[i] += q[k1 + eno.ishift + m] * eno.coef[l1, m] + eno.up1_2p[i] += q[k2 + eno.ishift + m] * eno.coef[l2, m] + +def inviscid_flux(up1_2m, up1_2p, flux, eno): + iflux = 0 + if iflux == 0: + rusanov_flux(up1_2m, up1_2p, flux, eno) + else: + engquist_osher_flux(up1_2m, up1_2p, flux, eno) + +def engquist_osher_flux(up1_2m, up1_2p, flux, eno): + for i in range(eno.nx + 1): + u_L = up1_2m[i] + u_R = up1_2p[i] + + cp = 0.5 * ( eno.c + abs(eno.c) ) + cm = 0.5 * ( eno.c - abs(eno.c) ) + + flux[i] = cp * uL + cm * u_R + +def rusanov_flux(up1_2m, up1_2p, flux, eno): + for i in range(eno.nx + 1): + u_L = up1_2m[i] + u_R = up1_2p[i] + F_L = eno.c * u_L # 左状态通量 + F_R = eno.c * u_R # 右状态通量 + alpha = abs(eno.c) # 最大波速 + flux[i] = 0.5 * (F_L + F_R) - 0.5 * alpha * (u_R - u_L) + + +def boundary(u, eno): + for i in range(-eno.ighost, 1): + u[eno.ist - 1 + i] = u[eno.ied + i] + for i in range(1, eno.ighost + 2): + u[eno.ied + i] = u[eno.ist - 1 + i] + +def update_oldfield(qn, q): + qn[:] = q[:] + +def init_coef( iorder, coef ): + if iorder == 1: + coef[0] = [1.0] + coef[1] = [1.0] + elif iorder == 2: + coef[0] = [3.0/2.0, -1.0/2.0] + coef[1] = [1.0/2.0, 1.0/2.0] + coef[2] = [-1.0/2.0, 3.0/2.0] + elif iorder == 3: + coef[0] = [ 11.0/6.0, -7.0/6.0, 1.0/3.0 ] + coef[1] = [ 1.0/3.0, 5.0/6.0, -1.0/6.0 ] + coef[2] = [ -1.0/6.0, 5.0/6.0, 1.0/3.0 ] + coef[3] = [ 1.0/3.0, -7.0/6.0, 11.0/6.0 ] + elif iorder == 4: + coef[0] = [ 25.0/12.0, -23.0/12.0, 13.0/12.0, -1.0/4.0 ] + coef[1] = [ 1.0/4.0, 13.0/12.0, -5.0/12.0, 1.0/12.0 ] + coef[2] = [ -1.0/12.0, 7.0/12.0, 7.0/12.0, -1.0/12.0 ] + coef[3] = [ 1.0/12.0, -5.0/12.0, 13.0/12.0, 1.0/4.0 ] + coef[4] = [ -1.0/4.0, 13.0/12.0, -23.0/12.0, 25.0/12.0 ] + elif iorder == 5: + coef[0] = [ 137.0/60.0, -163.0/60.0, 137.0/60.0, -21.0/20.0, 1.0/5.0 ] + coef[1] = [ 1.0/5.0, 77.0/60.0, -43.0/60.0, 17.0/60.0, -1.0/20.0 ] + coef[2] = [ -1.0/20.0, 9.0/20.0, 47.0/60.0, -13.0/60.0, 1.0/30.0 ] + coef[3] = [ 1.0/30.0, -13.0/60.0, 47.0/60.0, 9.0/20.0, -1.0/20.0 ] + coef[4] = [ -1.0/20.0, 17.0/60.0, -43.0/60.0, 77.0/60.0, 1.0/5.0 ] + coef[5] = [ 1.0/5.0, -21.0/20.0, 137.0/60.0, -163.0/60.0, 137.0/60.0 ] + elif iorder == 6: + coef[0] = [ 49.0/20.0, -71.0/20.0, 79.0/20.0, -163.0/60.0, 31.0/30.0, -1.0/6.0 ] + coef[1] = [ 1.0/6.0, 29.0/20.0, -21.0/20.0, 37.0/60.0, -13.0/60.0, 1.0/30.0 ] + coef[2] = [ -1.0/30.0, 11.0/30.0, 19.0/20.0, -23.0/60.0, 7.0/60.0, -1.0/60.0 ] + coef[3] = [ 1.0/60.0, -2.0/15.0, 37.0/60.0, 37.0/60.0, -2.0/15.0, 1.0/60.0 ] + coef[4] = [ -1.0/60.0, 7.0/60.0, -23.0/60.0, 19.0/20.0, 11.0/30.0, -1.0/30.0 ] + coef[5] = [ 1.0/30.0, -13.0/60.0, 37.0/60.0, -21.0/20.0, 29.0/20.0, 1.0/6.0 ] + coef[6] = [ -1.0/6.0, 31.0/30.0, -163.0/60.0, 79.0/20.0, -71.0/20.0, 49.0/20.0 ] + elif iorder == 7: + coef[0] = [ 363.0/140.0, -617.0/140.0, 853.0/140.0, -2341.0/420.0, 667.0/210.0, -43.0/42.0, 1.0/7.0 ] + coef[1] = [ 1.0/7.0, 223.0/140.0, -197.0/140.0, 153.0/140.0, -241.0/420.0, 37.0/210.0, -1.0/42.0 ] + coef[2] = [ -1.0/42.0, 13.0/42.0, 153.0/140.0, -241.0/420.0, 109.0/420.0, -31.0/420.0, 1.0/105.0 ] + coef[3] = [ 1.0/105.0, -19.0/210.0, 107.0/210.0, 319.0/420.0, -101.0/420.0, 5.0/84.0, -1.0/140.0 ] + coef[4] = [ -1.0/140.0, 5.0/84.0, -101.0/420.0, 319.0/420.0, 107.0/210.0, -19.0/210.0, 1.0/105.0 ] + coef[5] = [ 1.0/105.0, -31.0/420.0, 109.0/420.0, -241.0/420.0, 153.0/140.0, 13.0/42.0, -1.0/42.0 ] + coef[6] = [ -1.0/42.0, 37.0/210.0, -241.0/420.0, 153.0/140.0, -197.0/140.0, 223.0/140.0, 1.0/7.0 ] + coef[7] = [ 1.0/7.0, -43.0/42.0, 667.0/210.0, -2341.0/420.0, 853.0/140.0, -617.0/140.0, 363.0/140.0 ] + +def init_field(eno): + for i in range(eno.ist, eno.ied + 1): + j = i - eno.ist + if 0.5 <= eno.xcc[j] <= 1.0: + eno.u[i] = 2.0 + else: + eno.u[i] = 1.0 + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def runge_kutta(eno): + rk = eno.rk + if rk == 1: + runge_kutta_1(eno) + elif rk == 2: + runge_kutta_2(eno) + else: + runge_kutta_3(eno) + +def runge_kutta_1(eno): + global u, un, dt + residual(u, eno) + for i in range(nx): + j = i + ishift + u[j] = u[j] + dt * res[i] + boundary(u) + update_oldfield(un, u) + +def runge_kutta_2(eno): + #global u, un, dt + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = eno.u[j] + eno.dt * eno.res[i] + boundary(eno.u, eno) + + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = 0.5 * eno.un[j] + 0.5 * eno.u[j] + 0.5 * eno.dt * eno.res[i] + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def runge_kutta_3(eno): + global u, un, dt + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = eno.u[j] + eno.dt * eno.res[i] + boundary(eno.u, eno) + + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = 0.75 * eno.un[j] + 0.25 * eno.u[j] + 0.25 * eno.dt * eno.res[i] + boundary(eno.u, eno) + + residual(eno.u, eno) + c1, c2, c3 = 1.0/3.0, 2.0/3.0, 2.0/3.0 + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = c1 * eno.un[j] + c2 * eno.u[j] + c3 * eno.dt * eno.res[i] + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def get_ordinal_numbers(order): + if order == 1: + return 'st' + elif order == 2: + return 'nd' + elif order == 3: + return 'rd' + else: + return 'th' + +def visualize(eno): + with open('solution.plt', 'w') as f: + for i in range(eno.ist, eno.ied + 1): + j = i - eno.ist + f.write(f"{eno.xcc[j]:20.10e}{eno.u[i]:20.10e}\n") + + # 可视化 + u_numerical = np.copy(eno.u[eno.ist:eno.ied+1]) + print(f'u_numerical.size={u_numerical.size}') + print(f'eno.xcc.size={eno.xcc.size}') + #计算理论解 + u_analytical = analytical_solution(eno.xcc, eno.T, eno.c, eno.L) + print(f'u_analytical.size={u_analytical.size}') + plt.figure("OneFLOW-CFD Solver", figsize=(10, 6)) + plt.scatter(eno.xcc, u_numerical, facecolor="none", edgecolor="blue", s=20, linewidths=0.5, label=f'Numerical (Rusanov)') + plt.plot(eno.xcc, u_analytical, 'r--', label='Analytical') + plt.xlabel('x') + plt.ylabel('u') + ordinal1 = get_ordinal_numbers(eno.iorder) + ordinal2 = get_ordinal_numbers(eno.rk) + plt.title(f'1D Convection Equation at t = {eno.T:.3f} using {eno.iorder}{ordinal1}-order ENO and {eno.rk}{ordinal2}-order Runge-Kutta methods') + plt.legend() + plt.grid(True, color='gray', linestyle='--', linewidth=0.5, alpha=0.7) + plt.tight_layout() + plt.show() + +class Eno: + def __init__(self, iorder): + self.nx = 40 + self.rk = 2 + self.iorder = iorder + self.ighost = iorder + self.ishift = self.ighost + 1 + self.ist = 0 + self.ishift + self.ied = self.nx - 1 + self.ishift + self.ntcell = self.nx + 2 * self.ishift + self.isize = iorder * (iorder + 1) + + self.il = np.zeros(self.nx + 1, dtype=int) + self.ir = np.zeros(self.nx + 1, dtype=int) + self.coef = np.zeros((iorder + 1, iorder)) + self.dd = np.zeros((iorder, self.ntcell)) + self.up1_2m = np.zeros(self.nx + 1) + self.up1_2p = np.zeros(self.nx + 1) + self.flux = np.zeros(self.nx + 1) + self.res = np.zeros(self.nx) + self.L = 2.0 + self.x = np.zeros(self.nx + 1) + self.xcc = np.zeros(self.nx) + + # Field module variables + self.u = np.zeros(self.ntcell) + self.un = np.zeros(self.ntcell) + + self.c = 1.0 + self.T = 0.625 + self.dt = .0025 + def init_mesh(self): + xstart = 0.0 + xend = self.L + self.dx = (xend - xstart) / self.nx + + for i in range(0, self.nx+1): + self.x[i] = xstart + i * self.dx + + for i in range(0, self.nx): + self.xcc[i] = 0.5 * (self.x[i] + self.x[i + 1]) + +def plot_eno_field(xcc_list, u_list): + n = len(u_list) + + plt.figure("OneFLOW-CFD Solver", figsize=(10, 6)) + for i in range(0, n): + plt.scatter(xcc_list[i], u_list[i], facecolor="none", edgecolor="blue", s=20, linewidths=0.5, label=f'Numerical (Rusanov)') + plt.xlabel('x') + plt.ylabel('u') + plt.legend() + plt.grid(True, color='gray', linestyle='--', linewidth=0.5, alpha=0.7) + plt.tight_layout() + plt.show() + +def RunEno(iorder): + eno = Eno(iorder) + init_coef(eno.iorder, eno.coef) + eno.init_mesh() + init_field(eno) + + nt = int(eno.T / eno.dt) + simu_time = eno.T + + t = 0.0 + + while t < simu_time: + runge_kutta(eno) + t += eno.dt + if t + eno.dt > simu_time: + dt = simu_time - t + + print(t) + #visualize(eno) + return eno.xcc, np.copy(eno.u[eno.ist:eno.ied+1]) + +def main(): + iorder_max = 7 + xcc_list = [] + u_list = [] + for iorder in range(1, iorder_max+1): + xcc, u = RunEno(iorder) + xcc_list.append(xcc) + u_list.append(u) + + plot_eno_field(xcc_list, u_list) + + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/example/1d-linear-convection/eno/rusanov/rk3/eno1-7/01d/plot.py b/example/1d-linear-convection/eno/rusanov/rk3/eno1-7/01d/plot.py new file mode 100644 index 00000000..e389044c --- /dev/null +++ b/example/1d-linear-convection/eno/rusanov/rk3/eno1-7/01d/plot.py @@ -0,0 +1,53 @@ +import numpy as np +import matplotlib.pyplot as plt +import csv +import sys + +nvar = len(sys.argv) +print('nvar=',nvar) +print('sys.argv=',sys.argv) + +order = 1 +if nvar >= 2: + var = sys.argv[1] + print('var=',var) + order = int(var) + +print('order=',order) + +x_list = [] +u_list = [] + +with open('solution.plt', newline='') as csvfile: + #readCSV = csv.reader(csvfile, delimiter= ' ') + icount = 0 + for line in csvfile: + # 去除首尾空格,按连续空格分割 + row = line.strip().split() + #print("row=",row) + x_list.append(row[0]) + u_list.append(row[1]) + icount += 1 + +ni = icount +print("ni=",ni) + +#print("x_list=",x_list) + +x = np.zeros( ni ) +u = np.zeros( ni ) + +for i in range(0, ni): + x[i] = float(x_list[i]) + u[i] = float(u_list[i]) + +labelname = 'Eno' + str(order) + +plt.figure("OneFLOW-CFD Solver", figsize=(8, 6), dpi=100) +plt.plot(x, u, "b-", linewidth=1.0, marker = 's', markerfacecolor='None', label=labelname) +plt.xlabel("$x$") +plt.ylabel("$u$") +plt.title("burgers T=1") +plt.legend() +plt.tight_layout() +plt.show(); \ No newline at end of file diff --git a/example/1d-linear-convection/eno/rusanov/rk3/eno1-7/01e/eno.py b/example/1d-linear-convection/eno/rusanov/rk3/eno1-7/01e/eno.py new file mode 100644 index 00000000..b03bf34d --- /dev/null +++ b/example/1d-linear-convection/eno/rusanov/rk3/eno1-7/01e/eno.py @@ -0,0 +1,359 @@ +import numpy as np +import matplotlib.pyplot as plt + +# 初始条件 +def initial_condition(x): + u0 = np.zeros_like(x) + for i in range(len(x)): + if 0.5 <= x[i] <= 1.0: + u0[i] = 2.0 + else: + u0[i] = 1.0 + return u0 + +# 理论解 +def analytical_solution(x, t, a, L): + # 初始条件沿 x - at 平移 + x_shifted = x - a * t + return initial_condition((x_shifted + L) % L) # 周期边界条件 + +def residual(q, eno): + reconstruction(q, eno) + inviscid_flux(eno.up1_2m, eno.up1_2p, eno.flux, eno) + for i in range(eno.nx): + eno.res[i] = -(eno.flux[i + 1] - eno.flux[i]) / eno.dx + +def reconstruction(q, eno): + # Choose the stencil by ENO method + eno.dd[0, 0:eno.ntcell-1] = q[0:eno.ntcell-1] + + for m in range(1, eno.iorder): + for j in range(0, eno.ntcell-1): + eno.dd[m, j] = eno.dd[m-1, j+1] - eno.dd[m-1, j] + + for i in range(eno.nx + 1): + eno.il[i] = i - 1 + for m in range(1, eno.iorder): + if abs(eno.dd[m, eno.il[i]-1+eno.ishift]) <= abs(eno.dd[m, eno.il[i]+eno.ishift]): + eno.il[i] -= 1 + + for i in range(eno.nx + 1): + eno.ir[i] = i + for m in range(1, eno.iorder): + if abs(eno.dd[m, eno.ir[i]-1+eno.ishift]) <= abs(eno.dd[m, eno.ir[i]+eno.ishift]): + eno.ir[i] -= 1 + + # Reconstruction u(j+1/2) + for i in range(eno.nx + 1): + k1 = eno.il[i] + k2 = eno.ir[i] + l1 = i - k1 + l2 = i - k2 + eno.up1_2m[i] = 0 + eno.up1_2p[i] = 0 + for m in range(eno.iorder): + eno.up1_2m[i] += q[k1 + eno.ishift + m] * eno.coef[l1, m] + eno.up1_2p[i] += q[k2 + eno.ishift + m] * eno.coef[l2, m] + +def inviscid_flux(up1_2m, up1_2p, flux, eno): + iflux = 0 + if iflux == 0: + rusanov_flux(up1_2m, up1_2p, flux, eno) + else: + engquist_osher_flux(up1_2m, up1_2p, flux, eno) + +def engquist_osher_flux(up1_2m, up1_2p, flux, eno): + for i in range(eno.nx + 1): + u_L = up1_2m[i] + u_R = up1_2p[i] + + cp = 0.5 * ( eno.c + abs(eno.c) ) + cm = 0.5 * ( eno.c - abs(eno.c) ) + + flux[i] = cp * uL + cm * u_R + +def rusanov_flux(up1_2m, up1_2p, flux, eno): + for i in range(eno.nx + 1): + u_L = up1_2m[i] + u_R = up1_2p[i] + F_L = eno.c * u_L # 左状态通量 + F_R = eno.c * u_R # 右状态通量 + alpha = abs(eno.c) # 最大波速 + flux[i] = 0.5 * (F_L + F_R) - 0.5 * alpha * (u_R - u_L) + + +def boundary(u, eno): + for i in range(-eno.ighost, 1): + u[eno.ist - 1 + i] = u[eno.ied + i] + for i in range(1, eno.ighost + 2): + u[eno.ied + i] = u[eno.ist - 1 + i] + +def update_oldfield(qn, q): + qn[:] = q[:] + +def init_coef( iorder, coef ): + if iorder == 1: + coef[0] = [1.0] + coef[1] = [1.0] + elif iorder == 2: + coef[0] = [3.0/2.0, -1.0/2.0] + coef[1] = [1.0/2.0, 1.0/2.0] + coef[2] = [-1.0/2.0, 3.0/2.0] + elif iorder == 3: + coef[0] = [ 11.0/6.0, -7.0/6.0, 1.0/3.0 ] + coef[1] = [ 1.0/3.0, 5.0/6.0, -1.0/6.0 ] + coef[2] = [ -1.0/6.0, 5.0/6.0, 1.0/3.0 ] + coef[3] = [ 1.0/3.0, -7.0/6.0, 11.0/6.0 ] + elif iorder == 4: + coef[0] = [ 25.0/12.0, -23.0/12.0, 13.0/12.0, -1.0/4.0 ] + coef[1] = [ 1.0/4.0, 13.0/12.0, -5.0/12.0, 1.0/12.0 ] + coef[2] = [ -1.0/12.0, 7.0/12.0, 7.0/12.0, -1.0/12.0 ] + coef[3] = [ 1.0/12.0, -5.0/12.0, 13.0/12.0, 1.0/4.0 ] + coef[4] = [ -1.0/4.0, 13.0/12.0, -23.0/12.0, 25.0/12.0 ] + elif iorder == 5: + coef[0] = [ 137.0/60.0, -163.0/60.0, 137.0/60.0, -21.0/20.0, 1.0/5.0 ] + coef[1] = [ 1.0/5.0, 77.0/60.0, -43.0/60.0, 17.0/60.0, -1.0/20.0 ] + coef[2] = [ -1.0/20.0, 9.0/20.0, 47.0/60.0, -13.0/60.0, 1.0/30.0 ] + coef[3] = [ 1.0/30.0, -13.0/60.0, 47.0/60.0, 9.0/20.0, -1.0/20.0 ] + coef[4] = [ -1.0/20.0, 17.0/60.0, -43.0/60.0, 77.0/60.0, 1.0/5.0 ] + coef[5] = [ 1.0/5.0, -21.0/20.0, 137.0/60.0, -163.0/60.0, 137.0/60.0 ] + elif iorder == 6: + coef[0] = [ 49.0/20.0, -71.0/20.0, 79.0/20.0, -163.0/60.0, 31.0/30.0, -1.0/6.0 ] + coef[1] = [ 1.0/6.0, 29.0/20.0, -21.0/20.0, 37.0/60.0, -13.0/60.0, 1.0/30.0 ] + coef[2] = [ -1.0/30.0, 11.0/30.0, 19.0/20.0, -23.0/60.0, 7.0/60.0, -1.0/60.0 ] + coef[3] = [ 1.0/60.0, -2.0/15.0, 37.0/60.0, 37.0/60.0, -2.0/15.0, 1.0/60.0 ] + coef[4] = [ -1.0/60.0, 7.0/60.0, -23.0/60.0, 19.0/20.0, 11.0/30.0, -1.0/30.0 ] + coef[5] = [ 1.0/30.0, -13.0/60.0, 37.0/60.0, -21.0/20.0, 29.0/20.0, 1.0/6.0 ] + coef[6] = [ -1.0/6.0, 31.0/30.0, -163.0/60.0, 79.0/20.0, -71.0/20.0, 49.0/20.0 ] + elif iorder == 7: + coef[0] = [ 363.0/140.0, -617.0/140.0, 853.0/140.0, -2341.0/420.0, 667.0/210.0, -43.0/42.0, 1.0/7.0 ] + coef[1] = [ 1.0/7.0, 223.0/140.0, -197.0/140.0, 153.0/140.0, -241.0/420.0, 37.0/210.0, -1.0/42.0 ] + coef[2] = [ -1.0/42.0, 13.0/42.0, 153.0/140.0, -241.0/420.0, 109.0/420.0, -31.0/420.0, 1.0/105.0 ] + coef[3] = [ 1.0/105.0, -19.0/210.0, 107.0/210.0, 319.0/420.0, -101.0/420.0, 5.0/84.0, -1.0/140.0 ] + coef[4] = [ -1.0/140.0, 5.0/84.0, -101.0/420.0, 319.0/420.0, 107.0/210.0, -19.0/210.0, 1.0/105.0 ] + coef[5] = [ 1.0/105.0, -31.0/420.0, 109.0/420.0, -241.0/420.0, 153.0/140.0, 13.0/42.0, -1.0/42.0 ] + coef[6] = [ -1.0/42.0, 37.0/210.0, -241.0/420.0, 153.0/140.0, -197.0/140.0, 223.0/140.0, 1.0/7.0 ] + coef[7] = [ 1.0/7.0, -43.0/42.0, 667.0/210.0, -2341.0/420.0, 853.0/140.0, -617.0/140.0, 363.0/140.0 ] + +def init_field(eno): + for i in range(eno.ist, eno.ied + 1): + j = i - eno.ist + if 0.5 <= eno.xcc[j] <= 1.0: + eno.u[i] = 2.0 + else: + eno.u[i] = 1.0 + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def runge_kutta(eno): + rk = eno.rk + if rk == 1: + runge_kutta_1(eno) + elif rk == 2: + runge_kutta_2(eno) + else: + runge_kutta_3(eno) + +def runge_kutta_1(eno): + residual(u, eno) + for i in range(nx): + j = i + ishift + u[j] = u[j] + dt * res[i] + boundary(u) + update_oldfield(un, u) + +def runge_kutta_2(eno): + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = eno.u[j] + eno.dt * eno.res[i] + boundary(eno.u, eno) + + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = 0.5 * eno.un[j] + 0.5 * eno.u[j] + 0.5 * eno.dt * eno.res[i] + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def runge_kutta_3(eno): + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = eno.u[j] + eno.dt * eno.res[i] + boundary(eno.u, eno) + + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = 0.75 * eno.un[j] + 0.25 * eno.u[j] + 0.25 * eno.dt * eno.res[i] + boundary(eno.u, eno) + + residual(eno.u, eno) + c1, c2, c3 = 1.0/3.0, 2.0/3.0, 2.0/3.0 + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = c1 * eno.un[j] + c2 * eno.u[j] + c3 * eno.dt * eno.res[i] + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def get_ordinal_numbers(order): + if order == 1: + return 'st' + elif order == 2: + return 'nd' + elif order == 3: + return 'rd' + else: + return 'th' + +def visualize(eno): + with open('solution.plt', 'w') as f: + for i in range(eno.ist, eno.ied + 1): + j = i - eno.ist + f.write(f"{eno.xcc[j]:20.10e}{eno.u[i]:20.10e}\n") + + # 可视化 + u_numerical = np.copy(eno.u[eno.ist:eno.ied+1]) + print(f'u_numerical.size={u_numerical.size}') + print(f'eno.xcc.size={eno.xcc.size}') + #计算理论解 + u_analytical = analytical_solution(eno.xcc, eno.T, eno.c, eno.L) + print(f'u_analytical.size={u_analytical.size}') + plt.figure("OneFLOW-CFD Solver", figsize=(10, 6)) + plt.scatter(eno.xcc, u_numerical, facecolor="none", edgecolor="blue", s=20, linewidths=0.5, label=f'Numerical (Rusanov)') + plt.plot(eno.xcc, u_analytical, 'r--', label='Analytical') + plt.xlabel('x') + plt.ylabel('u') + ordinal1 = get_ordinal_numbers(eno.iorder) + ordinal2 = get_ordinal_numbers(eno.rk) + plt.title(f'1D Convection Equation at t = {eno.T:.3f} using {eno.iorder}{ordinal1}-order ENO and {eno.rk}{ordinal2}-order Runge-Kutta methods') + plt.legend() + plt.grid(True, color='gray', linestyle='--', linewidth=0.5, alpha=0.7) + plt.tight_layout() + plt.show() + +class Mesh: + def __init__(self): + self.nx = 40 + self.L = 2.0 + self.x = np.zeros(self.nx + 1) + self.xcc = np.zeros(self.nx) + self.init_mesh() + def init_mesh(self): + xstart = 0.0 + xend = self.L + self.dx = (xend - xstart) / self.nx + + for i in range(0, self.nx+1): + self.x[i] = xstart + i * self.dx + + for i in range(0, self.nx): + self.xcc[i] = 0.5 * (self.x[i] + self.x[i + 1]) + +class Eno: + def __init__(self, iorder, mesh): + self.mesh = mesh + self.nx = 40 + self.rk = 2 + self.iorder = iorder + self.ighost = iorder + self.ishift = self.ighost + 1 + self.ist = 0 + self.ishift + self.ied = self.nx - 1 + self.ishift + self.ntcell = self.nx + 2 * self.ishift + self.isize = iorder * (iorder + 1) + + self.il = np.zeros(self.nx + 1, dtype=int) + self.ir = np.zeros(self.nx + 1, dtype=int) + self.coef = np.zeros((iorder + 1, iorder)) + self.dd = np.zeros((iorder, self.ntcell)) + self.up1_2m = np.zeros(self.nx + 1) + self.up1_2p = np.zeros(self.nx + 1) + self.flux = np.zeros(self.nx + 1) + self.res = np.zeros(self.nx) + self.L = 2.0 + self.x = np.zeros(self.nx + 1) + self.xcc = np.zeros(self.nx) + + # Field module variables + self.u = np.zeros(self.ntcell) + self.un = np.zeros(self.ntcell) + + self.c = 1.0 + self.T = 0.625 + self.dt = .0025 + def init_mesh(self): + xstart = 0.0 + xend = self.L + self.dx = (xend - xstart) / self.nx + + for i in range(0, self.nx+1): + self.x[i] = xstart + i * self.dx + + for i in range(0, self.nx): + self.xcc[i] = 0.5 * (self.x[i] + self.x[i + 1]) + +def plot_eno_field(xcc_list, u_list): + # 定义一个包含不同颜色、线形和标记的列表 + styles = [ + {'color': 'black', 'linestyle': '-', 'marker': 'o'}, + {'color': 'blue', 'linestyle': '--', 'marker': 's'}, + {'color': 'black', 'linestyle': '-', 'marker': '^'}, + {'color': 'blue', 'linestyle': '--', 'marker': 'v'}, + {'color': 'black', 'linestyle': '-', 'marker': '<'}, + {'color': 'blue', 'linestyle': '--', 'marker': '>'}, + {'color': 'black', 'linestyle': '-', 'marker': 'D'}, + ] + + n = len(u_list) + num_styles = len(styles) + + plt.figure("OneFLOW-CFD Solver", figsize=(10, 6)) + for i in range(0, n): + style = styles[i % num_styles] + plt.plot(xcc_list[i], u_list[i], marker=style['marker'], markerfacecolor='none', linestyle=style['linestyle'], color=style['color'], \ + markersize=5, linewidth=0.5, alpha=1.0, label=f'Numerical (Rusanov)') + plt.xlabel('x') + plt.ylabel('u') + plt.legend() + plt.grid(True, color='gray', linestyle='--', linewidth=0.5, alpha=0.7) + plt.tight_layout() + plt.show() + +def RunEno(iorder, mesh): + eno = Eno(iorder, mesh) + init_coef(eno.iorder, eno.coef) + #eno.init_mesh() + init_field(eno) + + nt = int(eno.T / eno.dt) + simu_time = eno.T + + t = 0.0 + + while t < simu_time: + runge_kutta(eno) + t += eno.dt + if t + eno.dt > simu_time: + dt = simu_time - t + + print(t) + #visualize(eno) + return eno.xcc, np.copy(eno.u[eno.ist:eno.ied+1]) + +def main(): + iorder_max = 7 + mesh = Mesh() + xcc_list = [] + u_list = [] + for iorder in range(1, iorder_max+1): + xcc, u = RunEno(mesh, iorder) + xcc_list.append(xcc) + u_list.append(u) + + plot_eno_field(xcc_list, u_list) + + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/example/1d-linear-convection/eno/rusanov/rk3/eno1-7/01e/plot.py b/example/1d-linear-convection/eno/rusanov/rk3/eno1-7/01e/plot.py new file mode 100644 index 00000000..e389044c --- /dev/null +++ b/example/1d-linear-convection/eno/rusanov/rk3/eno1-7/01e/plot.py @@ -0,0 +1,53 @@ +import numpy as np +import matplotlib.pyplot as plt +import csv +import sys + +nvar = len(sys.argv) +print('nvar=',nvar) +print('sys.argv=',sys.argv) + +order = 1 +if nvar >= 2: + var = sys.argv[1] + print('var=',var) + order = int(var) + +print('order=',order) + +x_list = [] +u_list = [] + +with open('solution.plt', newline='') as csvfile: + #readCSV = csv.reader(csvfile, delimiter= ' ') + icount = 0 + for line in csvfile: + # 去除首尾空格,按连续空格分割 + row = line.strip().split() + #print("row=",row) + x_list.append(row[0]) + u_list.append(row[1]) + icount += 1 + +ni = icount +print("ni=",ni) + +#print("x_list=",x_list) + +x = np.zeros( ni ) +u = np.zeros( ni ) + +for i in range(0, ni): + x[i] = float(x_list[i]) + u[i] = float(u_list[i]) + +labelname = 'Eno' + str(order) + +plt.figure("OneFLOW-CFD Solver", figsize=(8, 6), dpi=100) +plt.plot(x, u, "b-", linewidth=1.0, marker = 's', markerfacecolor='None', label=labelname) +plt.xlabel("$x$") +plt.ylabel("$u$") +plt.title("burgers T=1") +plt.legend() +plt.tight_layout() +plt.show(); \ No newline at end of file diff --git a/example/1d-linear-convection/eno/rusanov/rk3/eno1-7/01f/eno.py b/example/1d-linear-convection/eno/rusanov/rk3/eno1-7/01f/eno.py new file mode 100644 index 00000000..8be21d57 --- /dev/null +++ b/example/1d-linear-convection/eno/rusanov/rk3/eno1-7/01f/eno.py @@ -0,0 +1,344 @@ +import numpy as np +import matplotlib.pyplot as plt + +# 初始条件 +def initial_condition(x): + u0 = np.zeros_like(x) + for i in range(len(x)): + if 0.5 <= x[i] <= 1.0: + u0[i] = 2.0 + else: + u0[i] = 1.0 + return u0 + +# 理论解 +def analytical_solution(x, t, a, L): + # 初始条件沿 x - at 平移 + x_shifted = x - a * t + return initial_condition((x_shifted + L) % L) # 周期边界条件 + +def residual(q, eno): + reconstruction(q, eno) + inviscid_flux(eno.up1_2m, eno.up1_2p, eno.flux, eno) + for i in range(eno.nx): + eno.res[i] = -(eno.flux[i + 1] - eno.flux[i]) / eno.mesh.dx + +def reconstruction(q, eno): + # Choose the stencil by ENO method + eno.dd[0, 0:eno.ntcell-1] = q[0:eno.ntcell-1] + + for m in range(1, eno.iorder): + for j in range(0, eno.ntcell-1): + eno.dd[m, j] = eno.dd[m-1, j+1] - eno.dd[m-1, j] + + for i in range(eno.nx + 1): + eno.il[i] = i - 1 + for m in range(1, eno.iorder): + if abs(eno.dd[m, eno.il[i]-1+eno.ishift]) <= abs(eno.dd[m, eno.il[i]+eno.ishift]): + eno.il[i] -= 1 + + for i in range(eno.nx + 1): + eno.ir[i] = i + for m in range(1, eno.iorder): + if abs(eno.dd[m, eno.ir[i]-1+eno.ishift]) <= abs(eno.dd[m, eno.ir[i]+eno.ishift]): + eno.ir[i] -= 1 + + # Reconstruction u(j+1/2) + for i in range(eno.nx + 1): + k1 = eno.il[i] + k2 = eno.ir[i] + l1 = i - k1 + l2 = i - k2 + eno.up1_2m[i] = 0 + eno.up1_2p[i] = 0 + for m in range(eno.iorder): + eno.up1_2m[i] += q[k1 + eno.ishift + m] * eno.coef[l1, m] + eno.up1_2p[i] += q[k2 + eno.ishift + m] * eno.coef[l2, m] + +def inviscid_flux(up1_2m, up1_2p, flux, eno): + iflux = 0 + if iflux == 0: + rusanov_flux(up1_2m, up1_2p, flux, eno) + else: + engquist_osher_flux(up1_2m, up1_2p, flux, eno) + +def engquist_osher_flux(up1_2m, up1_2p, flux, eno): + for i in range(eno.nx + 1): + u_L = up1_2m[i] + u_R = up1_2p[i] + + cp = 0.5 * ( eno.c + abs(eno.c) ) + cm = 0.5 * ( eno.c - abs(eno.c) ) + + flux[i] = cp * uL + cm * u_R + +def rusanov_flux(up1_2m, up1_2p, flux, eno): + for i in range(eno.nx + 1): + u_L = up1_2m[i] + u_R = up1_2p[i] + F_L = eno.c * u_L # 左状态通量 + F_R = eno.c * u_R # 右状态通量 + alpha = abs(eno.c) # 最大波速 + flux[i] = 0.5 * (F_L + F_R) - 0.5 * alpha * (u_R - u_L) + + +def boundary(u, eno): + for i in range(-eno.ighost, 1): + u[eno.ist - 1 + i] = u[eno.ied + i] + for i in range(1, eno.ighost + 2): + u[eno.ied + i] = u[eno.ist - 1 + i] + +def update_oldfield(qn, q): + qn[:] = q[:] + +def init_coef( iorder, coef ): + if iorder == 1: + coef[0] = [1.0] + coef[1] = [1.0] + elif iorder == 2: + coef[0] = [3.0/2.0, -1.0/2.0] + coef[1] = [1.0/2.0, 1.0/2.0] + coef[2] = [-1.0/2.0, 3.0/2.0] + elif iorder == 3: + coef[0] = [ 11.0/6.0, -7.0/6.0, 1.0/3.0 ] + coef[1] = [ 1.0/3.0, 5.0/6.0, -1.0/6.0 ] + coef[2] = [ -1.0/6.0, 5.0/6.0, 1.0/3.0 ] + coef[3] = [ 1.0/3.0, -7.0/6.0, 11.0/6.0 ] + elif iorder == 4: + coef[0] = [ 25.0/12.0, -23.0/12.0, 13.0/12.0, -1.0/4.0 ] + coef[1] = [ 1.0/4.0, 13.0/12.0, -5.0/12.0, 1.0/12.0 ] + coef[2] = [ -1.0/12.0, 7.0/12.0, 7.0/12.0, -1.0/12.0 ] + coef[3] = [ 1.0/12.0, -5.0/12.0, 13.0/12.0, 1.0/4.0 ] + coef[4] = [ -1.0/4.0, 13.0/12.0, -23.0/12.0, 25.0/12.0 ] + elif iorder == 5: + coef[0] = [ 137.0/60.0, -163.0/60.0, 137.0/60.0, -21.0/20.0, 1.0/5.0 ] + coef[1] = [ 1.0/5.0, 77.0/60.0, -43.0/60.0, 17.0/60.0, -1.0/20.0 ] + coef[2] = [ -1.0/20.0, 9.0/20.0, 47.0/60.0, -13.0/60.0, 1.0/30.0 ] + coef[3] = [ 1.0/30.0, -13.0/60.0, 47.0/60.0, 9.0/20.0, -1.0/20.0 ] + coef[4] = [ -1.0/20.0, 17.0/60.0, -43.0/60.0, 77.0/60.0, 1.0/5.0 ] + coef[5] = [ 1.0/5.0, -21.0/20.0, 137.0/60.0, -163.0/60.0, 137.0/60.0 ] + elif iorder == 6: + coef[0] = [ 49.0/20.0, -71.0/20.0, 79.0/20.0, -163.0/60.0, 31.0/30.0, -1.0/6.0 ] + coef[1] = [ 1.0/6.0, 29.0/20.0, -21.0/20.0, 37.0/60.0, -13.0/60.0, 1.0/30.0 ] + coef[2] = [ -1.0/30.0, 11.0/30.0, 19.0/20.0, -23.0/60.0, 7.0/60.0, -1.0/60.0 ] + coef[3] = [ 1.0/60.0, -2.0/15.0, 37.0/60.0, 37.0/60.0, -2.0/15.0, 1.0/60.0 ] + coef[4] = [ -1.0/60.0, 7.0/60.0, -23.0/60.0, 19.0/20.0, 11.0/30.0, -1.0/30.0 ] + coef[5] = [ 1.0/30.0, -13.0/60.0, 37.0/60.0, -21.0/20.0, 29.0/20.0, 1.0/6.0 ] + coef[6] = [ -1.0/6.0, 31.0/30.0, -163.0/60.0, 79.0/20.0, -71.0/20.0, 49.0/20.0 ] + elif iorder == 7: + coef[0] = [ 363.0/140.0, -617.0/140.0, 853.0/140.0, -2341.0/420.0, 667.0/210.0, -43.0/42.0, 1.0/7.0 ] + coef[1] = [ 1.0/7.0, 223.0/140.0, -197.0/140.0, 153.0/140.0, -241.0/420.0, 37.0/210.0, -1.0/42.0 ] + coef[2] = [ -1.0/42.0, 13.0/42.0, 153.0/140.0, -241.0/420.0, 109.0/420.0, -31.0/420.0, 1.0/105.0 ] + coef[3] = [ 1.0/105.0, -19.0/210.0, 107.0/210.0, 319.0/420.0, -101.0/420.0, 5.0/84.0, -1.0/140.0 ] + coef[4] = [ -1.0/140.0, 5.0/84.0, -101.0/420.0, 319.0/420.0, 107.0/210.0, -19.0/210.0, 1.0/105.0 ] + coef[5] = [ 1.0/105.0, -31.0/420.0, 109.0/420.0, -241.0/420.0, 153.0/140.0, 13.0/42.0, -1.0/42.0 ] + coef[6] = [ -1.0/42.0, 37.0/210.0, -241.0/420.0, 153.0/140.0, -197.0/140.0, 223.0/140.0, 1.0/7.0 ] + coef[7] = [ 1.0/7.0, -43.0/42.0, 667.0/210.0, -2341.0/420.0, 853.0/140.0, -617.0/140.0, 363.0/140.0 ] + +def init_field(eno): + for i in range(eno.ist, eno.ied + 1): + j = i - eno.ist + if 0.5 <= eno.mesh.xcc[j] <= 1.0: + eno.u[i] = 2.0 + else: + eno.u[i] = 1.0 + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def runge_kutta(eno): + rk = eno.rk + if rk == 1: + runge_kutta_1(eno) + elif rk == 2: + runge_kutta_2(eno) + else: + runge_kutta_3(eno) + +def runge_kutta_1(eno): + residual(u, eno) + for i in range(nx): + j = i + ishift + u[j] = u[j] + dt * res[i] + boundary(u) + update_oldfield(un, u) + +def runge_kutta_2(eno): + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = eno.u[j] + eno.dt * eno.res[i] + boundary(eno.u, eno) + + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = 0.5 * eno.un[j] + 0.5 * eno.u[j] + 0.5 * eno.dt * eno.res[i] + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def runge_kutta_3(eno): + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = eno.u[j] + eno.dt * eno.res[i] + boundary(eno.u, eno) + + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = 0.75 * eno.un[j] + 0.25 * eno.u[j] + 0.25 * eno.dt * eno.res[i] + boundary(eno.u, eno) + + residual(eno.u, eno) + c1, c2, c3 = 1.0/3.0, 2.0/3.0, 2.0/3.0 + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = c1 * eno.un[j] + c2 * eno.u[j] + c3 * eno.dt * eno.res[i] + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def get_ordinal_numbers(order): + if order == 1: + return 'st' + elif order == 2: + return 'nd' + elif order == 3: + return 'rd' + else: + return 'th' + +def visualize(eno): + with open('solution.plt', 'w') as f: + for i in range(eno.ist, eno.ied + 1): + j = i - eno.ist + f.write(f"{eno.xcc[j]:20.10e}{eno.u[i]:20.10e}\n") + + # 可视化 + u_numerical = np.copy(eno.u[eno.ist:eno.ied+1]) + print(f'u_numerical.size={u_numerical.size}') + print(f'eno.xcc.size={eno.xcc.size}') + #计算理论解 + u_analytical = analytical_solution(eno.xcc, eno.T, eno.c, eno.L) + print(f'u_analytical.size={u_analytical.size}') + plt.figure("OneFLOW-CFD Solver", figsize=(10, 6)) + plt.scatter(eno.xcc, u_numerical, facecolor="none", edgecolor="blue", s=20, linewidths=0.5, label=f'Numerical (Rusanov)') + plt.plot(eno.xcc, u_analytical, 'r--', label='Analytical') + plt.xlabel('x') + plt.ylabel('u') + ordinal1 = get_ordinal_numbers(eno.iorder) + ordinal2 = get_ordinal_numbers(eno.rk) + plt.title(f'1D Convection Equation at t = {eno.T:.3f} using {eno.iorder}{ordinal1}-order ENO and {eno.rk}{ordinal2}-order Runge-Kutta methods') + plt.legend() + plt.grid(True, color='gray', linestyle='--', linewidth=0.5, alpha=0.7) + plt.tight_layout() + plt.show() + +class Mesh: + def __init__(self): + self.nx = 40 + self.L = 2.0 + self.x = np.zeros(self.nx + 1) + self.xcc = np.zeros(self.nx) + self.init_mesh() + def init_mesh(self): + xstart = 0.0 + xend = self.L + self.dx = (xend - xstart) / self.nx + + for i in range(0, self.nx+1): + self.x[i] = xstart + i * self.dx + + for i in range(0, self.nx): + self.xcc[i] = 0.5 * (self.x[i] + self.x[i + 1]) + +class Eno: + def __init__(self, mesh, iorder): + self.mesh = mesh + self.nx = mesh.nx + self.rk = 2 + self.iorder = iorder + self.ighost = iorder + self.ishift = self.ighost + 1 + self.ist = 0 + self.ishift + self.ied = self.nx - 1 + self.ishift + self.ntcell = self.nx + 2 * self.ishift + self.isize = iorder * (iorder + 1) + + self.il = np.zeros(self.nx + 1, dtype=int) + self.ir = np.zeros(self.nx + 1, dtype=int) + self.coef = np.zeros((iorder + 1, iorder)) + self.dd = np.zeros((iorder, self.ntcell)) + self.up1_2m = np.zeros(self.nx + 1) + self.up1_2p = np.zeros(self.nx + 1) + self.flux = np.zeros(self.nx + 1) + self.res = np.zeros(self.nx) + self.L = 2.0 + + # Field module variables + self.u = np.zeros(self.ntcell) + self.un = np.zeros(self.ntcell) + + self.c = 1.0 + self.T = 0.625 + self.dt = .0025 + +def plot_eno_field(xcc, u_list): + # 定义一个包含不同颜色、线形和标记的列表 + styles = [ + {'color': 'black', 'linestyle': '-', 'marker': 'o'}, + {'color': 'blue', 'linestyle': '--', 'marker': 's'}, + {'color': 'black', 'linestyle': '-', 'marker': '^'}, + {'color': 'blue', 'linestyle': '--', 'marker': 'v'}, + {'color': 'black', 'linestyle': '-', 'marker': '<'}, + {'color': 'blue', 'linestyle': '--', 'marker': '>'}, + {'color': 'black', 'linestyle': '-', 'marker': 'D'}, + ] + + n = len(u_list) + num_styles = len(styles) + + plt.figure("OneFLOW-CFD Solver", figsize=(10, 6)) + for i in range(0, n): + style = styles[i % num_styles] + plt.plot(xcc, u_list[i], marker=style['marker'], markerfacecolor='none', linestyle=style['linestyle'], color=style['color'], \ + markersize=5, linewidth=0.5, alpha=1.0, label=f'Numerical (Rusanov)') + plt.xlabel('x') + plt.ylabel('u') + plt.legend() + plt.grid(True, color='gray', linestyle='--', linewidth=0.5, alpha=0.7) + plt.tight_layout() + plt.show() + +def RunEno(mesh, iorder): + eno = Eno(mesh, iorder) + init_coef(eno.iorder, eno.coef) + init_field(eno) + + nt = int(eno.T / eno.dt) + simu_time = eno.T + + t = 0.0 + + while t < simu_time: + runge_kutta(eno) + t += eno.dt + if t + eno.dt > simu_time: + dt = simu_time - t + + print(t) + #visualize(eno) + return np.copy(eno.u[eno.ist:eno.ied+1]) + +def main(): + iorder_max = 7 + mesh = Mesh() + u_list = [] + for iorder in range(1, iorder_max+1): + u = RunEno(mesh, iorder) + u_list.append(u) + + plot_eno_field(mesh.xcc, u_list) + + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/example/1d-linear-convection/eno/rusanov/rk3/eno1-7/01f/plot.py b/example/1d-linear-convection/eno/rusanov/rk3/eno1-7/01f/plot.py new file mode 100644 index 00000000..e389044c --- /dev/null +++ b/example/1d-linear-convection/eno/rusanov/rk3/eno1-7/01f/plot.py @@ -0,0 +1,53 @@ +import numpy as np +import matplotlib.pyplot as plt +import csv +import sys + +nvar = len(sys.argv) +print('nvar=',nvar) +print('sys.argv=',sys.argv) + +order = 1 +if nvar >= 2: + var = sys.argv[1] + print('var=',var) + order = int(var) + +print('order=',order) + +x_list = [] +u_list = [] + +with open('solution.plt', newline='') as csvfile: + #readCSV = csv.reader(csvfile, delimiter= ' ') + icount = 0 + for line in csvfile: + # 去除首尾空格,按连续空格分割 + row = line.strip().split() + #print("row=",row) + x_list.append(row[0]) + u_list.append(row[1]) + icount += 1 + +ni = icount +print("ni=",ni) + +#print("x_list=",x_list) + +x = np.zeros( ni ) +u = np.zeros( ni ) + +for i in range(0, ni): + x[i] = float(x_list[i]) + u[i] = float(u_list[i]) + +labelname = 'Eno' + str(order) + +plt.figure("OneFLOW-CFD Solver", figsize=(8, 6), dpi=100) +plt.plot(x, u, "b-", linewidth=1.0, marker = 's', markerfacecolor='None', label=labelname) +plt.xlabel("$x$") +plt.ylabel("$u$") +plt.title("burgers T=1") +plt.legend() +plt.tight_layout() +plt.show(); \ No newline at end of file diff --git a/example/1d-linear-convection/eno/rusanov/rk3/eno1-7/01g/eno.py b/example/1d-linear-convection/eno/rusanov/rk3/eno1-7/01g/eno.py new file mode 100644 index 00000000..de500472 --- /dev/null +++ b/example/1d-linear-convection/eno/rusanov/rk3/eno1-7/01g/eno.py @@ -0,0 +1,354 @@ +import numpy as np +import matplotlib.pyplot as plt + +# 初始条件 +def initial_condition(x): + u0 = np.zeros_like(x) + for i in range(len(x)): + if 0.5 <= x[i] <= 1.0: + u0[i] = 2.0 + else: + u0[i] = 1.0 + return u0 + +# 理论解 +def analytical_solution(x, t, a, L): + # 初始条件沿 x - at 平移 + x_shifted = x - a * t + return initial_condition((x_shifted + L) % L) # 周期边界条件 + +def residual(q, eno): + reconstruction(q, eno) + inviscid_flux(eno.up1_2m, eno.up1_2p, eno.flux, eno) + for i in range(eno.nx): + eno.res[i] = -(eno.flux[i + 1] - eno.flux[i]) / eno.mesh.dx + +def reconstruction(q, eno): + # Choose the stencil by ENO method + eno.dd[0, 0:eno.ntcell-1] = q[0:eno.ntcell-1] + + for m in range(1, eno.iorder): + for j in range(0, eno.ntcell-1): + eno.dd[m, j] = eno.dd[m-1, j+1] - eno.dd[m-1, j] + + for i in range(eno.nx + 1): + eno.il[i] = i - 1 + for m in range(1, eno.iorder): + if abs(eno.dd[m, eno.il[i]-1+eno.ishift]) <= abs(eno.dd[m, eno.il[i]+eno.ishift]): + eno.il[i] -= 1 + + for i in range(eno.nx + 1): + eno.ir[i] = i + for m in range(1, eno.iorder): + if abs(eno.dd[m, eno.ir[i]-1+eno.ishift]) <= abs(eno.dd[m, eno.ir[i]+eno.ishift]): + eno.ir[i] -= 1 + + # Reconstruction u(j+1/2) + for i in range(eno.nx + 1): + k1 = eno.il[i] + k2 = eno.ir[i] + l1 = i - k1 + l2 = i - k2 + eno.up1_2m[i] = 0 + eno.up1_2p[i] = 0 + for m in range(eno.iorder): + eno.up1_2m[i] += q[k1 + eno.ishift + m] * eno.coef[l1, m] + eno.up1_2p[i] += q[k2 + eno.ishift + m] * eno.coef[l2, m] + +def inviscid_flux(up1_2m, up1_2p, flux, eno): + iflux = 0 + if iflux == 0: + rusanov_flux(up1_2m, up1_2p, flux, eno) + else: + engquist_osher_flux(up1_2m, up1_2p, flux, eno) + +def engquist_osher_flux(up1_2m, up1_2p, flux, eno): + for i in range(eno.nx + 1): + u_L = up1_2m[i] + u_R = up1_2p[i] + + cp = 0.5 * ( eno.c + abs(eno.c) ) + cm = 0.5 * ( eno.c - abs(eno.c) ) + + flux[i] = cp * uL + cm * u_R + +def rusanov_flux(up1_2m, up1_2p, flux, eno): + for i in range(eno.nx + 1): + u_L = up1_2m[i] + u_R = up1_2p[i] + F_L = eno.c * u_L # 左状态通量 + F_R = eno.c * u_R # 右状态通量 + alpha = abs(eno.c) # 最大波速 + flux[i] = 0.5 * (F_L + F_R) - 0.5 * alpha * (u_R - u_L) + + +def boundary(u, eno): + for i in range(-eno.ighost, 1): + u[eno.ist - 1 + i] = u[eno.ied + i] + for i in range(1, eno.ighost + 2): + u[eno.ied + i] = u[eno.ist - 1 + i] + +def update_oldfield(qn, q): + qn[:] = q[:] + +def init_coef( iorder, coef ): + if iorder == 1: + coef[0] = [1.0] + coef[1] = [1.0] + elif iorder == 2: + coef[0] = [3.0/2.0, -1.0/2.0] + coef[1] = [1.0/2.0, 1.0/2.0] + coef[2] = [-1.0/2.0, 3.0/2.0] + elif iorder == 3: + coef[0] = [ 11.0/6.0, -7.0/6.0, 1.0/3.0 ] + coef[1] = [ 1.0/3.0, 5.0/6.0, -1.0/6.0 ] + coef[2] = [ -1.0/6.0, 5.0/6.0, 1.0/3.0 ] + coef[3] = [ 1.0/3.0, -7.0/6.0, 11.0/6.0 ] + elif iorder == 4: + coef[0] = [ 25.0/12.0, -23.0/12.0, 13.0/12.0, -1.0/4.0 ] + coef[1] = [ 1.0/4.0, 13.0/12.0, -5.0/12.0, 1.0/12.0 ] + coef[2] = [ -1.0/12.0, 7.0/12.0, 7.0/12.0, -1.0/12.0 ] + coef[3] = [ 1.0/12.0, -5.0/12.0, 13.0/12.0, 1.0/4.0 ] + coef[4] = [ -1.0/4.0, 13.0/12.0, -23.0/12.0, 25.0/12.0 ] + elif iorder == 5: + coef[0] = [ 137.0/60.0, -163.0/60.0, 137.0/60.0, -21.0/20.0, 1.0/5.0 ] + coef[1] = [ 1.0/5.0, 77.0/60.0, -43.0/60.0, 17.0/60.0, -1.0/20.0 ] + coef[2] = [ -1.0/20.0, 9.0/20.0, 47.0/60.0, -13.0/60.0, 1.0/30.0 ] + coef[3] = [ 1.0/30.0, -13.0/60.0, 47.0/60.0, 9.0/20.0, -1.0/20.0 ] + coef[4] = [ -1.0/20.0, 17.0/60.0, -43.0/60.0, 77.0/60.0, 1.0/5.0 ] + coef[5] = [ 1.0/5.0, -21.0/20.0, 137.0/60.0, -163.0/60.0, 137.0/60.0 ] + elif iorder == 6: + coef[0] = [ 49.0/20.0, -71.0/20.0, 79.0/20.0, -163.0/60.0, 31.0/30.0, -1.0/6.0 ] + coef[1] = [ 1.0/6.0, 29.0/20.0, -21.0/20.0, 37.0/60.0, -13.0/60.0, 1.0/30.0 ] + coef[2] = [ -1.0/30.0, 11.0/30.0, 19.0/20.0, -23.0/60.0, 7.0/60.0, -1.0/60.0 ] + coef[3] = [ 1.0/60.0, -2.0/15.0, 37.0/60.0, 37.0/60.0, -2.0/15.0, 1.0/60.0 ] + coef[4] = [ -1.0/60.0, 7.0/60.0, -23.0/60.0, 19.0/20.0, 11.0/30.0, -1.0/30.0 ] + coef[5] = [ 1.0/30.0, -13.0/60.0, 37.0/60.0, -21.0/20.0, 29.0/20.0, 1.0/6.0 ] + coef[6] = [ -1.0/6.0, 31.0/30.0, -163.0/60.0, 79.0/20.0, -71.0/20.0, 49.0/20.0 ] + elif iorder == 7: + coef[0] = [ 363.0/140.0, -617.0/140.0, 853.0/140.0, -2341.0/420.0, 667.0/210.0, -43.0/42.0, 1.0/7.0 ] + coef[1] = [ 1.0/7.0, 223.0/140.0, -197.0/140.0, 153.0/140.0, -241.0/420.0, 37.0/210.0, -1.0/42.0 ] + coef[2] = [ -1.0/42.0, 13.0/42.0, 153.0/140.0, -241.0/420.0, 109.0/420.0, -31.0/420.0, 1.0/105.0 ] + coef[3] = [ 1.0/105.0, -19.0/210.0, 107.0/210.0, 319.0/420.0, -101.0/420.0, 5.0/84.0, -1.0/140.0 ] + coef[4] = [ -1.0/140.0, 5.0/84.0, -101.0/420.0, 319.0/420.0, 107.0/210.0, -19.0/210.0, 1.0/105.0 ] + coef[5] = [ 1.0/105.0, -31.0/420.0, 109.0/420.0, -241.0/420.0, 153.0/140.0, 13.0/42.0, -1.0/42.0 ] + coef[6] = [ -1.0/42.0, 37.0/210.0, -241.0/420.0, 153.0/140.0, -197.0/140.0, 223.0/140.0, 1.0/7.0 ] + coef[7] = [ 1.0/7.0, -43.0/42.0, 667.0/210.0, -2341.0/420.0, 853.0/140.0, -617.0/140.0, 363.0/140.0 ] + +def init_field(eno): + for i in range(eno.ist, eno.ied + 1): + j = i - eno.ist + if 0.5 <= eno.mesh.xcc[j] <= 1.0: + eno.u[i] = 2.0 + else: + eno.u[i] = 1.0 + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def runge_kutta(eno): + rk = eno.rk + if rk == 1: + runge_kutta_1(eno) + elif rk == 2: + runge_kutta_2(eno) + else: + runge_kutta_3(eno) + +def runge_kutta_1(eno): + residual(u, eno) + for i in range(nx): + j = i + ishift + u[j] = u[j] + dt * res[i] + boundary(u) + update_oldfield(un, u) + +def runge_kutta_2(eno): + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = eno.u[j] + eno.dt * eno.res[i] + boundary(eno.u, eno) + + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = 0.5 * eno.un[j] + 0.5 * eno.u[j] + 0.5 * eno.dt * eno.res[i] + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def runge_kutta_3(eno): + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = eno.u[j] + eno.dt * eno.res[i] + boundary(eno.u, eno) + + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = 0.75 * eno.un[j] + 0.25 * eno.u[j] + 0.25 * eno.dt * eno.res[i] + boundary(eno.u, eno) + + residual(eno.u, eno) + c1, c2, c3 = 1.0/3.0, 2.0/3.0, 2.0/3.0 + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = c1 * eno.un[j] + c2 * eno.u[j] + c3 * eno.dt * eno.res[i] + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def get_ordinal_numbers(order): + if order == 1: + return 'st' + elif order == 2: + return 'nd' + elif order == 3: + return 'rd' + else: + return 'th' + +def visualize(eno): + with open('solution.plt', 'w') as f: + for i in range(eno.ist, eno.ied + 1): + j = i - eno.ist + f.write(f"{eno.xcc[j]:20.10e}{eno.u[i]:20.10e}\n") + + # 可视化 + u_numerical = np.copy(eno.u[eno.ist:eno.ied+1]) + print(f'u_numerical.size={u_numerical.size}') + print(f'eno.xcc.size={eno.xcc.size}') + #计算理论解 + u_analytical = analytical_solution(eno.mesh.xcc, eno.T, eno.c, eno.L) + print(f'u_analytical.size={u_analytical.size}') + plt.figure("OneFLOW-CFD Solver", figsize=(10, 6)) + plt.scatter(eno.xcc, u_numerical, facecolor="none", edgecolor="blue", s=20, linewidths=0.5, label=f'Numerical (Rusanov)') + plt.plot(eno.xcc, u_analytical, 'r--', label='Analytical') + plt.xlabel('x') + plt.ylabel('u') + ordinal1 = get_ordinal_numbers(eno.iorder) + ordinal2 = get_ordinal_numbers(eno.rk) + plt.title(f'1D Convection Equation at t = {eno.T:.3f} using {eno.iorder}{ordinal1}-order ENO and {eno.rk}{ordinal2}-order Runge-Kutta methods') + plt.legend() + plt.grid(True, color='gray', linestyle='--', linewidth=0.5, alpha=0.7) + plt.tight_layout() + plt.show() + +class Mesh: + def __init__(self): + self.nx = 40 + self.L = 2.0 + self.x = np.zeros(self.nx + 1) + self.xcc = np.zeros(self.nx) + self.init_mesh() + def init_mesh(self): + xstart = 0.0 + xend = self.L + self.dx = (xend - xstart) / self.nx + + for i in range(0, self.nx+1): + self.x[i] = xstart + i * self.dx + + for i in range(0, self.nx): + self.xcc[i] = 0.5 * (self.x[i] + self.x[i + 1]) + +class Solver: + def __init__(self): + self.c = 1.0 + self.T = 0.625 + +class Eno: + def __init__(self, mesh, iorder): + self.mesh = mesh + self.nx = mesh.nx + self.rk = 2 + self.iorder = iorder + self.ighost = iorder + self.ishift = self.ighost + 1 + self.ist = 0 + self.ishift + self.ied = self.nx - 1 + self.ishift + self.ntcell = self.nx + 2 * self.ishift + self.isize = iorder * (iorder + 1) + + self.il = np.zeros(self.nx + 1, dtype=int) + self.ir = np.zeros(self.nx + 1, dtype=int) + self.coef = np.zeros((iorder + 1, iorder)) + self.dd = np.zeros((iorder, self.ntcell)) + self.up1_2m = np.zeros(self.nx + 1) + self.up1_2p = np.zeros(self.nx + 1) + self.flux = np.zeros(self.nx + 1) + self.res = np.zeros(self.nx) + self.L = 2.0 + + # Field module variables + self.u = np.zeros(self.ntcell) + self.un = np.zeros(self.ntcell) + + self.c = 1.0 + self.T = 0.625 + self.dt = .0025 + +def plot_eno_field(xcc, u_list, u_analytical): + # 定义一个包含不同颜色、线形和标记的列表 + styles = [ + {'color': 'black', 'linestyle': '-', 'marker': 'o'}, + {'color': 'blue', 'linestyle': '--', 'marker': 's'}, + {'color': 'black', 'linestyle': '-', 'marker': '^'}, + {'color': 'blue', 'linestyle': '--', 'marker': 'v'}, + {'color': 'black', 'linestyle': '-', 'marker': '<'}, + {'color': 'blue', 'linestyle': '--', 'marker': '>'}, + {'color': 'black', 'linestyle': '-', 'marker': 'D'}, + ] + + n = len(u_list) + num_styles = len(styles) + + plt.figure("OneFLOW-CFD Solver", figsize=(10, 6)) + for i in range(0, n): + style = styles[i % num_styles] + plt.plot(xcc, u_list[i], marker=style['marker'], markerfacecolor='none', linestyle=style['linestyle'], color=style['color'], \ + markersize=5, linewidth=0.5, alpha=1.0, label=f'Numerical (Rusanov)') + plt.plot(xcc, u_analytical, 'r--', label='Analytical') + plt.xlabel('x') + plt.ylabel('u') + plt.legend() + plt.grid(True, color='gray', linestyle='--', linewidth=0.5, alpha=0.7) + plt.tight_layout() + plt.show() + +def RunEno(mesh, iorder): + eno = Eno(mesh, iorder) + init_coef(eno.iorder, eno.coef) + init_field(eno) + + nt = int(eno.T / eno.dt) + simu_time = eno.T + + t = 0.0 + + while t < simu_time: + runge_kutta(eno) + t += eno.dt + if t + eno.dt > simu_time: + dt = simu_time - t + + print(t) + #visualize(eno) + return np.copy(eno.u[eno.ist:eno.ied+1]) + +def main(): + iorder_max = 7 + mesh = Mesh() + solver = Solver() + #计算理论解 + u_analytical = analytical_solution(mesh.xcc, solver.T, solver.c, mesh.L) + + u_list = [] + for iorder in range(1, iorder_max+1): + u = RunEno(mesh, iorder) + u_list.append(u) + + plot_eno_field(mesh.xcc, u_list, u_analytical) + + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/example/1d-linear-convection/eno/rusanov/rk3/eno1-7/01g/plot.py b/example/1d-linear-convection/eno/rusanov/rk3/eno1-7/01g/plot.py new file mode 100644 index 00000000..e389044c --- /dev/null +++ b/example/1d-linear-convection/eno/rusanov/rk3/eno1-7/01g/plot.py @@ -0,0 +1,53 @@ +import numpy as np +import matplotlib.pyplot as plt +import csv +import sys + +nvar = len(sys.argv) +print('nvar=',nvar) +print('sys.argv=',sys.argv) + +order = 1 +if nvar >= 2: + var = sys.argv[1] + print('var=',var) + order = int(var) + +print('order=',order) + +x_list = [] +u_list = [] + +with open('solution.plt', newline='') as csvfile: + #readCSV = csv.reader(csvfile, delimiter= ' ') + icount = 0 + for line in csvfile: + # 去除首尾空格,按连续空格分割 + row = line.strip().split() + #print("row=",row) + x_list.append(row[0]) + u_list.append(row[1]) + icount += 1 + +ni = icount +print("ni=",ni) + +#print("x_list=",x_list) + +x = np.zeros( ni ) +u = np.zeros( ni ) + +for i in range(0, ni): + x[i] = float(x_list[i]) + u[i] = float(u_list[i]) + +labelname = 'Eno' + str(order) + +plt.figure("OneFLOW-CFD Solver", figsize=(8, 6), dpi=100) +plt.plot(x, u, "b-", linewidth=1.0, marker = 's', markerfacecolor='None', label=labelname) +plt.xlabel("$x$") +plt.ylabel("$u$") +plt.title("burgers T=1") +plt.legend() +plt.tight_layout() +plt.show(); \ No newline at end of file diff --git a/example/1d-linear-convection/eno/rusanov/rk3/eno1-7/01h/eno.py b/example/1d-linear-convection/eno/rusanov/rk3/eno1-7/01h/eno.py new file mode 100644 index 00000000..a0bd66ba --- /dev/null +++ b/example/1d-linear-convection/eno/rusanov/rk3/eno1-7/01h/eno.py @@ -0,0 +1,352 @@ +import numpy as np +import matplotlib.pyplot as plt + +# 初始条件 +def initial_condition(x): + u0 = np.zeros_like(x) + for i in range(len(x)): + if 0.5 <= x[i] <= 1.0: + u0[i] = 2.0 + else: + u0[i] = 1.0 + return u0 + +# 理论解 +def analytical_solution(x, t, a, L): + # 初始条件沿 x - at 平移 + x_shifted = x - a * t + return initial_condition((x_shifted + L) % L) # 周期边界条件 + +def residual(q, eno): + reconstruction(q, eno) + inviscid_flux(eno.up1_2m, eno.up1_2p, eno.flux, eno) + for i in range(eno.nx): + eno.res[i] = -(eno.flux[i + 1] - eno.flux[i]) / eno.mesh.dx + +def reconstruction(q, eno): + # Choose the stencil by ENO method + eno.dd[0, 0:eno.ntcell-1] = q[0:eno.ntcell-1] + + for m in range(1, eno.iorder): + for j in range(0, eno.ntcell-1): + eno.dd[m, j] = eno.dd[m-1, j+1] - eno.dd[m-1, j] + + for i in range(eno.nx + 1): + eno.il[i] = i - 1 + for m in range(1, eno.iorder): + if abs(eno.dd[m, eno.il[i]-1+eno.ishift]) <= abs(eno.dd[m, eno.il[i]+eno.ishift]): + eno.il[i] -= 1 + + for i in range(eno.nx + 1): + eno.ir[i] = i + for m in range(1, eno.iorder): + if abs(eno.dd[m, eno.ir[i]-1+eno.ishift]) <= abs(eno.dd[m, eno.ir[i]+eno.ishift]): + eno.ir[i] -= 1 + + # Reconstruction u(j+1/2) + for i in range(eno.nx + 1): + k1 = eno.il[i] + k2 = eno.ir[i] + l1 = i - k1 + l2 = i - k2 + eno.up1_2m[i] = 0 + eno.up1_2p[i] = 0 + for m in range(eno.iorder): + eno.up1_2m[i] += q[k1 + eno.ishift + m] * eno.coef[l1, m] + eno.up1_2p[i] += q[k2 + eno.ishift + m] * eno.coef[l2, m] + +def inviscid_flux(up1_2m, up1_2p, flux, eno): + if eno.iflux == 0: + rusanov_flux(up1_2m, up1_2p, flux, eno) + else: + engquist_osher_flux(up1_2m, up1_2p, flux, eno) + +def engquist_osher_flux(up1_2m, up1_2p, flux, eno): + for i in range(eno.nx + 1): + u_L = up1_2m[i] + u_R = up1_2p[i] + + cp = 0.5 * ( eno.solver.c + abs(eno.solver.c) ) + cm = 0.5 * ( eno.solver.c - abs(eno.solver.c) ) + + flux[i] = cp * u_L + cm * u_R + +def rusanov_flux(up1_2m, up1_2p, flux, eno): + for i in range(eno.nx + 1): + u_L = up1_2m[i] + u_R = up1_2p[i] + F_L = eno.solver.c * u_L # 左状态通量 + F_R = eno.solver.c * u_R # 右状态通量 + alpha = abs(eno.solver.c) # 最大波速 + flux[i] = 0.5 * (F_L + F_R) - 0.5 * alpha * (u_R - u_L) + + +def boundary(u, eno): + for i in range(-eno.ighost, 1): + u[eno.ist - 1 + i] = u[eno.ied + i] + for i in range(1, eno.ighost + 2): + u[eno.ied + i] = u[eno.ist - 1 + i] + +def update_oldfield(qn, q): + qn[:] = q[:] + +def init_coef( iorder, coef ): + if iorder == 1: + coef[0] = [1.0] + coef[1] = [1.0] + elif iorder == 2: + coef[0] = [3.0/2.0, -1.0/2.0] + coef[1] = [1.0/2.0, 1.0/2.0] + coef[2] = [-1.0/2.0, 3.0/2.0] + elif iorder == 3: + coef[0] = [ 11.0/6.0, -7.0/6.0, 1.0/3.0 ] + coef[1] = [ 1.0/3.0, 5.0/6.0, -1.0/6.0 ] + coef[2] = [ -1.0/6.0, 5.0/6.0, 1.0/3.0 ] + coef[3] = [ 1.0/3.0, -7.0/6.0, 11.0/6.0 ] + elif iorder == 4: + coef[0] = [ 25.0/12.0, -23.0/12.0, 13.0/12.0, -1.0/4.0 ] + coef[1] = [ 1.0/4.0, 13.0/12.0, -5.0/12.0, 1.0/12.0 ] + coef[2] = [ -1.0/12.0, 7.0/12.0, 7.0/12.0, -1.0/12.0 ] + coef[3] = [ 1.0/12.0, -5.0/12.0, 13.0/12.0, 1.0/4.0 ] + coef[4] = [ -1.0/4.0, 13.0/12.0, -23.0/12.0, 25.0/12.0 ] + elif iorder == 5: + coef[0] = [ 137.0/60.0, -163.0/60.0, 137.0/60.0, -21.0/20.0, 1.0/5.0 ] + coef[1] = [ 1.0/5.0, 77.0/60.0, -43.0/60.0, 17.0/60.0, -1.0/20.0 ] + coef[2] = [ -1.0/20.0, 9.0/20.0, 47.0/60.0, -13.0/60.0, 1.0/30.0 ] + coef[3] = [ 1.0/30.0, -13.0/60.0, 47.0/60.0, 9.0/20.0, -1.0/20.0 ] + coef[4] = [ -1.0/20.0, 17.0/60.0, -43.0/60.0, 77.0/60.0, 1.0/5.0 ] + coef[5] = [ 1.0/5.0, -21.0/20.0, 137.0/60.0, -163.0/60.0, 137.0/60.0 ] + elif iorder == 6: + coef[0] = [ 49.0/20.0, -71.0/20.0, 79.0/20.0, -163.0/60.0, 31.0/30.0, -1.0/6.0 ] + coef[1] = [ 1.0/6.0, 29.0/20.0, -21.0/20.0, 37.0/60.0, -13.0/60.0, 1.0/30.0 ] + coef[2] = [ -1.0/30.0, 11.0/30.0, 19.0/20.0, -23.0/60.0, 7.0/60.0, -1.0/60.0 ] + coef[3] = [ 1.0/60.0, -2.0/15.0, 37.0/60.0, 37.0/60.0, -2.0/15.0, 1.0/60.0 ] + coef[4] = [ -1.0/60.0, 7.0/60.0, -23.0/60.0, 19.0/20.0, 11.0/30.0, -1.0/30.0 ] + coef[5] = [ 1.0/30.0, -13.0/60.0, 37.0/60.0, -21.0/20.0, 29.0/20.0, 1.0/6.0 ] + coef[6] = [ -1.0/6.0, 31.0/30.0, -163.0/60.0, 79.0/20.0, -71.0/20.0, 49.0/20.0 ] + elif iorder == 7: + coef[0] = [ 363.0/140.0, -617.0/140.0, 853.0/140.0, -2341.0/420.0, 667.0/210.0, -43.0/42.0, 1.0/7.0 ] + coef[1] = [ 1.0/7.0, 223.0/140.0, -197.0/140.0, 153.0/140.0, -241.0/420.0, 37.0/210.0, -1.0/42.0 ] + coef[2] = [ -1.0/42.0, 13.0/42.0, 153.0/140.0, -241.0/420.0, 109.0/420.0, -31.0/420.0, 1.0/105.0 ] + coef[3] = [ 1.0/105.0, -19.0/210.0, 107.0/210.0, 319.0/420.0, -101.0/420.0, 5.0/84.0, -1.0/140.0 ] + coef[4] = [ -1.0/140.0, 5.0/84.0, -101.0/420.0, 319.0/420.0, 107.0/210.0, -19.0/210.0, 1.0/105.0 ] + coef[5] = [ 1.0/105.0, -31.0/420.0, 109.0/420.0, -241.0/420.0, 153.0/140.0, 13.0/42.0, -1.0/42.0 ] + coef[6] = [ -1.0/42.0, 37.0/210.0, -241.0/420.0, 153.0/140.0, -197.0/140.0, 223.0/140.0, 1.0/7.0 ] + coef[7] = [ 1.0/7.0, -43.0/42.0, 667.0/210.0, -2341.0/420.0, 853.0/140.0, -617.0/140.0, 363.0/140.0 ] + +def init_field(eno): + for i in range(eno.ist, eno.ied + 1): + j = i - eno.ist + if 0.5 <= eno.mesh.xcc[j] <= 1.0: + eno.u[i] = 2.0 + else: + eno.u[i] = 1.0 + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def runge_kutta(eno): + rk = eno.rk + if rk == 1: + runge_kutta_1(eno) + elif rk == 2: + runge_kutta_2(eno) + else: + runge_kutta_3(eno) + +def runge_kutta_1(eno): + residual(u, eno) + for i in range(nx): + j = i + ishift + u[j] = u[j] + dt * res[i] + boundary(u) + update_oldfield(un, u) + +def runge_kutta_2(eno): + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = eno.u[j] + eno.dt * eno.res[i] + boundary(eno.u, eno) + + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = 0.5 * eno.un[j] + 0.5 * eno.u[j] + 0.5 * eno.dt * eno.res[i] + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def runge_kutta_3(eno): + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = eno.u[j] + eno.dt * eno.res[i] + boundary(eno.u, eno) + + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = 0.75 * eno.un[j] + 0.25 * eno.u[j] + 0.25 * eno.dt * eno.res[i] + boundary(eno.u, eno) + + residual(eno.u, eno) + c1, c2, c3 = 1.0/3.0, 2.0/3.0, 2.0/3.0 + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = c1 * eno.un[j] + c2 * eno.u[j] + c3 * eno.dt * eno.res[i] + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def get_ordinal_numbers(order): + if order == 1: + return 'st' + elif order == 2: + return 'nd' + elif order == 3: + return 'rd' + else: + return 'th' + +def visualize(eno): + with open('solution.plt', 'w') as f: + for i in range(eno.ist, eno.ied + 1): + j = i - eno.ist + f.write(f"{eno.xcc[j]:20.10e}{eno.u[i]:20.10e}\n") + + # 可视化 + u_numerical = np.copy(eno.u[eno.ist:eno.ied+1]) + print(f'u_numerical.size={u_numerical.size}') + print(f'eno.xcc.size={eno.xcc.size}') + #计算理论解 + u_analytical = analytical_solution(eno.mesh.xcc, eno.T, eno.c, eno.L) + print(f'u_analytical.size={u_analytical.size}') + plt.figure("OneFLOW-CFD Solver", figsize=(10, 6)) + plt.scatter(eno.xcc, u_numerical, facecolor="none", edgecolor="blue", s=20, linewidths=0.5, label=f'Numerical (Rusanov)') + plt.plot(eno.xcc, u_analytical, 'r--', label='Analytical') + plt.xlabel('x') + plt.ylabel('u') + ordinal1 = get_ordinal_numbers(eno.iorder) + ordinal2 = get_ordinal_numbers(eno.rk) + plt.title(f'1D Convection Equation at t = {eno.T:.3f} using {eno.iorder}{ordinal1}-order ENO and {eno.rk}{ordinal2}-order Runge-Kutta methods') + plt.legend() + plt.grid(True, color='gray', linestyle='--', linewidth=0.5, alpha=0.7) + plt.tight_layout() + plt.show() + +class Mesh: + def __init__(self): + self.nx = 40 + self.L = 2.0 + self.x = np.zeros(self.nx + 1) + self.xcc = np.zeros(self.nx) + self.init_mesh() + def init_mesh(self): + xstart = 0.0 + xend = self.L + self.dx = (xend - xstart) / self.nx + + for i in range(0, self.nx+1): + self.x[i] = xstart + i * self.dx + + for i in range(0, self.nx): + self.xcc[i] = 0.5 * (self.x[i] + self.x[i + 1]) + +class Solver: + def __init__(self): + self.c = 1.0 + self.T = 0.625 + +class Eno: + def __init__(self, solver, mesh, iorder): + self.solver = solver + self.mesh = mesh + self.nx = mesh.nx + self.rk = 2 + self.iflux = 0 + self.iorder = iorder + self.ighost = iorder + self.ishift = self.ighost + 1 + self.ist = 0 + self.ishift + self.ied = self.nx - 1 + self.ishift + self.ntcell = self.nx + 2 * self.ishift + self.isize = iorder * (iorder + 1) + + self.il = np.zeros(self.nx + 1, dtype=int) + self.ir = np.zeros(self.nx + 1, dtype=int) + self.coef = np.zeros((iorder + 1, iorder)) + self.dd = np.zeros((iorder, self.ntcell)) + self.up1_2m = np.zeros(self.nx + 1) + self.up1_2p = np.zeros(self.nx + 1) + self.flux = np.zeros(self.nx + 1) + self.res = np.zeros(self.nx) + self.L = 2.0 + + # Field module variables + self.u = np.zeros(self.ntcell) + self.un = np.zeros(self.ntcell) + + self.dt = .0025 + +def plot_eno_field(xcc, u_list, u_analytical): + # 定义一个包含不同颜色、线形和标记的列表 + styles = [ + {'color': 'black', 'linestyle': '-', 'marker': 'o'}, + {'color': 'blue', 'linestyle': '--', 'marker': 's'}, + {'color': 'black', 'linestyle': '-', 'marker': '^'}, + {'color': 'blue', 'linestyle': '--', 'marker': 'v'}, + {'color': 'black', 'linestyle': '-', 'marker': '<'}, + {'color': 'blue', 'linestyle': '--', 'marker': '>'}, + {'color': 'black', 'linestyle': '-', 'marker': 'D'}, + ] + + n = len(u_list) + num_styles = len(styles) + + plt.figure("OneFLOW-CFD Solver", figsize=(10, 6)) + for i in range(0, n): + lable = 'Numerical (Rusanov)ENO' + str(i+1) + style = styles[i % num_styles] + plt.plot(xcc, u_list[i], marker=style['marker'], markerfacecolor='none', linestyle=style['linestyle'], color=style['color'], \ + markersize=5, linewidth=0.5, alpha=1.0, label=f'{lable}') + plt.plot(xcc, u_analytical, 'r--', label='Analytical') + plt.xlabel('x') + plt.ylabel('u') + plt.legend() + plt.grid(True, color='gray', linestyle='--', linewidth=0.5, alpha=0.7) + plt.tight_layout() + plt.show() + +def RunEno(solver, mesh, iorder): + eno = Eno(solver, mesh, iorder) + init_coef(eno.iorder, eno.coef) + init_field(eno) + + simu_time = solver.T + t = 0.0 + + while t < simu_time: + runge_kutta(eno) + t += eno.dt + if t + eno.dt > simu_time: + dt = simu_time - t + + print(t) + #visualize(eno) + return np.copy(eno.u[eno.ist:eno.ied+1]) + +def main(): + iorder_max = 7 + mesh = Mesh() + solver = Solver() + #计算理论解 + u_analytical = analytical_solution(mesh.xcc, solver.T, solver.c, mesh.L) + + u_list = [] + for iorder in range(1, iorder_max+1): + u = RunEno(solver, mesh, iorder) + u_list.append(u) + + plot_eno_field(mesh.xcc, u_list, u_analytical) + + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/example/1d-linear-convection/eno/rusanov/rk3/eno1-7/01h/plot.py b/example/1d-linear-convection/eno/rusanov/rk3/eno1-7/01h/plot.py new file mode 100644 index 00000000..e389044c --- /dev/null +++ b/example/1d-linear-convection/eno/rusanov/rk3/eno1-7/01h/plot.py @@ -0,0 +1,53 @@ +import numpy as np +import matplotlib.pyplot as plt +import csv +import sys + +nvar = len(sys.argv) +print('nvar=',nvar) +print('sys.argv=',sys.argv) + +order = 1 +if nvar >= 2: + var = sys.argv[1] + print('var=',var) + order = int(var) + +print('order=',order) + +x_list = [] +u_list = [] + +with open('solution.plt', newline='') as csvfile: + #readCSV = csv.reader(csvfile, delimiter= ' ') + icount = 0 + for line in csvfile: + # 去除首尾空格,按连续空格分割 + row = line.strip().split() + #print("row=",row) + x_list.append(row[0]) + u_list.append(row[1]) + icount += 1 + +ni = icount +print("ni=",ni) + +#print("x_list=",x_list) + +x = np.zeros( ni ) +u = np.zeros( ni ) + +for i in range(0, ni): + x[i] = float(x_list[i]) + u[i] = float(u_list[i]) + +labelname = 'Eno' + str(order) + +plt.figure("OneFLOW-CFD Solver", figsize=(8, 6), dpi=100) +plt.plot(x, u, "b-", linewidth=1.0, marker = 's', markerfacecolor='None', label=labelname) +plt.xlabel("$x$") +plt.ylabel("$u$") +plt.title("burgers T=1") +plt.legend() +plt.tight_layout() +plt.show(); \ No newline at end of file diff --git a/example/1d-linear-convection/eno/rusanov/rk3/eno1-7/02/eno.py b/example/1d-linear-convection/eno/rusanov/rk3/eno1-7/02/eno.py new file mode 100644 index 00000000..4c46a5b8 --- /dev/null +++ b/example/1d-linear-convection/eno/rusanov/rk3/eno1-7/02/eno.py @@ -0,0 +1,357 @@ +import numpy as np +import matplotlib.pyplot as plt + +# 初始条件 +def initial_condition(x): + u0 = np.zeros_like(x) + for i in range(len(x)): + if 0.5 <= x[i] <= 1.0: + u0[i] = 2.0 + else: + u0[i] = 1.0 + return u0 + +# 理论解 +def analytical_solution(x, t, a, L): + # 初始条件沿 x - at 平移 + x_shifted = x - a * t + return initial_condition((x_shifted + L) % L) # 周期边界条件 + +def residual(q, eno): + reconstruction(q, eno) + inviscid_flux(eno.up1_2m, eno.up1_2p, eno.flux, eno) + for i in range(eno.nx): + eno.res[i] = -(eno.flux[i + 1] - eno.flux[i]) / eno.mesh.dx + +def reconstruction(q, eno): + # Choose the stencil by ENO method + eno.dd[0, 0:eno.ntcell-1] = q[0:eno.ntcell-1] + + for m in range(1, eno.iorder): + for j in range(0, eno.ntcell-1): + eno.dd[m, j] = eno.dd[m-1, j+1] - eno.dd[m-1, j] + + for i in range(eno.nx + 1): + eno.il[i] = i - 1 + for m in range(1, eno.iorder): + if abs(eno.dd[m, eno.il[i]-1+eno.ishift]) <= abs(eno.dd[m, eno.il[i]+eno.ishift]): + eno.il[i] -= 1 + + for i in range(eno.nx + 1): + eno.ir[i] = i + for m in range(1, eno.iorder): + if abs(eno.dd[m, eno.ir[i]-1+eno.ishift]) <= abs(eno.dd[m, eno.ir[i]+eno.ishift]): + eno.ir[i] -= 1 + + # Reconstruction u(j+1/2) + for i in range(eno.nx + 1): + k1 = eno.il[i] + k2 = eno.ir[i] + l1 = i - k1 + l2 = i - k2 + eno.up1_2m[i] = 0 + eno.up1_2p[i] = 0 + for m in range(eno.iorder): + eno.up1_2m[i] += q[k1 + eno.ishift + m] * eno.coef[l1, m] + eno.up1_2p[i] += q[k2 + eno.ishift + m] * eno.coef[l2, m] + +fluxnames = [ + 'Rusanov', + 'Engquist-Osher', +] + +def inviscid_flux(up1_2m, up1_2p, flux, eno): + if eno.solver.iflux == 0: + rusanov_flux(up1_2m, up1_2p, flux, eno) + else: + engquist_osher_flux(up1_2m, up1_2p, flux, eno) + +def engquist_osher_flux(up1_2m, up1_2p, flux, eno): + for i in range(eno.nx + 1): + u_L = up1_2m[i] + u_R = up1_2p[i] + + cp = 0.5 * ( eno.solver.c + abs(eno.solver.c) ) + cm = 0.5 * ( eno.solver.c - abs(eno.solver.c) ) + + flux[i] = cp * u_L + cm * u_R + +def rusanov_flux(up1_2m, up1_2p, flux, eno): + for i in range(eno.nx + 1): + u_L = up1_2m[i] + u_R = up1_2p[i] + F_L = eno.solver.c * u_L # 左状态通量 + F_R = eno.solver.c * u_R # 右状态通量 + alpha = abs(eno.solver.c) # 最大波速 + flux[i] = 0.5 * (F_L + F_R) - 0.5 * alpha * (u_R - u_L) + + +def boundary(u, eno): + for i in range(-eno.ighost, 1): + u[eno.ist - 1 + i] = u[eno.ied + i] + for i in range(1, eno.ighost + 2): + u[eno.ied + i] = u[eno.ist - 1 + i] + +def update_oldfield(qn, q): + qn[:] = q[:] + +def init_coef( iorder, coef ): + if iorder == 1: + coef[0] = [1.0] + coef[1] = [1.0] + elif iorder == 2: + coef[0] = [3.0/2.0, -1.0/2.0] + coef[1] = [1.0/2.0, 1.0/2.0] + coef[2] = [-1.0/2.0, 3.0/2.0] + elif iorder == 3: + coef[0] = [ 11.0/6.0, -7.0/6.0, 1.0/3.0 ] + coef[1] = [ 1.0/3.0, 5.0/6.0, -1.0/6.0 ] + coef[2] = [ -1.0/6.0, 5.0/6.0, 1.0/3.0 ] + coef[3] = [ 1.0/3.0, -7.0/6.0, 11.0/6.0 ] + elif iorder == 4: + coef[0] = [ 25.0/12.0, -23.0/12.0, 13.0/12.0, -1.0/4.0 ] + coef[1] = [ 1.0/4.0, 13.0/12.0, -5.0/12.0, 1.0/12.0 ] + coef[2] = [ -1.0/12.0, 7.0/12.0, 7.0/12.0, -1.0/12.0 ] + coef[3] = [ 1.0/12.0, -5.0/12.0, 13.0/12.0, 1.0/4.0 ] + coef[4] = [ -1.0/4.0, 13.0/12.0, -23.0/12.0, 25.0/12.0 ] + elif iorder == 5: + coef[0] = [ 137.0/60.0, -163.0/60.0, 137.0/60.0, -21.0/20.0, 1.0/5.0 ] + coef[1] = [ 1.0/5.0, 77.0/60.0, -43.0/60.0, 17.0/60.0, -1.0/20.0 ] + coef[2] = [ -1.0/20.0, 9.0/20.0, 47.0/60.0, -13.0/60.0, 1.0/30.0 ] + coef[3] = [ 1.0/30.0, -13.0/60.0, 47.0/60.0, 9.0/20.0, -1.0/20.0 ] + coef[4] = [ -1.0/20.0, 17.0/60.0, -43.0/60.0, 77.0/60.0, 1.0/5.0 ] + coef[5] = [ 1.0/5.0, -21.0/20.0, 137.0/60.0, -163.0/60.0, 137.0/60.0 ] + elif iorder == 6: + coef[0] = [ 49.0/20.0, -71.0/20.0, 79.0/20.0, -163.0/60.0, 31.0/30.0, -1.0/6.0 ] + coef[1] = [ 1.0/6.0, 29.0/20.0, -21.0/20.0, 37.0/60.0, -13.0/60.0, 1.0/30.0 ] + coef[2] = [ -1.0/30.0, 11.0/30.0, 19.0/20.0, -23.0/60.0, 7.0/60.0, -1.0/60.0 ] + coef[3] = [ 1.0/60.0, -2.0/15.0, 37.0/60.0, 37.0/60.0, -2.0/15.0, 1.0/60.0 ] + coef[4] = [ -1.0/60.0, 7.0/60.0, -23.0/60.0, 19.0/20.0, 11.0/30.0, -1.0/30.0 ] + coef[5] = [ 1.0/30.0, -13.0/60.0, 37.0/60.0, -21.0/20.0, 29.0/20.0, 1.0/6.0 ] + coef[6] = [ -1.0/6.0, 31.0/30.0, -163.0/60.0, 79.0/20.0, -71.0/20.0, 49.0/20.0 ] + elif iorder == 7: + coef[0] = [ 363.0/140.0, -617.0/140.0, 853.0/140.0, -2341.0/420.0, 667.0/210.0, -43.0/42.0, 1.0/7.0 ] + coef[1] = [ 1.0/7.0, 223.0/140.0, -197.0/140.0, 153.0/140.0, -241.0/420.0, 37.0/210.0, -1.0/42.0 ] + coef[2] = [ -1.0/42.0, 13.0/42.0, 153.0/140.0, -241.0/420.0, 109.0/420.0, -31.0/420.0, 1.0/105.0 ] + coef[3] = [ 1.0/105.0, -19.0/210.0, 107.0/210.0, 319.0/420.0, -101.0/420.0, 5.0/84.0, -1.0/140.0 ] + coef[4] = [ -1.0/140.0, 5.0/84.0, -101.0/420.0, 319.0/420.0, 107.0/210.0, -19.0/210.0, 1.0/105.0 ] + coef[5] = [ 1.0/105.0, -31.0/420.0, 109.0/420.0, -241.0/420.0, 153.0/140.0, 13.0/42.0, -1.0/42.0 ] + coef[6] = [ -1.0/42.0, 37.0/210.0, -241.0/420.0, 153.0/140.0, -197.0/140.0, 223.0/140.0, 1.0/7.0 ] + coef[7] = [ 1.0/7.0, -43.0/42.0, 667.0/210.0, -2341.0/420.0, 853.0/140.0, -617.0/140.0, 363.0/140.0 ] + +def init_field(eno): + for i in range(eno.ist, eno.ied + 1): + j = i - eno.ist + if 0.5 <= eno.mesh.xcc[j] <= 1.0: + eno.u[i] = 2.0 + else: + eno.u[i] = 1.0 + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def runge_kutta(eno): + rk = eno.solver.rk + if rk == 1: + runge_kutta_1(eno) + elif rk == 2: + runge_kutta_2(eno) + else: + runge_kutta_3(eno) + +def runge_kutta_1(eno): + residual(u, eno) + for i in range(nx): + j = i + ishift + u[j] = u[j] + dt * res[i] + boundary(u) + update_oldfield(un, u) + +def runge_kutta_2(eno): + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = eno.u[j] + eno.dt * eno.res[i] + boundary(eno.u, eno) + + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = 0.5 * eno.un[j] + 0.5 * eno.u[j] + 0.5 * eno.dt * eno.res[i] + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def runge_kutta_3(eno): + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = eno.u[j] + eno.dt * eno.res[i] + boundary(eno.u, eno) + + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = 0.75 * eno.un[j] + 0.25 * eno.u[j] + 0.25 * eno.dt * eno.res[i] + boundary(eno.u, eno) + + residual(eno.u, eno) + c1, c2, c3 = 1.0/3.0, 2.0/3.0, 2.0/3.0 + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = c1 * eno.un[j] + c2 * eno.u[j] + c3 * eno.dt * eno.res[i] + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def get_ordinal_numbers(order): + if order == 1: + return 'st' + elif order == 2: + return 'nd' + elif order == 3: + return 'rd' + else: + return 'th' + +def visualize(eno): + with open('solution.plt', 'w') as f: + for i in range(eno.ist, eno.ied + 1): + j = i - eno.ist + f.write(f"{eno.xcc[j]:20.10e}{eno.u[i]:20.10e}\n") + + # 可视化 + u_numerical = np.copy(eno.u[eno.ist:eno.ied+1]) + print(f'u_numerical.size={u_numerical.size}') + print(f'eno.xcc.size={eno.xcc.size}') + #计算理论解 + u_analytical = analytical_solution(eno.mesh.xcc, eno.T, eno.c, eno.L) + print(f'u_analytical.size={u_analytical.size}') + plt.figure("OneFLOW-CFD Solver", figsize=(10, 6)) + plt.scatter(eno.xcc, u_numerical, facecolor="none", edgecolor="blue", s=20, linewidths=0.5, label=f'Numerical (Rusanov)') + plt.plot(eno.xcc, u_analytical, 'r--', label='Analytical') + plt.xlabel('x') + plt.ylabel('u') + ordinal1 = get_ordinal_numbers(eno.iorder) + ordinal2 = get_ordinal_numbers(eno.rk) + plt.title(f'1D Convection Equation at t = {eno.T:.3f} using {eno.iorder}{ordinal1}-order ENO and {eno.rk}{ordinal2}-order Runge-Kutta methods') + plt.legend() + plt.grid(True, color='gray', linestyle='--', linewidth=0.5, alpha=0.7) + plt.tight_layout() + plt.show() + +class Mesh: + def __init__(self): + self.nx = 40 + self.L = 2.0 + self.x = np.zeros(self.nx + 1) + self.xcc = np.zeros(self.nx) + self.init_mesh() + def init_mesh(self): + xstart = 0.0 + xend = self.L + self.dx = (xend - xstart) / self.nx + + for i in range(0, self.nx+1): + self.x[i] = xstart + i * self.dx + + for i in range(0, self.nx): + self.xcc[i] = 0.5 * (self.x[i] + self.x[i + 1]) + +class Solver: + def __init__(self): + self.iflux = 0 + self.rk = 3 + self.c = 1.0 + self.T = 0.625 + +class Eno: + def __init__(self, solver, mesh, iorder): + self.solver = solver + self.mesh = mesh + self.nx = mesh.nx + self.iorder = iorder + self.ighost = iorder + self.ishift = self.ighost + 1 + self.ist = 0 + self.ishift + self.ied = self.nx - 1 + self.ishift + self.ntcell = self.nx + 2 * self.ishift + self.isize = iorder * (iorder + 1) + + self.il = np.zeros(self.nx + 1, dtype=int) + self.ir = np.zeros(self.nx + 1, dtype=int) + self.coef = np.zeros((iorder + 1, iorder)) + self.dd = np.zeros((iorder, self.ntcell)) + self.up1_2m = np.zeros(self.nx + 1) + self.up1_2p = np.zeros(self.nx + 1) + self.flux = np.zeros(self.nx + 1) + self.res = np.zeros(self.nx) + + # Field module variables + self.u = np.zeros(self.ntcell) + self.un = np.zeros(self.ntcell) + + self.dt = .0025 + +def plot_eno_field(solver, xcc, u_list, u_analytical): + # 定义一个包含不同颜色、线形和标记的列表 + styles = [ + {'color': 'black', 'linestyle': '-', 'marker': 'o'}, + {'color': 'blue', 'linestyle': '--', 'marker': 's'}, + {'color': 'black', 'linestyle': '-', 'marker': '^'}, + {'color': 'blue', 'linestyle': '--', 'marker': 'v'}, + {'color': 'black', 'linestyle': '-', 'marker': '<'}, + {'color': 'blue', 'linestyle': '--', 'marker': '>'}, + {'color': 'black', 'linestyle': '-', 'marker': 'D'}, + ] + + n = len(u_list) + num_styles = len(styles) + ordinal = get_ordinal_numbers(solver.rk) + + plt.figure("OneFLOW-CFD Solver", figsize=(10, 6)) + plt.title(f'1D Convection Equation at t = {solver.T:.3f} using [1-7]th-order ENO and {solver.rk}{ordinal}-order Runge-Kutta methods') + for i in range(0, n): + lable = 'Numerical (Rusanov)ENO' + str(i+1) + style = styles[i % num_styles] + plt.plot(xcc, u_list[i], marker=style['marker'], markerfacecolor='none', linestyle=style['linestyle'], color=style['color'], \ + markersize=5, linewidth=0.5, alpha=1.0, label=f'{lable}') + plt.plot(xcc, u_analytical, 'r--', label='Analytical') + plt.xlabel('x') + plt.ylabel('u') + plt.legend() + plt.grid(True, color='gray', linestyle='--', linewidth=0.5, alpha=0.7) + plt.tight_layout() + plt.show() + +def RunEno(solver, mesh, iorder): + eno = Eno(solver, mesh, iorder) + init_coef(eno.iorder, eno.coef) + init_field(eno) + + simu_time = solver.T + t = 0.0 + dt = eno.dt + while t < simu_time: + runge_kutta(eno) + if t + dt > simu_time: + dt = simu_time - t + t += dt + print(f'T={t:.3f},runge_kutta{solver.rk},ENO{eno.iorder},{fluxnames[solver.iflux]} FLUX') + #visualize(eno) + return np.copy(eno.u[eno.ist:eno.ied+1]) + +def main(): + iorder_max = 7 + mesh = Mesh() + solver = Solver() + #计算理论解 + u_analytical = analytical_solution(mesh.xcc, solver.T, solver.c, mesh.L) + + u_list = [] + for iorder in range(1, iorder_max+1): + u = RunEno(solver, mesh, iorder) + u_list.append(u) + + plot_eno_field(solver, mesh.xcc, u_list, u_analytical) + + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/example/1d-linear-convection/eno/rusanov/rk3/eno1-7/02/plot.py b/example/1d-linear-convection/eno/rusanov/rk3/eno1-7/02/plot.py new file mode 100644 index 00000000..e389044c --- /dev/null +++ b/example/1d-linear-convection/eno/rusanov/rk3/eno1-7/02/plot.py @@ -0,0 +1,53 @@ +import numpy as np +import matplotlib.pyplot as plt +import csv +import sys + +nvar = len(sys.argv) +print('nvar=',nvar) +print('sys.argv=',sys.argv) + +order = 1 +if nvar >= 2: + var = sys.argv[1] + print('var=',var) + order = int(var) + +print('order=',order) + +x_list = [] +u_list = [] + +with open('solution.plt', newline='') as csvfile: + #readCSV = csv.reader(csvfile, delimiter= ' ') + icount = 0 + for line in csvfile: + # 去除首尾空格,按连续空格分割 + row = line.strip().split() + #print("row=",row) + x_list.append(row[0]) + u_list.append(row[1]) + icount += 1 + +ni = icount +print("ni=",ni) + +#print("x_list=",x_list) + +x = np.zeros( ni ) +u = np.zeros( ni ) + +for i in range(0, ni): + x[i] = float(x_list[i]) + u[i] = float(u_list[i]) + +labelname = 'Eno' + str(order) + +plt.figure("OneFLOW-CFD Solver", figsize=(8, 6), dpi=100) +plt.plot(x, u, "b-", linewidth=1.0, marker = 's', markerfacecolor='None', label=labelname) +plt.xlabel("$x$") +plt.ylabel("$u$") +plt.title("burgers T=1") +plt.legend() +plt.tight_layout() +plt.show(); \ No newline at end of file diff --git a/example/1d-linear-convection/eno/rusanov/timestep/rk1-eno/eno1/01/eno.py b/example/1d-linear-convection/eno/rusanov/timestep/rk1-eno/eno1/01/eno.py new file mode 100644 index 00000000..310b1ed0 --- /dev/null +++ b/example/1d-linear-convection/eno/rusanov/timestep/rk1-eno/eno1/01/eno.py @@ -0,0 +1,426 @@ +import numpy as np +import matplotlib.pyplot as plt + +# 初始条件 +def initial_condition(x): + u0 = np.zeros_like(x) + for i in range(len(x)): + if 0.5 <= x[i] <= 1.0: + u0[i] = 2.0 + else: + u0[i] = 1.0 + return u0 + +# 理论解 +def analytical_solution(x, t, a, L): + # 初始条件沿 x - at 平移 + x_shifted = x - a * t + return initial_condition((x_shifted + L) % L) # 周期边界条件 + +def residual(q, eno): + reconstruction(q, eno) + inviscid_flux(eno.up1_2m, eno.up1_2p, eno.flux, eno) + for i in range(eno.nx): + eno.res[i] = -(eno.flux[i + 1] - eno.flux[i]) / eno.mesh.dx + +def reconstruction(q, eno): + # Choose the stencil by ENO method + eno.dd[0, 0:eno.ntcell-1] = q[0:eno.ntcell-1] + + for m in range(1, eno.iorder): + for j in range(0, eno.ntcell-1): + eno.dd[m, j] = eno.dd[m-1, j+1] - eno.dd[m-1, j] + + for i in range(eno.nx + 1): + eno.il[i] = i - 1 + for m in range(1, eno.iorder): + if abs(eno.dd[m, eno.il[i]-1+eno.ishift]) <= abs(eno.dd[m, eno.il[i]+eno.ishift]): + eno.il[i] -= 1 + + for i in range(eno.nx + 1): + eno.ir[i] = i + for m in range(1, eno.iorder): + if abs(eno.dd[m, eno.ir[i]-1+eno.ishift]) <= abs(eno.dd[m, eno.ir[i]+eno.ishift]): + eno.ir[i] -= 1 + + # Reconstruction u(j+1/2) + for i in range(eno.nx + 1): + k1 = eno.il[i] + k2 = eno.ir[i] + l1 = i - k1 + l2 = i - k2 + eno.up1_2m[i] = 0 + eno.up1_2p[i] = 0 + for m in range(eno.iorder): + eno.up1_2m[i] += q[k1 + eno.ishift + m] * eno.coef[l1, m] + eno.up1_2p[i] += q[k2 + eno.ishift + m] * eno.coef[l2, m] + +fluxnames = [ + 'Rusanov', + 'Engquist-Osher', +] + +def inviscid_flux(up1_2m, up1_2p, flux, eno): + if eno.solver.iflux == 0: + rusanov_flux(up1_2m, up1_2p, flux, eno) + else: + engquist_osher_flux(up1_2m, up1_2p, flux, eno) + +def engquist_osher_flux(up1_2m, up1_2p, flux, eno): + for i in range(eno.nx + 1): + u_L = up1_2m[i] + u_R = up1_2p[i] + + cp = 0.5 * ( eno.solver.c + abs(eno.solver.c) ) + cm = 0.5 * ( eno.solver.c - abs(eno.solver.c) ) + + flux[i] = cp * u_L + cm * u_R + +def rusanov_flux(up1_2m, up1_2p, flux, eno): + for i in range(eno.nx + 1): + u_L = up1_2m[i] + u_R = up1_2p[i] + F_L = eno.solver.c * u_L # 左状态通量 + F_R = eno.solver.c * u_R # 右状态通量 + alpha = abs(eno.solver.c) # 最大波速 + flux[i] = 0.5 * (F_L + F_R) - 0.5 * alpha * (u_R - u_L) + + +def boundary(u, eno): + for i in range(-eno.ighost, 1): + u[eno.ist - 1 + i] = u[eno.ied + i] + for i in range(1, eno.ighost + 2): + u[eno.ied + i] = u[eno.ist - 1 + i] + +def update_oldfield(qn, q): + qn[:] = q[:] + +def init_coef( iorder, coef ): + if iorder == 1: + coef[0] = [1.0] + coef[1] = [1.0] + elif iorder == 2: + coef[0] = [3.0/2.0, -1.0/2.0] + coef[1] = [1.0/2.0, 1.0/2.0] + coef[2] = [-1.0/2.0, 3.0/2.0] + elif iorder == 3: + coef[0] = [ 11.0/6.0, -7.0/6.0, 1.0/3.0 ] + coef[1] = [ 1.0/3.0, 5.0/6.0, -1.0/6.0 ] + coef[2] = [ -1.0/6.0, 5.0/6.0, 1.0/3.0 ] + coef[3] = [ 1.0/3.0, -7.0/6.0, 11.0/6.0 ] + elif iorder == 4: + coef[0] = [ 25.0/12.0, -23.0/12.0, 13.0/12.0, -1.0/4.0 ] + coef[1] = [ 1.0/4.0, 13.0/12.0, -5.0/12.0, 1.0/12.0 ] + coef[2] = [ -1.0/12.0, 7.0/12.0, 7.0/12.0, -1.0/12.0 ] + coef[3] = [ 1.0/12.0, -5.0/12.0, 13.0/12.0, 1.0/4.0 ] + coef[4] = [ -1.0/4.0, 13.0/12.0, -23.0/12.0, 25.0/12.0 ] + elif iorder == 5: + coef[0] = [ 137.0/60.0, -163.0/60.0, 137.0/60.0, -21.0/20.0, 1.0/5.0 ] + coef[1] = [ 1.0/5.0, 77.0/60.0, -43.0/60.0, 17.0/60.0, -1.0/20.0 ] + coef[2] = [ -1.0/20.0, 9.0/20.0, 47.0/60.0, -13.0/60.0, 1.0/30.0 ] + coef[3] = [ 1.0/30.0, -13.0/60.0, 47.0/60.0, 9.0/20.0, -1.0/20.0 ] + coef[4] = [ -1.0/20.0, 17.0/60.0, -43.0/60.0, 77.0/60.0, 1.0/5.0 ] + coef[5] = [ 1.0/5.0, -21.0/20.0, 137.0/60.0, -163.0/60.0, 137.0/60.0 ] + elif iorder == 6: + coef[0] = [ 49.0/20.0, -71.0/20.0, 79.0/20.0, -163.0/60.0, 31.0/30.0, -1.0/6.0 ] + coef[1] = [ 1.0/6.0, 29.0/20.0, -21.0/20.0, 37.0/60.0, -13.0/60.0, 1.0/30.0 ] + coef[2] = [ -1.0/30.0, 11.0/30.0, 19.0/20.0, -23.0/60.0, 7.0/60.0, -1.0/60.0 ] + coef[3] = [ 1.0/60.0, -2.0/15.0, 37.0/60.0, 37.0/60.0, -2.0/15.0, 1.0/60.0 ] + coef[4] = [ -1.0/60.0, 7.0/60.0, -23.0/60.0, 19.0/20.0, 11.0/30.0, -1.0/30.0 ] + coef[5] = [ 1.0/30.0, -13.0/60.0, 37.0/60.0, -21.0/20.0, 29.0/20.0, 1.0/6.0 ] + coef[6] = [ -1.0/6.0, 31.0/30.0, -163.0/60.0, 79.0/20.0, -71.0/20.0, 49.0/20.0 ] + elif iorder == 7: + coef[0] = [ 363.0/140.0, -617.0/140.0, 853.0/140.0, -2341.0/420.0, 667.0/210.0, -43.0/42.0, 1.0/7.0 ] + coef[1] = [ 1.0/7.0, 223.0/140.0, -197.0/140.0, 153.0/140.0, -241.0/420.0, 37.0/210.0, -1.0/42.0 ] + coef[2] = [ -1.0/42.0, 13.0/42.0, 153.0/140.0, -241.0/420.0, 109.0/420.0, -31.0/420.0, 1.0/105.0 ] + coef[3] = [ 1.0/105.0, -19.0/210.0, 107.0/210.0, 319.0/420.0, -101.0/420.0, 5.0/84.0, -1.0/140.0 ] + coef[4] = [ -1.0/140.0, 5.0/84.0, -101.0/420.0, 319.0/420.0, 107.0/210.0, -19.0/210.0, 1.0/105.0 ] + coef[5] = [ 1.0/105.0, -31.0/420.0, 109.0/420.0, -241.0/420.0, 153.0/140.0, 13.0/42.0, -1.0/42.0 ] + coef[6] = [ -1.0/42.0, 37.0/210.0, -241.0/420.0, 153.0/140.0, -197.0/140.0, 223.0/140.0, 1.0/7.0 ] + coef[7] = [ 1.0/7.0, -43.0/42.0, 667.0/210.0, -2341.0/420.0, 853.0/140.0, -617.0/140.0, 363.0/140.0 ] + +def init_field(eno): + for i in range(eno.ist, eno.ied + 1): + j = i - eno.ist + if 0.5 <= eno.mesh.xcc[j] <= 1.0: + eno.u[i] = 2.0 + else: + eno.u[i] = 1.0 + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def runge_kutta(eno): + rk = eno.solver.rk + if rk == 1: + runge_kutta_1(eno) + elif rk == 2: + runge_kutta_2(eno) + else: + runge_kutta_3(eno) + +def runge_kutta_1(eno): + dt = eno.solver.dt + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = eno.u[j] + dt * eno.res[i] + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def runge_kutta_2(eno): + dt = eno.solver.dt + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = eno.u[j] + dt * eno.res[i] + boundary(eno.u, eno) + + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = 0.5 * eno.un[j] + 0.5 * eno.u[j] + 0.5 * dt * eno.res[i] + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def runge_kutta_3(eno): + dt = eno.solver.dt + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = eno.u[j] + dt * eno.res[i] + boundary(eno.u, eno) + + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = 0.75 * eno.un[j] + 0.25 * eno.u[j] + 0.25 * dt * eno.res[i] + boundary(eno.u, eno) + + residual(eno.u, eno) + c1, c2, c3 = 1.0/3.0, 2.0/3.0, 2.0/3.0 + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = c1 * eno.un[j] + c2 * eno.u[j] + c3 * dt * eno.res[i] + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def get_ordinal_numbers(order): + if order == 1: + return 'st' + elif order == 2: + return 'nd' + elif order == 3: + return 'rd' + else: + return 'th' + +def visualize(eno): + with open('solution.plt', 'w') as f: + for i in range(eno.ist, eno.ied + 1): + j = i - eno.ist + f.write(f"{eno.xcc[j]:20.10e}{eno.u[i]:20.10e}\n") + + # 可视化 + u_numerical = np.copy(eno.u[eno.ist:eno.ied+1]) + print(f'u_numerical.size={u_numerical.size}') + print(f'eno.xcc.size={eno.xcc.size}') + #计算理论解 + u_analytical = analytical_solution(eno.mesh.xcc, eno.T, eno.c, eno.L) + print(f'u_analytical.size={u_analytical.size}') + plt.figure("OneFLOW-CFD Solver", figsize=(10, 6)) + plt.scatter(eno.xcc, u_numerical, facecolor="none", edgecolor="blue", s=20, linewidths=0.5, label=f'Numerical (Rusanov)') + plt.plot(eno.xcc, u_analytical, 'r--', label='Analytical') + plt.xlabel('x') + plt.ylabel('u') + ordinal1 = get_ordinal_numbers(eno.iorder) + ordinal2 = get_ordinal_numbers(eno.rk) + plt.title(f'1D Convection Equation at t = {eno.T:.3f} using {eno.iorder}{ordinal1}-order ENO and {eno.rk}{ordinal2}-order Runge-Kutta methods') + plt.legend() + plt.grid(True, color='gray', linestyle='--', linewidth=0.5, alpha=0.7) + plt.tight_layout() + plt.show() + +class Mesh: + def __init__(self): + self.nx = 40 + self.L = 2.0 + self.x = np.zeros(self.nx + 1) + self.xcc = np.zeros(self.nx) + self.init_mesh() + def init_mesh(self): + xstart = 0.0 + xend = self.L + self.dx = (xend - xstart) / self.nx + + for i in range(0, self.nx+1): + self.x[i] = xstart + i * self.dx + + for i in range(0, self.nx): + self.xcc[i] = 0.5 * (self.x[i] + self.x[i + 1]) + +class Solver: + def __init__(self): + self.iflux = 0 + self.rk = 1 + self.c = 1.0 + self.T = 0.625 + self.dt = .0025 + +class Eno: + def __init__(self, solver, mesh, iorder): + self.solver = solver + self.mesh = mesh + self.nx = mesh.nx + self.iorder = iorder + self.ighost = iorder + self.ishift = self.ighost + 1 + self.ist = 0 + self.ishift + self.ied = self.nx - 1 + self.ishift + self.ntcell = self.nx + 2 * self.ishift + self.isize = iorder * (iorder + 1) + + self.il = np.zeros(self.nx + 1, dtype=int) + self.ir = np.zeros(self.nx + 1, dtype=int) + self.coef = np.zeros((iorder + 1, iorder)) + self.dd = np.zeros((iorder, self.ntcell)) + self.up1_2m = np.zeros(self.nx + 1) + self.up1_2p = np.zeros(self.nx + 1) + self.flux = np.zeros(self.nx + 1) + self.res = np.zeros(self.nx) + + # Field module variables + self.u = np.zeros(self.ntcell) + self.un = np.zeros(self.ntcell) + + #self.dt = .0025 + +def plot_eno_OrderAnalysis(solver, xcc, u_list, u_analytical): + # 定义一个包含不同颜色、线形和标记的列表 + styles = [ + {'color': 'black', 'linestyle': '-', 'marker': 'o'}, + {'color': 'blue', 'linestyle': '--', 'marker': 's'}, + {'color': 'black', 'linestyle': '-', 'marker': '^'}, + {'color': 'blue', 'linestyle': '--', 'marker': 'v'}, + {'color': 'black', 'linestyle': '-', 'marker': '<'}, + {'color': 'blue', 'linestyle': '--', 'marker': '>'}, + {'color': 'black', 'linestyle': '-', 'marker': 'D'}, + ] + + n = len(u_list) + num_styles = len(styles) + ordinal = get_ordinal_numbers(solver.rk) + + plt.figure("OneFLOW-CFD Solver", figsize=(10, 6)) + plt.title(f'1D Convection Equation at t = {solver.T:.3f} using [1-7]th-order ENO and {solver.rk}{ordinal}-order Runge-Kutta methods') + for i in range(0, n): + lable = 'Numerical (Rusanov)ENO' + str(i+1) + style = styles[i % num_styles] + plt.plot(xcc, u_list[i], marker=style['marker'], markerfacecolor='none', linestyle=style['linestyle'], color=style['color'], \ + markersize=5, linewidth=0.5, alpha=1.0, label=f'{lable}') + plt.plot(xcc, u_analytical, 'r--', label='Analytical') + plt.xlabel('x') + plt.ylabel('u') + plt.legend() + plt.grid(True, color='gray', linestyle='--', linewidth=0.5, alpha=0.7) + plt.tight_layout() + plt.show() + +def plot_eno_TimestepAnalysis(solver, xcc, u_list, u_analytical, dt_list, iorder): + # 定义一个包含不同颜色、线形和标记的列表 + styles = [ + {'color': 'black', 'linestyle': '-', 'marker': 'o'}, + {'color': 'blue', 'linestyle': '--', 'marker': 's'}, + {'color': 'black', 'linestyle': '-', 'marker': '^'}, + {'color': 'blue', 'linestyle': '--', 'marker': 'v'}, + {'color': 'black', 'linestyle': '-', 'marker': '<'}, + {'color': 'blue', 'linestyle': '--', 'marker': '>'}, + {'color': 'black', 'linestyle': '-', 'marker': 'D'}, + {'color': 'blue', 'linestyle': '--', 'marker': 'o'}, + {'color': 'black', 'linestyle': '-', 'marker': 's'}, + {'color': 'blue', 'linestyle': '--', 'marker': '^'}, + {'color': 'black', 'linestyle': '-', 'marker': 'v'}, + {'color': 'blue', 'linestyle': '--', 'marker': '<'}, + {'color': 'black', 'linestyle': '-', 'marker': '>'}, + {'color': 'blue', 'linestyle': '--', 'marker': 'D'}, + ] + + n = len(u_list) + num_styles = len(styles) + + ordinalENO = get_ordinal_numbers(iorder) + ordinalRK = get_ordinal_numbers(solver.rk) + + plt.figure("OneFLOW-CFD Solver", figsize=(10, 6)) + plt.title(f'1D Convection Equation at t = {solver.T:.3f} using {iorder}{ordinalENO}-order ENO and {solver.rk}{ordinalRK}-order Runge-Kutta methods') + for i in range(0, n): + lable = 'Numerical (Rusanov)ENO' + str(iorder) + ' T='+str(dt_list[i]) + style = styles[i % num_styles] + plt.plot(xcc, u_list[i], marker=style['marker'], markerfacecolor='none', linestyle=style['linestyle'], color=style['color'], \ + markersize=5, linewidth=1.0, alpha=1.0, label=f'{lable}') + plt.plot(xcc, u_analytical, 'r--', label='Analytical') + plt.xlabel('x') + plt.ylabel('u') + plt.legend() + plt.grid(True, color='gray', linestyle='--', linewidth=0.5, alpha=0.7) + plt.tight_layout() + plt.show() + +def RunEno(solver, mesh, iorder): + eno = Eno(solver, mesh, iorder) + init_coef(eno.iorder, eno.coef) + init_field(eno) + + simu_time = solver.T + t = 0.0 + dt = solver.dt + while t < simu_time: + runge_kutta(eno) + if t + dt > simu_time: + dt = simu_time - t + t += dt + #print(f'T={t:.3f},runge_kutta{solver.rk},ENO{eno.iorder},{fluxnames[solver.iflux]} FLUX') + #visualize(eno) + return np.copy(eno.u[eno.ist:eno.ied+1]) + +def performEnoOrderAnalysis(): + iorder_max = 7 + mesh = Mesh() + solver = Solver() + #计算理论解 + u_analytical = analytical_solution(mesh.xcc, solver.T, solver.c, mesh.L) + + u_list = [] + for iorder in range(1, iorder_max+1): + u = RunEno(solver, mesh, iorder) + u_list.append(u) + + plot_eno_OrderAnalysis(solver, mesh.xcc, u_list, u_analytical) + +def performEnoTimestepAnalysis(): + mesh = Mesh() + solver = Solver() + #计算理论解 + u_analytical = analytical_solution(mesh.xcc, solver.T, solver.c, mesh.L) + + u_list = [] + dt_list = [] + solver.dt = 0.025 + #solver.dt = 0.025/16 + n = 12 + solver.rk = 1 + iorder = 1 + for i in range(0, n): + u = RunEno(solver, mesh, iorder) + u_list.append(u) + dt_list.append(solver.dt) + print(f'i={i+1},N={n},T={solver.T:.3f},dt={solver.dt},nt={int(solver.T/solver.dt)},runge_kutta{solver.rk},ENO{iorder},{fluxnames[solver.iflux]} FLUX') + solver.dt /= 2 + + plot_eno_TimestepAnalysis(solver, mesh.xcc, u_list, u_analytical, dt_list, iorder) + +def main(): + #performEnoOrderAnalysis() + performEnoTimestepAnalysis() + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/example/1d-linear-convection/eno/rusanov/timestep/rk1-eno/eno1/01/plot.py b/example/1d-linear-convection/eno/rusanov/timestep/rk1-eno/eno1/01/plot.py new file mode 100644 index 00000000..e389044c --- /dev/null +++ b/example/1d-linear-convection/eno/rusanov/timestep/rk1-eno/eno1/01/plot.py @@ -0,0 +1,53 @@ +import numpy as np +import matplotlib.pyplot as plt +import csv +import sys + +nvar = len(sys.argv) +print('nvar=',nvar) +print('sys.argv=',sys.argv) + +order = 1 +if nvar >= 2: + var = sys.argv[1] + print('var=',var) + order = int(var) + +print('order=',order) + +x_list = [] +u_list = [] + +with open('solution.plt', newline='') as csvfile: + #readCSV = csv.reader(csvfile, delimiter= ' ') + icount = 0 + for line in csvfile: + # 去除首尾空格,按连续空格分割 + row = line.strip().split() + #print("row=",row) + x_list.append(row[0]) + u_list.append(row[1]) + icount += 1 + +ni = icount +print("ni=",ni) + +#print("x_list=",x_list) + +x = np.zeros( ni ) +u = np.zeros( ni ) + +for i in range(0, ni): + x[i] = float(x_list[i]) + u[i] = float(u_list[i]) + +labelname = 'Eno' + str(order) + +plt.figure("OneFLOW-CFD Solver", figsize=(8, 6), dpi=100) +plt.plot(x, u, "b-", linewidth=1.0, marker = 's', markerfacecolor='None', label=labelname) +plt.xlabel("$x$") +plt.ylabel("$u$") +plt.title("burgers T=1") +plt.legend() +plt.tight_layout() +plt.show(); \ No newline at end of file diff --git a/example/1d-linear-convection/eno/rusanov/timestep/rk1-eno/eno2/01/eno.py b/example/1d-linear-convection/eno/rusanov/timestep/rk1-eno/eno2/01/eno.py new file mode 100644 index 00000000..0f55e28d --- /dev/null +++ b/example/1d-linear-convection/eno/rusanov/timestep/rk1-eno/eno2/01/eno.py @@ -0,0 +1,426 @@ +import numpy as np +import matplotlib.pyplot as plt + +# 初始条件 +def initial_condition(x): + u0 = np.zeros_like(x) + for i in range(len(x)): + if 0.5 <= x[i] <= 1.0: + u0[i] = 2.0 + else: + u0[i] = 1.0 + return u0 + +# 理论解 +def analytical_solution(x, t, a, L): + # 初始条件沿 x - at 平移 + x_shifted = x - a * t + return initial_condition((x_shifted + L) % L) # 周期边界条件 + +def residual(q, eno): + reconstruction(q, eno) + inviscid_flux(eno.up1_2m, eno.up1_2p, eno.flux, eno) + for i in range(eno.nx): + eno.res[i] = -(eno.flux[i + 1] - eno.flux[i]) / eno.mesh.dx + +def reconstruction(q, eno): + # Choose the stencil by ENO method + eno.dd[0, 0:eno.ntcell-1] = q[0:eno.ntcell-1] + + for m in range(1, eno.iorder): + for j in range(0, eno.ntcell-1): + eno.dd[m, j] = eno.dd[m-1, j+1] - eno.dd[m-1, j] + + for i in range(eno.nx + 1): + eno.il[i] = i - 1 + for m in range(1, eno.iorder): + if abs(eno.dd[m, eno.il[i]-1+eno.ishift]) <= abs(eno.dd[m, eno.il[i]+eno.ishift]): + eno.il[i] -= 1 + + for i in range(eno.nx + 1): + eno.ir[i] = i + for m in range(1, eno.iorder): + if abs(eno.dd[m, eno.ir[i]-1+eno.ishift]) <= abs(eno.dd[m, eno.ir[i]+eno.ishift]): + eno.ir[i] -= 1 + + # Reconstruction u(j+1/2) + for i in range(eno.nx + 1): + k1 = eno.il[i] + k2 = eno.ir[i] + l1 = i - k1 + l2 = i - k2 + eno.up1_2m[i] = 0 + eno.up1_2p[i] = 0 + for m in range(eno.iorder): + eno.up1_2m[i] += q[k1 + eno.ishift + m] * eno.coef[l1, m] + eno.up1_2p[i] += q[k2 + eno.ishift + m] * eno.coef[l2, m] + +fluxnames = [ + 'Rusanov', + 'Engquist-Osher', +] + +def inviscid_flux(up1_2m, up1_2p, flux, eno): + if eno.solver.iflux == 0: + rusanov_flux(up1_2m, up1_2p, flux, eno) + else: + engquist_osher_flux(up1_2m, up1_2p, flux, eno) + +def engquist_osher_flux(up1_2m, up1_2p, flux, eno): + for i in range(eno.nx + 1): + u_L = up1_2m[i] + u_R = up1_2p[i] + + cp = 0.5 * ( eno.solver.c + abs(eno.solver.c) ) + cm = 0.5 * ( eno.solver.c - abs(eno.solver.c) ) + + flux[i] = cp * u_L + cm * u_R + +def rusanov_flux(up1_2m, up1_2p, flux, eno): + for i in range(eno.nx + 1): + u_L = up1_2m[i] + u_R = up1_2p[i] + F_L = eno.solver.c * u_L # 左状态通量 + F_R = eno.solver.c * u_R # 右状态通量 + alpha = abs(eno.solver.c) # 最大波速 + flux[i] = 0.5 * (F_L + F_R) - 0.5 * alpha * (u_R - u_L) + + +def boundary(u, eno): + for i in range(-eno.ighost, 1): + u[eno.ist - 1 + i] = u[eno.ied + i] + for i in range(1, eno.ighost + 2): + u[eno.ied + i] = u[eno.ist - 1 + i] + +def update_oldfield(qn, q): + qn[:] = q[:] + +def init_coef( iorder, coef ): + if iorder == 1: + coef[0] = [1.0] + coef[1] = [1.0] + elif iorder == 2: + coef[0] = [3.0/2.0, -1.0/2.0] + coef[1] = [1.0/2.0, 1.0/2.0] + coef[2] = [-1.0/2.0, 3.0/2.0] + elif iorder == 3: + coef[0] = [ 11.0/6.0, -7.0/6.0, 1.0/3.0 ] + coef[1] = [ 1.0/3.0, 5.0/6.0, -1.0/6.0 ] + coef[2] = [ -1.0/6.0, 5.0/6.0, 1.0/3.0 ] + coef[3] = [ 1.0/3.0, -7.0/6.0, 11.0/6.0 ] + elif iorder == 4: + coef[0] = [ 25.0/12.0, -23.0/12.0, 13.0/12.0, -1.0/4.0 ] + coef[1] = [ 1.0/4.0, 13.0/12.0, -5.0/12.0, 1.0/12.0 ] + coef[2] = [ -1.0/12.0, 7.0/12.0, 7.0/12.0, -1.0/12.0 ] + coef[3] = [ 1.0/12.0, -5.0/12.0, 13.0/12.0, 1.0/4.0 ] + coef[4] = [ -1.0/4.0, 13.0/12.0, -23.0/12.0, 25.0/12.0 ] + elif iorder == 5: + coef[0] = [ 137.0/60.0, -163.0/60.0, 137.0/60.0, -21.0/20.0, 1.0/5.0 ] + coef[1] = [ 1.0/5.0, 77.0/60.0, -43.0/60.0, 17.0/60.0, -1.0/20.0 ] + coef[2] = [ -1.0/20.0, 9.0/20.0, 47.0/60.0, -13.0/60.0, 1.0/30.0 ] + coef[3] = [ 1.0/30.0, -13.0/60.0, 47.0/60.0, 9.0/20.0, -1.0/20.0 ] + coef[4] = [ -1.0/20.0, 17.0/60.0, -43.0/60.0, 77.0/60.0, 1.0/5.0 ] + coef[5] = [ 1.0/5.0, -21.0/20.0, 137.0/60.0, -163.0/60.0, 137.0/60.0 ] + elif iorder == 6: + coef[0] = [ 49.0/20.0, -71.0/20.0, 79.0/20.0, -163.0/60.0, 31.0/30.0, -1.0/6.0 ] + coef[1] = [ 1.0/6.0, 29.0/20.0, -21.0/20.0, 37.0/60.0, -13.0/60.0, 1.0/30.0 ] + coef[2] = [ -1.0/30.0, 11.0/30.0, 19.0/20.0, -23.0/60.0, 7.0/60.0, -1.0/60.0 ] + coef[3] = [ 1.0/60.0, -2.0/15.0, 37.0/60.0, 37.0/60.0, -2.0/15.0, 1.0/60.0 ] + coef[4] = [ -1.0/60.0, 7.0/60.0, -23.0/60.0, 19.0/20.0, 11.0/30.0, -1.0/30.0 ] + coef[5] = [ 1.0/30.0, -13.0/60.0, 37.0/60.0, -21.0/20.0, 29.0/20.0, 1.0/6.0 ] + coef[6] = [ -1.0/6.0, 31.0/30.0, -163.0/60.0, 79.0/20.0, -71.0/20.0, 49.0/20.0 ] + elif iorder == 7: + coef[0] = [ 363.0/140.0, -617.0/140.0, 853.0/140.0, -2341.0/420.0, 667.0/210.0, -43.0/42.0, 1.0/7.0 ] + coef[1] = [ 1.0/7.0, 223.0/140.0, -197.0/140.0, 153.0/140.0, -241.0/420.0, 37.0/210.0, -1.0/42.0 ] + coef[2] = [ -1.0/42.0, 13.0/42.0, 153.0/140.0, -241.0/420.0, 109.0/420.0, -31.0/420.0, 1.0/105.0 ] + coef[3] = [ 1.0/105.0, -19.0/210.0, 107.0/210.0, 319.0/420.0, -101.0/420.0, 5.0/84.0, -1.0/140.0 ] + coef[4] = [ -1.0/140.0, 5.0/84.0, -101.0/420.0, 319.0/420.0, 107.0/210.0, -19.0/210.0, 1.0/105.0 ] + coef[5] = [ 1.0/105.0, -31.0/420.0, 109.0/420.0, -241.0/420.0, 153.0/140.0, 13.0/42.0, -1.0/42.0 ] + coef[6] = [ -1.0/42.0, 37.0/210.0, -241.0/420.0, 153.0/140.0, -197.0/140.0, 223.0/140.0, 1.0/7.0 ] + coef[7] = [ 1.0/7.0, -43.0/42.0, 667.0/210.0, -2341.0/420.0, 853.0/140.0, -617.0/140.0, 363.0/140.0 ] + +def init_field(eno): + for i in range(eno.ist, eno.ied + 1): + j = i - eno.ist + if 0.5 <= eno.mesh.xcc[j] <= 1.0: + eno.u[i] = 2.0 + else: + eno.u[i] = 1.0 + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def runge_kutta(eno): + rk = eno.solver.rk + if rk == 1: + runge_kutta_1(eno) + elif rk == 2: + runge_kutta_2(eno) + else: + runge_kutta_3(eno) + +def runge_kutta_1(eno): + dt = eno.solver.dt + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = eno.u[j] + dt * eno.res[i] + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def runge_kutta_2(eno): + dt = eno.solver.dt + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = eno.u[j] + dt * eno.res[i] + boundary(eno.u, eno) + + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = 0.5 * eno.un[j] + 0.5 * eno.u[j] + 0.5 * dt * eno.res[i] + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def runge_kutta_3(eno): + dt = eno.solver.dt + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = eno.u[j] + dt * eno.res[i] + boundary(eno.u, eno) + + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = 0.75 * eno.un[j] + 0.25 * eno.u[j] + 0.25 * dt * eno.res[i] + boundary(eno.u, eno) + + residual(eno.u, eno) + c1, c2, c3 = 1.0/3.0, 2.0/3.0, 2.0/3.0 + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = c1 * eno.un[j] + c2 * eno.u[j] + c3 * dt * eno.res[i] + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def get_ordinal_numbers(order): + if order == 1: + return 'st' + elif order == 2: + return 'nd' + elif order == 3: + return 'rd' + else: + return 'th' + +def visualize(eno): + with open('solution.plt', 'w') as f: + for i in range(eno.ist, eno.ied + 1): + j = i - eno.ist + f.write(f"{eno.xcc[j]:20.10e}{eno.u[i]:20.10e}\n") + + # 可视化 + u_numerical = np.copy(eno.u[eno.ist:eno.ied+1]) + print(f'u_numerical.size={u_numerical.size}') + print(f'eno.xcc.size={eno.xcc.size}') + #计算理论解 + u_analytical = analytical_solution(eno.mesh.xcc, eno.T, eno.c, eno.L) + print(f'u_analytical.size={u_analytical.size}') + plt.figure("OneFLOW-CFD Solver", figsize=(10, 6)) + plt.scatter(eno.xcc, u_numerical, facecolor="none", edgecolor="blue", s=20, linewidths=0.5, label=f'Numerical (Rusanov)') + plt.plot(eno.xcc, u_analytical, 'r--', label='Analytical') + plt.xlabel('x') + plt.ylabel('u') + ordinal1 = get_ordinal_numbers(eno.iorder) + ordinal2 = get_ordinal_numbers(eno.rk) + plt.title(f'1D Convection Equation at t = {eno.T:.3f} using {eno.iorder}{ordinal1}-order ENO and {eno.rk}{ordinal2}-order Runge-Kutta methods') + plt.legend() + plt.grid(True, color='gray', linestyle='--', linewidth=0.5, alpha=0.7) + plt.tight_layout() + plt.show() + +class Mesh: + def __init__(self): + self.nx = 40 + self.L = 2.0 + self.x = np.zeros(self.nx + 1) + self.xcc = np.zeros(self.nx) + self.init_mesh() + def init_mesh(self): + xstart = 0.0 + xend = self.L + self.dx = (xend - xstart) / self.nx + + for i in range(0, self.nx+1): + self.x[i] = xstart + i * self.dx + + for i in range(0, self.nx): + self.xcc[i] = 0.5 * (self.x[i] + self.x[i + 1]) + +class Solver: + def __init__(self): + self.iflux = 0 + self.rk = 1 + self.c = 1.0 + self.T = 0.625 + self.dt = .0025 + +class Eno: + def __init__(self, solver, mesh, iorder): + self.solver = solver + self.mesh = mesh + self.nx = mesh.nx + self.iorder = iorder + self.ighost = iorder + self.ishift = self.ighost + 1 + self.ist = 0 + self.ishift + self.ied = self.nx - 1 + self.ishift + self.ntcell = self.nx + 2 * self.ishift + self.isize = iorder * (iorder + 1) + + self.il = np.zeros(self.nx + 1, dtype=int) + self.ir = np.zeros(self.nx + 1, dtype=int) + self.coef = np.zeros((iorder + 1, iorder)) + self.dd = np.zeros((iorder, self.ntcell)) + self.up1_2m = np.zeros(self.nx + 1) + self.up1_2p = np.zeros(self.nx + 1) + self.flux = np.zeros(self.nx + 1) + self.res = np.zeros(self.nx) + + # Field module variables + self.u = np.zeros(self.ntcell) + self.un = np.zeros(self.ntcell) + + #self.dt = .0025 + +def plot_eno_OrderAnalysis(solver, xcc, u_list, u_analytical): + # 定义一个包含不同颜色、线形和标记的列表 + styles = [ + {'color': 'black', 'linestyle': '-', 'marker': 'o'}, + {'color': 'blue', 'linestyle': '--', 'marker': 's'}, + {'color': 'black', 'linestyle': '-', 'marker': '^'}, + {'color': 'blue', 'linestyle': '--', 'marker': 'v'}, + {'color': 'black', 'linestyle': '-', 'marker': '<'}, + {'color': 'blue', 'linestyle': '--', 'marker': '>'}, + {'color': 'black', 'linestyle': '-', 'marker': 'D'}, + ] + + n = len(u_list) + num_styles = len(styles) + ordinal = get_ordinal_numbers(solver.rk) + + plt.figure("OneFLOW-CFD Solver", figsize=(10, 6)) + plt.title(f'1D Convection Equation at t = {solver.T:.3f} using [1-7]th-order ENO and {solver.rk}{ordinal}-order Runge-Kutta methods') + for i in range(0, n): + lable = 'Numerical (Rusanov)ENO' + str(i+1) + style = styles[i % num_styles] + plt.plot(xcc, u_list[i], marker=style['marker'], markerfacecolor='none', linestyle=style['linestyle'], color=style['color'], \ + markersize=5, linewidth=0.5, alpha=1.0, label=f'{lable}') + plt.plot(xcc, u_analytical, 'r--', label='Analytical') + plt.xlabel('x') + plt.ylabel('u') + plt.legend() + plt.grid(True, color='gray', linestyle='--', linewidth=0.5, alpha=0.7) + plt.tight_layout() + plt.show() + +def plot_eno_TimestepAnalysis(solver, xcc, u_list, u_analytical, dt_list, iorder): + # 定义一个包含不同颜色、线形和标记的列表 + styles = [ + {'color': 'black', 'linestyle': '-', 'marker': 'o'}, + {'color': 'blue', 'linestyle': '--', 'marker': 's'}, + {'color': 'black', 'linestyle': '-', 'marker': '^'}, + {'color': 'blue', 'linestyle': '--', 'marker': 'v'}, + {'color': 'black', 'linestyle': '-', 'marker': '<'}, + {'color': 'blue', 'linestyle': '--', 'marker': '>'}, + {'color': 'black', 'linestyle': '-', 'marker': 'D'}, + {'color': 'blue', 'linestyle': '--', 'marker': 'o'}, + {'color': 'black', 'linestyle': '-', 'marker': 's'}, + {'color': 'blue', 'linestyle': '--', 'marker': '^'}, + {'color': 'black', 'linestyle': '-', 'marker': 'v'}, + {'color': 'blue', 'linestyle': '--', 'marker': '<'}, + {'color': 'black', 'linestyle': '-', 'marker': '>'}, + {'color': 'blue', 'linestyle': '--', 'marker': 'D'}, + ] + + n = len(u_list) + num_styles = len(styles) + + ordinalENO = get_ordinal_numbers(iorder) + ordinalRK = get_ordinal_numbers(solver.rk) + + plt.figure("OneFLOW-CFD Solver", figsize=(10, 6)) + plt.title(f'1D Convection Equation at t = {solver.T:.3f} using {iorder}{ordinalENO}-order ENO and {solver.rk}{ordinalRK}-order Runge-Kutta methods') + for i in range(0, n): + lable = 'Numerical (Rusanov)ENO' + str(iorder) + ' T='+str(dt_list[i]) + style = styles[i % num_styles] + plt.plot(xcc, u_list[i], marker=style['marker'], markerfacecolor='none', linestyle=style['linestyle'], color=style['color'], \ + markersize=5, linewidth=1.0, alpha=1.0, label=f'{lable}') + plt.plot(xcc, u_analytical, 'r--', label='Analytical') + plt.xlabel('x') + plt.ylabel('u') + plt.legend() + plt.grid(True, color='gray', linestyle='--', linewidth=0.5, alpha=0.7) + plt.tight_layout() + plt.show() + +def RunEno(solver, mesh, iorder): + eno = Eno(solver, mesh, iorder) + init_coef(eno.iorder, eno.coef) + init_field(eno) + + simu_time = solver.T + t = 0.0 + dt = solver.dt + while t < simu_time: + runge_kutta(eno) + if t + dt > simu_time: + dt = simu_time - t + t += dt + #print(f'T={t:.3f},runge_kutta{solver.rk},ENO{eno.iorder},{fluxnames[solver.iflux]} FLUX') + #visualize(eno) + return np.copy(eno.u[eno.ist:eno.ied+1]) + +def performEnoOrderAnalysis(): + iorder_max = 7 + mesh = Mesh() + solver = Solver() + #计算理论解 + u_analytical = analytical_solution(mesh.xcc, solver.T, solver.c, mesh.L) + + u_list = [] + for iorder in range(1, iorder_max+1): + u = RunEno(solver, mesh, iorder) + u_list.append(u) + + plot_eno_OrderAnalysis(solver, mesh.xcc, u_list, u_analytical) + +def performEnoTimestepAnalysis(): + mesh = Mesh() + solver = Solver() + #计算理论解 + u_analytical = analytical_solution(mesh.xcc, solver.T, solver.c, mesh.L) + + u_list = [] + dt_list = [] + solver.dt = 0.025 + #solver.dt = 0.025/16 + n = 12 + solver.rk = 1 + iorder = 2 + for i in range(0, n): + u = RunEno(solver, mesh, iorder) + u_list.append(u) + dt_list.append(solver.dt) + print(f'i={i+1},N={n},T={solver.T:.3f},dt={solver.dt},nt={int(solver.T/solver.dt)},runge_kutta{solver.rk},ENO{iorder},{fluxnames[solver.iflux]} FLUX') + solver.dt /= 2 + + plot_eno_TimestepAnalysis(solver, mesh.xcc, u_list, u_analytical, dt_list, iorder) + +def main(): + #performEnoOrderAnalysis() + performEnoTimestepAnalysis() + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/example/1d-linear-convection/eno/rusanov/timestep/rk1-eno/eno2/01/plot.py b/example/1d-linear-convection/eno/rusanov/timestep/rk1-eno/eno2/01/plot.py new file mode 100644 index 00000000..e389044c --- /dev/null +++ b/example/1d-linear-convection/eno/rusanov/timestep/rk1-eno/eno2/01/plot.py @@ -0,0 +1,53 @@ +import numpy as np +import matplotlib.pyplot as plt +import csv +import sys + +nvar = len(sys.argv) +print('nvar=',nvar) +print('sys.argv=',sys.argv) + +order = 1 +if nvar >= 2: + var = sys.argv[1] + print('var=',var) + order = int(var) + +print('order=',order) + +x_list = [] +u_list = [] + +with open('solution.plt', newline='') as csvfile: + #readCSV = csv.reader(csvfile, delimiter= ' ') + icount = 0 + for line in csvfile: + # 去除首尾空格,按连续空格分割 + row = line.strip().split() + #print("row=",row) + x_list.append(row[0]) + u_list.append(row[1]) + icount += 1 + +ni = icount +print("ni=",ni) + +#print("x_list=",x_list) + +x = np.zeros( ni ) +u = np.zeros( ni ) + +for i in range(0, ni): + x[i] = float(x_list[i]) + u[i] = float(u_list[i]) + +labelname = 'Eno' + str(order) + +plt.figure("OneFLOW-CFD Solver", figsize=(8, 6), dpi=100) +plt.plot(x, u, "b-", linewidth=1.0, marker = 's', markerfacecolor='None', label=labelname) +plt.xlabel("$x$") +plt.ylabel("$u$") +plt.title("burgers T=1") +plt.legend() +plt.tight_layout() +plt.show(); \ No newline at end of file diff --git a/example/1d-linear-convection/eno/rusanov/timestep/rk1-eno/eno3/01/eno.py b/example/1d-linear-convection/eno/rusanov/timestep/rk1-eno/eno3/01/eno.py new file mode 100644 index 00000000..0dc9f6c3 --- /dev/null +++ b/example/1d-linear-convection/eno/rusanov/timestep/rk1-eno/eno3/01/eno.py @@ -0,0 +1,426 @@ +import numpy as np +import matplotlib.pyplot as plt + +# 初始条件 +def initial_condition(x): + u0 = np.zeros_like(x) + for i in range(len(x)): + if 0.5 <= x[i] <= 1.0: + u0[i] = 2.0 + else: + u0[i] = 1.0 + return u0 + +# 理论解 +def analytical_solution(x, t, a, L): + # 初始条件沿 x - at 平移 + x_shifted = x - a * t + return initial_condition((x_shifted + L) % L) # 周期边界条件 + +def residual(q, eno): + reconstruction(q, eno) + inviscid_flux(eno.up1_2m, eno.up1_2p, eno.flux, eno) + for i in range(eno.nx): + eno.res[i] = -(eno.flux[i + 1] - eno.flux[i]) / eno.mesh.dx + +def reconstruction(q, eno): + # Choose the stencil by ENO method + eno.dd[0, 0:eno.ntcell-1] = q[0:eno.ntcell-1] + + for m in range(1, eno.iorder): + for j in range(0, eno.ntcell-1): + eno.dd[m, j] = eno.dd[m-1, j+1] - eno.dd[m-1, j] + + for i in range(eno.nx + 1): + eno.il[i] = i - 1 + for m in range(1, eno.iorder): + if abs(eno.dd[m, eno.il[i]-1+eno.ishift]) <= abs(eno.dd[m, eno.il[i]+eno.ishift]): + eno.il[i] -= 1 + + for i in range(eno.nx + 1): + eno.ir[i] = i + for m in range(1, eno.iorder): + if abs(eno.dd[m, eno.ir[i]-1+eno.ishift]) <= abs(eno.dd[m, eno.ir[i]+eno.ishift]): + eno.ir[i] -= 1 + + # Reconstruction u(j+1/2) + for i in range(eno.nx + 1): + k1 = eno.il[i] + k2 = eno.ir[i] + l1 = i - k1 + l2 = i - k2 + eno.up1_2m[i] = 0 + eno.up1_2p[i] = 0 + for m in range(eno.iorder): + eno.up1_2m[i] += q[k1 + eno.ishift + m] * eno.coef[l1, m] + eno.up1_2p[i] += q[k2 + eno.ishift + m] * eno.coef[l2, m] + +fluxnames = [ + 'Rusanov', + 'Engquist-Osher', +] + +def inviscid_flux(up1_2m, up1_2p, flux, eno): + if eno.solver.iflux == 0: + rusanov_flux(up1_2m, up1_2p, flux, eno) + else: + engquist_osher_flux(up1_2m, up1_2p, flux, eno) + +def engquist_osher_flux(up1_2m, up1_2p, flux, eno): + for i in range(eno.nx + 1): + u_L = up1_2m[i] + u_R = up1_2p[i] + + cp = 0.5 * ( eno.solver.c + abs(eno.solver.c) ) + cm = 0.5 * ( eno.solver.c - abs(eno.solver.c) ) + + flux[i] = cp * u_L + cm * u_R + +def rusanov_flux(up1_2m, up1_2p, flux, eno): + for i in range(eno.nx + 1): + u_L = up1_2m[i] + u_R = up1_2p[i] + F_L = eno.solver.c * u_L # 左状态通量 + F_R = eno.solver.c * u_R # 右状态通量 + alpha = abs(eno.solver.c) # 最大波速 + flux[i] = 0.5 * (F_L + F_R) - 0.5 * alpha * (u_R - u_L) + + +def boundary(u, eno): + for i in range(-eno.ighost, 1): + u[eno.ist - 1 + i] = u[eno.ied + i] + for i in range(1, eno.ighost + 2): + u[eno.ied + i] = u[eno.ist - 1 + i] + +def update_oldfield(qn, q): + qn[:] = q[:] + +def init_coef( iorder, coef ): + if iorder == 1: + coef[0] = [1.0] + coef[1] = [1.0] + elif iorder == 2: + coef[0] = [3.0/2.0, -1.0/2.0] + coef[1] = [1.0/2.0, 1.0/2.0] + coef[2] = [-1.0/2.0, 3.0/2.0] + elif iorder == 3: + coef[0] = [ 11.0/6.0, -7.0/6.0, 1.0/3.0 ] + coef[1] = [ 1.0/3.0, 5.0/6.0, -1.0/6.0 ] + coef[2] = [ -1.0/6.0, 5.0/6.0, 1.0/3.0 ] + coef[3] = [ 1.0/3.0, -7.0/6.0, 11.0/6.0 ] + elif iorder == 4: + coef[0] = [ 25.0/12.0, -23.0/12.0, 13.0/12.0, -1.0/4.0 ] + coef[1] = [ 1.0/4.0, 13.0/12.0, -5.0/12.0, 1.0/12.0 ] + coef[2] = [ -1.0/12.0, 7.0/12.0, 7.0/12.0, -1.0/12.0 ] + coef[3] = [ 1.0/12.0, -5.0/12.0, 13.0/12.0, 1.0/4.0 ] + coef[4] = [ -1.0/4.0, 13.0/12.0, -23.0/12.0, 25.0/12.0 ] + elif iorder == 5: + coef[0] = [ 137.0/60.0, -163.0/60.0, 137.0/60.0, -21.0/20.0, 1.0/5.0 ] + coef[1] = [ 1.0/5.0, 77.0/60.0, -43.0/60.0, 17.0/60.0, -1.0/20.0 ] + coef[2] = [ -1.0/20.0, 9.0/20.0, 47.0/60.0, -13.0/60.0, 1.0/30.0 ] + coef[3] = [ 1.0/30.0, -13.0/60.0, 47.0/60.0, 9.0/20.0, -1.0/20.0 ] + coef[4] = [ -1.0/20.0, 17.0/60.0, -43.0/60.0, 77.0/60.0, 1.0/5.0 ] + coef[5] = [ 1.0/5.0, -21.0/20.0, 137.0/60.0, -163.0/60.0, 137.0/60.0 ] + elif iorder == 6: + coef[0] = [ 49.0/20.0, -71.0/20.0, 79.0/20.0, -163.0/60.0, 31.0/30.0, -1.0/6.0 ] + coef[1] = [ 1.0/6.0, 29.0/20.0, -21.0/20.0, 37.0/60.0, -13.0/60.0, 1.0/30.0 ] + coef[2] = [ -1.0/30.0, 11.0/30.0, 19.0/20.0, -23.0/60.0, 7.0/60.0, -1.0/60.0 ] + coef[3] = [ 1.0/60.0, -2.0/15.0, 37.0/60.0, 37.0/60.0, -2.0/15.0, 1.0/60.0 ] + coef[4] = [ -1.0/60.0, 7.0/60.0, -23.0/60.0, 19.0/20.0, 11.0/30.0, -1.0/30.0 ] + coef[5] = [ 1.0/30.0, -13.0/60.0, 37.0/60.0, -21.0/20.0, 29.0/20.0, 1.0/6.0 ] + coef[6] = [ -1.0/6.0, 31.0/30.0, -163.0/60.0, 79.0/20.0, -71.0/20.0, 49.0/20.0 ] + elif iorder == 7: + coef[0] = [ 363.0/140.0, -617.0/140.0, 853.0/140.0, -2341.0/420.0, 667.0/210.0, -43.0/42.0, 1.0/7.0 ] + coef[1] = [ 1.0/7.0, 223.0/140.0, -197.0/140.0, 153.0/140.0, -241.0/420.0, 37.0/210.0, -1.0/42.0 ] + coef[2] = [ -1.0/42.0, 13.0/42.0, 153.0/140.0, -241.0/420.0, 109.0/420.0, -31.0/420.0, 1.0/105.0 ] + coef[3] = [ 1.0/105.0, -19.0/210.0, 107.0/210.0, 319.0/420.0, -101.0/420.0, 5.0/84.0, -1.0/140.0 ] + coef[4] = [ -1.0/140.0, 5.0/84.0, -101.0/420.0, 319.0/420.0, 107.0/210.0, -19.0/210.0, 1.0/105.0 ] + coef[5] = [ 1.0/105.0, -31.0/420.0, 109.0/420.0, -241.0/420.0, 153.0/140.0, 13.0/42.0, -1.0/42.0 ] + coef[6] = [ -1.0/42.0, 37.0/210.0, -241.0/420.0, 153.0/140.0, -197.0/140.0, 223.0/140.0, 1.0/7.0 ] + coef[7] = [ 1.0/7.0, -43.0/42.0, 667.0/210.0, -2341.0/420.0, 853.0/140.0, -617.0/140.0, 363.0/140.0 ] + +def init_field(eno): + for i in range(eno.ist, eno.ied + 1): + j = i - eno.ist + if 0.5 <= eno.mesh.xcc[j] <= 1.0: + eno.u[i] = 2.0 + else: + eno.u[i] = 1.0 + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def runge_kutta(eno): + rk = eno.solver.rk + if rk == 1: + runge_kutta_1(eno) + elif rk == 2: + runge_kutta_2(eno) + else: + runge_kutta_3(eno) + +def runge_kutta_1(eno): + dt = eno.solver.dt + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = eno.u[j] + dt * eno.res[i] + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def runge_kutta_2(eno): + dt = eno.solver.dt + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = eno.u[j] + dt * eno.res[i] + boundary(eno.u, eno) + + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = 0.5 * eno.un[j] + 0.5 * eno.u[j] + 0.5 * dt * eno.res[i] + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def runge_kutta_3(eno): + dt = eno.solver.dt + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = eno.u[j] + dt * eno.res[i] + boundary(eno.u, eno) + + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = 0.75 * eno.un[j] + 0.25 * eno.u[j] + 0.25 * dt * eno.res[i] + boundary(eno.u, eno) + + residual(eno.u, eno) + c1, c2, c3 = 1.0/3.0, 2.0/3.0, 2.0/3.0 + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = c1 * eno.un[j] + c2 * eno.u[j] + c3 * dt * eno.res[i] + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def get_ordinal_numbers(order): + if order == 1: + return 'st' + elif order == 2: + return 'nd' + elif order == 3: + return 'rd' + else: + return 'th' + +def visualize(eno): + with open('solution.plt', 'w') as f: + for i in range(eno.ist, eno.ied + 1): + j = i - eno.ist + f.write(f"{eno.xcc[j]:20.10e}{eno.u[i]:20.10e}\n") + + # 可视化 + u_numerical = np.copy(eno.u[eno.ist:eno.ied+1]) + print(f'u_numerical.size={u_numerical.size}') + print(f'eno.xcc.size={eno.xcc.size}') + #计算理论解 + u_analytical = analytical_solution(eno.mesh.xcc, eno.T, eno.c, eno.L) + print(f'u_analytical.size={u_analytical.size}') + plt.figure("OneFLOW-CFD Solver", figsize=(10, 6)) + plt.scatter(eno.xcc, u_numerical, facecolor="none", edgecolor="blue", s=20, linewidths=0.5, label=f'Numerical (Rusanov)') + plt.plot(eno.xcc, u_analytical, 'r--', label='Analytical') + plt.xlabel('x') + plt.ylabel('u') + ordinal1 = get_ordinal_numbers(eno.iorder) + ordinal2 = get_ordinal_numbers(eno.rk) + plt.title(f'1D Convection Equation at t = {eno.T:.3f} using {eno.iorder}{ordinal1}-order ENO and {eno.rk}{ordinal2}-order Runge-Kutta methods') + plt.legend() + plt.grid(True, color='gray', linestyle='--', linewidth=0.5, alpha=0.7) + plt.tight_layout() + plt.show() + +class Mesh: + def __init__(self): + self.nx = 40 + self.L = 2.0 + self.x = np.zeros(self.nx + 1) + self.xcc = np.zeros(self.nx) + self.init_mesh() + def init_mesh(self): + xstart = 0.0 + xend = self.L + self.dx = (xend - xstart) / self.nx + + for i in range(0, self.nx+1): + self.x[i] = xstart + i * self.dx + + for i in range(0, self.nx): + self.xcc[i] = 0.5 * (self.x[i] + self.x[i + 1]) + +class Solver: + def __init__(self): + self.iflux = 0 + self.rk = 1 + self.c = 1.0 + self.T = 0.625 + self.dt = .0025 + +class Eno: + def __init__(self, solver, mesh, iorder): + self.solver = solver + self.mesh = mesh + self.nx = mesh.nx + self.iorder = iorder + self.ighost = iorder + self.ishift = self.ighost + 1 + self.ist = 0 + self.ishift + self.ied = self.nx - 1 + self.ishift + self.ntcell = self.nx + 2 * self.ishift + self.isize = iorder * (iorder + 1) + + self.il = np.zeros(self.nx + 1, dtype=int) + self.ir = np.zeros(self.nx + 1, dtype=int) + self.coef = np.zeros((iorder + 1, iorder)) + self.dd = np.zeros((iorder, self.ntcell)) + self.up1_2m = np.zeros(self.nx + 1) + self.up1_2p = np.zeros(self.nx + 1) + self.flux = np.zeros(self.nx + 1) + self.res = np.zeros(self.nx) + + # Field module variables + self.u = np.zeros(self.ntcell) + self.un = np.zeros(self.ntcell) + + #self.dt = .0025 + +def plot_eno_OrderAnalysis(solver, xcc, u_list, u_analytical): + # 定义一个包含不同颜色、线形和标记的列表 + styles = [ + {'color': 'black', 'linestyle': '-', 'marker': 'o'}, + {'color': 'blue', 'linestyle': '--', 'marker': 's'}, + {'color': 'black', 'linestyle': '-', 'marker': '^'}, + {'color': 'blue', 'linestyle': '--', 'marker': 'v'}, + {'color': 'black', 'linestyle': '-', 'marker': '<'}, + {'color': 'blue', 'linestyle': '--', 'marker': '>'}, + {'color': 'black', 'linestyle': '-', 'marker': 'D'}, + ] + + n = len(u_list) + num_styles = len(styles) + ordinal = get_ordinal_numbers(solver.rk) + + plt.figure("OneFLOW-CFD Solver", figsize=(10, 6)) + plt.title(f'1D Convection Equation at t = {solver.T:.3f} using [1-7]th-order ENO and {solver.rk}{ordinal}-order Runge-Kutta methods') + for i in range(0, n): + lable = 'Numerical (Rusanov)ENO' + str(i+1) + style = styles[i % num_styles] + plt.plot(xcc, u_list[i], marker=style['marker'], markerfacecolor='none', linestyle=style['linestyle'], color=style['color'], \ + markersize=5, linewidth=0.5, alpha=1.0, label=f'{lable}') + plt.plot(xcc, u_analytical, 'r--', label='Analytical') + plt.xlabel('x') + plt.ylabel('u') + plt.legend() + plt.grid(True, color='gray', linestyle='--', linewidth=0.5, alpha=0.7) + plt.tight_layout() + plt.show() + +def plot_eno_TimestepAnalysis(solver, xcc, u_list, u_analytical, dt_list, iorder): + # 定义一个包含不同颜色、线形和标记的列表 + styles = [ + {'color': 'black', 'linestyle': '-', 'marker': 'o'}, + {'color': 'blue', 'linestyle': '--', 'marker': 's'}, + {'color': 'black', 'linestyle': '-', 'marker': '^'}, + {'color': 'blue', 'linestyle': '--', 'marker': 'v'}, + {'color': 'black', 'linestyle': '-', 'marker': '<'}, + {'color': 'blue', 'linestyle': '--', 'marker': '>'}, + {'color': 'black', 'linestyle': '-', 'marker': 'D'}, + {'color': 'blue', 'linestyle': '--', 'marker': 'o'}, + {'color': 'black', 'linestyle': '-', 'marker': 's'}, + {'color': 'blue', 'linestyle': '--', 'marker': '^'}, + {'color': 'black', 'linestyle': '-', 'marker': 'v'}, + {'color': 'blue', 'linestyle': '--', 'marker': '<'}, + {'color': 'black', 'linestyle': '-', 'marker': '>'}, + {'color': 'blue', 'linestyle': '--', 'marker': 'D'}, + ] + + n = len(u_list) + num_styles = len(styles) + + ordinalENO = get_ordinal_numbers(iorder) + ordinalRK = get_ordinal_numbers(solver.rk) + + plt.figure("OneFLOW-CFD Solver", figsize=(10, 6)) + plt.title(f'1D Convection Equation at t = {solver.T:.3f} using {iorder}{ordinalENO}-order ENO and {solver.rk}{ordinalRK}-order Runge-Kutta methods') + for i in range(0, n): + lable = 'Numerical (Rusanov)ENO' + str(iorder) + ' T='+str(dt_list[i]) + style = styles[i % num_styles] + plt.plot(xcc, u_list[i], marker=style['marker'], markerfacecolor='none', linestyle=style['linestyle'], color=style['color'], \ + markersize=5, linewidth=1.0, alpha=1.0, label=f'{lable}') + plt.plot(xcc, u_analytical, 'r--', label='Analytical') + plt.xlabel('x') + plt.ylabel('u') + plt.legend() + plt.grid(True, color='gray', linestyle='--', linewidth=0.5, alpha=0.7) + plt.tight_layout() + plt.show() + +def RunEno(solver, mesh, iorder): + eno = Eno(solver, mesh, iorder) + init_coef(eno.iorder, eno.coef) + init_field(eno) + + simu_time = solver.T + t = 0.0 + dt = solver.dt + while t < simu_time: + runge_kutta(eno) + if t + dt > simu_time: + dt = simu_time - t + t += dt + #print(f'T={t:.3f},runge_kutta{solver.rk},ENO{eno.iorder},{fluxnames[solver.iflux]} FLUX') + #visualize(eno) + return np.copy(eno.u[eno.ist:eno.ied+1]) + +def performEnoOrderAnalysis(): + iorder_max = 7 + mesh = Mesh() + solver = Solver() + #计算理论解 + u_analytical = analytical_solution(mesh.xcc, solver.T, solver.c, mesh.L) + + u_list = [] + for iorder in range(1, iorder_max+1): + u = RunEno(solver, mesh, iorder) + u_list.append(u) + + plot_eno_OrderAnalysis(solver, mesh.xcc, u_list, u_analytical) + +def performEnoTimestepAnalysis(): + mesh = Mesh() + solver = Solver() + #计算理论解 + u_analytical = analytical_solution(mesh.xcc, solver.T, solver.c, mesh.L) + + u_list = [] + dt_list = [] + solver.dt = 0.025 + #solver.dt = 0.025/16 + n = 12 + solver.rk = 1 + iorder = 3 + for i in range(0, n): + u = RunEno(solver, mesh, iorder) + u_list.append(u) + dt_list.append(solver.dt) + print(f'i={i+1},N={n},T={solver.T:.3f},dt={solver.dt},nt={int(solver.T/solver.dt)},runge_kutta{solver.rk},ENO{iorder},{fluxnames[solver.iflux]} FLUX') + solver.dt /= 2 + + plot_eno_TimestepAnalysis(solver, mesh.xcc, u_list, u_analytical, dt_list, iorder) + +def main(): + #performEnoOrderAnalysis() + performEnoTimestepAnalysis() + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/example/1d-linear-convection/eno/rusanov/timestep/rk1-eno/eno3/01/plot.py b/example/1d-linear-convection/eno/rusanov/timestep/rk1-eno/eno3/01/plot.py new file mode 100644 index 00000000..e389044c --- /dev/null +++ b/example/1d-linear-convection/eno/rusanov/timestep/rk1-eno/eno3/01/plot.py @@ -0,0 +1,53 @@ +import numpy as np +import matplotlib.pyplot as plt +import csv +import sys + +nvar = len(sys.argv) +print('nvar=',nvar) +print('sys.argv=',sys.argv) + +order = 1 +if nvar >= 2: + var = sys.argv[1] + print('var=',var) + order = int(var) + +print('order=',order) + +x_list = [] +u_list = [] + +with open('solution.plt', newline='') as csvfile: + #readCSV = csv.reader(csvfile, delimiter= ' ') + icount = 0 + for line in csvfile: + # 去除首尾空格,按连续空格分割 + row = line.strip().split() + #print("row=",row) + x_list.append(row[0]) + u_list.append(row[1]) + icount += 1 + +ni = icount +print("ni=",ni) + +#print("x_list=",x_list) + +x = np.zeros( ni ) +u = np.zeros( ni ) + +for i in range(0, ni): + x[i] = float(x_list[i]) + u[i] = float(u_list[i]) + +labelname = 'Eno' + str(order) + +plt.figure("OneFLOW-CFD Solver", figsize=(8, 6), dpi=100) +plt.plot(x, u, "b-", linewidth=1.0, marker = 's', markerfacecolor='None', label=labelname) +plt.xlabel("$x$") +plt.ylabel("$u$") +plt.title("burgers T=1") +plt.legend() +plt.tight_layout() +plt.show(); \ No newline at end of file diff --git a/example/1d-linear-convection/eno/rusanov/timestep/rk1-eno/eno4/01/eno.py b/example/1d-linear-convection/eno/rusanov/timestep/rk1-eno/eno4/01/eno.py new file mode 100644 index 00000000..f5ac8edd --- /dev/null +++ b/example/1d-linear-convection/eno/rusanov/timestep/rk1-eno/eno4/01/eno.py @@ -0,0 +1,426 @@ +import numpy as np +import matplotlib.pyplot as plt + +# 初始条件 +def initial_condition(x): + u0 = np.zeros_like(x) + for i in range(len(x)): + if 0.5 <= x[i] <= 1.0: + u0[i] = 2.0 + else: + u0[i] = 1.0 + return u0 + +# 理论解 +def analytical_solution(x, t, a, L): + # 初始条件沿 x - at 平移 + x_shifted = x - a * t + return initial_condition((x_shifted + L) % L) # 周期边界条件 + +def residual(q, eno): + reconstruction(q, eno) + inviscid_flux(eno.up1_2m, eno.up1_2p, eno.flux, eno) + for i in range(eno.nx): + eno.res[i] = -(eno.flux[i + 1] - eno.flux[i]) / eno.mesh.dx + +def reconstruction(q, eno): + # Choose the stencil by ENO method + eno.dd[0, 0:eno.ntcell-1] = q[0:eno.ntcell-1] + + for m in range(1, eno.iorder): + for j in range(0, eno.ntcell-1): + eno.dd[m, j] = eno.dd[m-1, j+1] - eno.dd[m-1, j] + + for i in range(eno.nx + 1): + eno.il[i] = i - 1 + for m in range(1, eno.iorder): + if abs(eno.dd[m, eno.il[i]-1+eno.ishift]) <= abs(eno.dd[m, eno.il[i]+eno.ishift]): + eno.il[i] -= 1 + + for i in range(eno.nx + 1): + eno.ir[i] = i + for m in range(1, eno.iorder): + if abs(eno.dd[m, eno.ir[i]-1+eno.ishift]) <= abs(eno.dd[m, eno.ir[i]+eno.ishift]): + eno.ir[i] -= 1 + + # Reconstruction u(j+1/2) + for i in range(eno.nx + 1): + k1 = eno.il[i] + k2 = eno.ir[i] + l1 = i - k1 + l2 = i - k2 + eno.up1_2m[i] = 0 + eno.up1_2p[i] = 0 + for m in range(eno.iorder): + eno.up1_2m[i] += q[k1 + eno.ishift + m] * eno.coef[l1, m] + eno.up1_2p[i] += q[k2 + eno.ishift + m] * eno.coef[l2, m] + +fluxnames = [ + 'Rusanov', + 'Engquist-Osher', +] + +def inviscid_flux(up1_2m, up1_2p, flux, eno): + if eno.solver.iflux == 0: + rusanov_flux(up1_2m, up1_2p, flux, eno) + else: + engquist_osher_flux(up1_2m, up1_2p, flux, eno) + +def engquist_osher_flux(up1_2m, up1_2p, flux, eno): + for i in range(eno.nx + 1): + u_L = up1_2m[i] + u_R = up1_2p[i] + + cp = 0.5 * ( eno.solver.c + abs(eno.solver.c) ) + cm = 0.5 * ( eno.solver.c - abs(eno.solver.c) ) + + flux[i] = cp * u_L + cm * u_R + +def rusanov_flux(up1_2m, up1_2p, flux, eno): + for i in range(eno.nx + 1): + u_L = up1_2m[i] + u_R = up1_2p[i] + F_L = eno.solver.c * u_L # 左状态通量 + F_R = eno.solver.c * u_R # 右状态通量 + alpha = abs(eno.solver.c) # 最大波速 + flux[i] = 0.5 * (F_L + F_R) - 0.5 * alpha * (u_R - u_L) + + +def boundary(u, eno): + for i in range(-eno.ighost, 1): + u[eno.ist - 1 + i] = u[eno.ied + i] + for i in range(1, eno.ighost + 2): + u[eno.ied + i] = u[eno.ist - 1 + i] + +def update_oldfield(qn, q): + qn[:] = q[:] + +def init_coef( iorder, coef ): + if iorder == 1: + coef[0] = [1.0] + coef[1] = [1.0] + elif iorder == 2: + coef[0] = [3.0/2.0, -1.0/2.0] + coef[1] = [1.0/2.0, 1.0/2.0] + coef[2] = [-1.0/2.0, 3.0/2.0] + elif iorder == 3: + coef[0] = [ 11.0/6.0, -7.0/6.0, 1.0/3.0 ] + coef[1] = [ 1.0/3.0, 5.0/6.0, -1.0/6.0 ] + coef[2] = [ -1.0/6.0, 5.0/6.0, 1.0/3.0 ] + coef[3] = [ 1.0/3.0, -7.0/6.0, 11.0/6.0 ] + elif iorder == 4: + coef[0] = [ 25.0/12.0, -23.0/12.0, 13.0/12.0, -1.0/4.0 ] + coef[1] = [ 1.0/4.0, 13.0/12.0, -5.0/12.0, 1.0/12.0 ] + coef[2] = [ -1.0/12.0, 7.0/12.0, 7.0/12.0, -1.0/12.0 ] + coef[3] = [ 1.0/12.0, -5.0/12.0, 13.0/12.0, 1.0/4.0 ] + coef[4] = [ -1.0/4.0, 13.0/12.0, -23.0/12.0, 25.0/12.0 ] + elif iorder == 5: + coef[0] = [ 137.0/60.0, -163.0/60.0, 137.0/60.0, -21.0/20.0, 1.0/5.0 ] + coef[1] = [ 1.0/5.0, 77.0/60.0, -43.0/60.0, 17.0/60.0, -1.0/20.0 ] + coef[2] = [ -1.0/20.0, 9.0/20.0, 47.0/60.0, -13.0/60.0, 1.0/30.0 ] + coef[3] = [ 1.0/30.0, -13.0/60.0, 47.0/60.0, 9.0/20.0, -1.0/20.0 ] + coef[4] = [ -1.0/20.0, 17.0/60.0, -43.0/60.0, 77.0/60.0, 1.0/5.0 ] + coef[5] = [ 1.0/5.0, -21.0/20.0, 137.0/60.0, -163.0/60.0, 137.0/60.0 ] + elif iorder == 6: + coef[0] = [ 49.0/20.0, -71.0/20.0, 79.0/20.0, -163.0/60.0, 31.0/30.0, -1.0/6.0 ] + coef[1] = [ 1.0/6.0, 29.0/20.0, -21.0/20.0, 37.0/60.0, -13.0/60.0, 1.0/30.0 ] + coef[2] = [ -1.0/30.0, 11.0/30.0, 19.0/20.0, -23.0/60.0, 7.0/60.0, -1.0/60.0 ] + coef[3] = [ 1.0/60.0, -2.0/15.0, 37.0/60.0, 37.0/60.0, -2.0/15.0, 1.0/60.0 ] + coef[4] = [ -1.0/60.0, 7.0/60.0, -23.0/60.0, 19.0/20.0, 11.0/30.0, -1.0/30.0 ] + coef[5] = [ 1.0/30.0, -13.0/60.0, 37.0/60.0, -21.0/20.0, 29.0/20.0, 1.0/6.0 ] + coef[6] = [ -1.0/6.0, 31.0/30.0, -163.0/60.0, 79.0/20.0, -71.0/20.0, 49.0/20.0 ] + elif iorder == 7: + coef[0] = [ 363.0/140.0, -617.0/140.0, 853.0/140.0, -2341.0/420.0, 667.0/210.0, -43.0/42.0, 1.0/7.0 ] + coef[1] = [ 1.0/7.0, 223.0/140.0, -197.0/140.0, 153.0/140.0, -241.0/420.0, 37.0/210.0, -1.0/42.0 ] + coef[2] = [ -1.0/42.0, 13.0/42.0, 153.0/140.0, -241.0/420.0, 109.0/420.0, -31.0/420.0, 1.0/105.0 ] + coef[3] = [ 1.0/105.0, -19.0/210.0, 107.0/210.0, 319.0/420.0, -101.0/420.0, 5.0/84.0, -1.0/140.0 ] + coef[4] = [ -1.0/140.0, 5.0/84.0, -101.0/420.0, 319.0/420.0, 107.0/210.0, -19.0/210.0, 1.0/105.0 ] + coef[5] = [ 1.0/105.0, -31.0/420.0, 109.0/420.0, -241.0/420.0, 153.0/140.0, 13.0/42.0, -1.0/42.0 ] + coef[6] = [ -1.0/42.0, 37.0/210.0, -241.0/420.0, 153.0/140.0, -197.0/140.0, 223.0/140.0, 1.0/7.0 ] + coef[7] = [ 1.0/7.0, -43.0/42.0, 667.0/210.0, -2341.0/420.0, 853.0/140.0, -617.0/140.0, 363.0/140.0 ] + +def init_field(eno): + for i in range(eno.ist, eno.ied + 1): + j = i - eno.ist + if 0.5 <= eno.mesh.xcc[j] <= 1.0: + eno.u[i] = 2.0 + else: + eno.u[i] = 1.0 + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def runge_kutta(eno): + rk = eno.solver.rk + if rk == 1: + runge_kutta_1(eno) + elif rk == 2: + runge_kutta_2(eno) + else: + runge_kutta_3(eno) + +def runge_kutta_1(eno): + dt = eno.solver.dt + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = eno.u[j] + dt * eno.res[i] + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def runge_kutta_2(eno): + dt = eno.solver.dt + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = eno.u[j] + dt * eno.res[i] + boundary(eno.u, eno) + + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = 0.5 * eno.un[j] + 0.5 * eno.u[j] + 0.5 * dt * eno.res[i] + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def runge_kutta_3(eno): + dt = eno.solver.dt + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = eno.u[j] + dt * eno.res[i] + boundary(eno.u, eno) + + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = 0.75 * eno.un[j] + 0.25 * eno.u[j] + 0.25 * dt * eno.res[i] + boundary(eno.u, eno) + + residual(eno.u, eno) + c1, c2, c3 = 1.0/3.0, 2.0/3.0, 2.0/3.0 + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = c1 * eno.un[j] + c2 * eno.u[j] + c3 * dt * eno.res[i] + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def get_ordinal_numbers(order): + if order == 1: + return 'st' + elif order == 2: + return 'nd' + elif order == 3: + return 'rd' + else: + return 'th' + +def visualize(eno): + with open('solution.plt', 'w') as f: + for i in range(eno.ist, eno.ied + 1): + j = i - eno.ist + f.write(f"{eno.xcc[j]:20.10e}{eno.u[i]:20.10e}\n") + + # 可视化 + u_numerical = np.copy(eno.u[eno.ist:eno.ied+1]) + print(f'u_numerical.size={u_numerical.size}') + print(f'eno.xcc.size={eno.xcc.size}') + #计算理论解 + u_analytical = analytical_solution(eno.mesh.xcc, eno.T, eno.c, eno.L) + print(f'u_analytical.size={u_analytical.size}') + plt.figure("OneFLOW-CFD Solver", figsize=(10, 6)) + plt.scatter(eno.xcc, u_numerical, facecolor="none", edgecolor="blue", s=20, linewidths=0.5, label=f'Numerical (Rusanov)') + plt.plot(eno.xcc, u_analytical, 'r--', label='Analytical') + plt.xlabel('x') + plt.ylabel('u') + ordinal1 = get_ordinal_numbers(eno.iorder) + ordinal2 = get_ordinal_numbers(eno.rk) + plt.title(f'1D Convection Equation at t = {eno.T:.3f} using {eno.iorder}{ordinal1}-order ENO and {eno.rk}{ordinal2}-order Runge-Kutta methods') + plt.legend() + plt.grid(True, color='gray', linestyle='--', linewidth=0.5, alpha=0.7) + plt.tight_layout() + plt.show() + +class Mesh: + def __init__(self): + self.nx = 40 + self.L = 2.0 + self.x = np.zeros(self.nx + 1) + self.xcc = np.zeros(self.nx) + self.init_mesh() + def init_mesh(self): + xstart = 0.0 + xend = self.L + self.dx = (xend - xstart) / self.nx + + for i in range(0, self.nx+1): + self.x[i] = xstart + i * self.dx + + for i in range(0, self.nx): + self.xcc[i] = 0.5 * (self.x[i] + self.x[i + 1]) + +class Solver: + def __init__(self): + self.iflux = 0 + self.rk = 1 + self.c = 1.0 + self.T = 0.625 + self.dt = .0025 + +class Eno: + def __init__(self, solver, mesh, iorder): + self.solver = solver + self.mesh = mesh + self.nx = mesh.nx + self.iorder = iorder + self.ighost = iorder + self.ishift = self.ighost + 1 + self.ist = 0 + self.ishift + self.ied = self.nx - 1 + self.ishift + self.ntcell = self.nx + 2 * self.ishift + self.isize = iorder * (iorder + 1) + + self.il = np.zeros(self.nx + 1, dtype=int) + self.ir = np.zeros(self.nx + 1, dtype=int) + self.coef = np.zeros((iorder + 1, iorder)) + self.dd = np.zeros((iorder, self.ntcell)) + self.up1_2m = np.zeros(self.nx + 1) + self.up1_2p = np.zeros(self.nx + 1) + self.flux = np.zeros(self.nx + 1) + self.res = np.zeros(self.nx) + + # Field module variables + self.u = np.zeros(self.ntcell) + self.un = np.zeros(self.ntcell) + + #self.dt = .0025 + +def plot_eno_OrderAnalysis(solver, xcc, u_list, u_analytical): + # 定义一个包含不同颜色、线形和标记的列表 + styles = [ + {'color': 'black', 'linestyle': '-', 'marker': 'o'}, + {'color': 'blue', 'linestyle': '--', 'marker': 's'}, + {'color': 'black', 'linestyle': '-', 'marker': '^'}, + {'color': 'blue', 'linestyle': '--', 'marker': 'v'}, + {'color': 'black', 'linestyle': '-', 'marker': '<'}, + {'color': 'blue', 'linestyle': '--', 'marker': '>'}, + {'color': 'black', 'linestyle': '-', 'marker': 'D'}, + ] + + n = len(u_list) + num_styles = len(styles) + ordinal = get_ordinal_numbers(solver.rk) + + plt.figure("OneFLOW-CFD Solver", figsize=(10, 6)) + plt.title(f'1D Convection Equation at t = {solver.T:.3f} using [1-7]th-order ENO and {solver.rk}{ordinal}-order Runge-Kutta methods') + for i in range(0, n): + lable = 'Numerical (Rusanov)ENO' + str(i+1) + style = styles[i % num_styles] + plt.plot(xcc, u_list[i], marker=style['marker'], markerfacecolor='none', linestyle=style['linestyle'], color=style['color'], \ + markersize=5, linewidth=0.5, alpha=1.0, label=f'{lable}') + plt.plot(xcc, u_analytical, 'r--', label='Analytical') + plt.xlabel('x') + plt.ylabel('u') + plt.legend() + plt.grid(True, color='gray', linestyle='--', linewidth=0.5, alpha=0.7) + plt.tight_layout() + plt.show() + +def plot_eno_TimestepAnalysis(solver, xcc, u_list, u_analytical, dt_list, iorder): + # 定义一个包含不同颜色、线形和标记的列表 + styles = [ + {'color': 'black', 'linestyle': '-', 'marker': 'o'}, + {'color': 'blue', 'linestyle': '--', 'marker': 's'}, + {'color': 'black', 'linestyle': '-', 'marker': '^'}, + {'color': 'blue', 'linestyle': '--', 'marker': 'v'}, + {'color': 'black', 'linestyle': '-', 'marker': '<'}, + {'color': 'blue', 'linestyle': '--', 'marker': '>'}, + {'color': 'black', 'linestyle': '-', 'marker': 'D'}, + {'color': 'blue', 'linestyle': '--', 'marker': 'o'}, + {'color': 'black', 'linestyle': '-', 'marker': 's'}, + {'color': 'blue', 'linestyle': '--', 'marker': '^'}, + {'color': 'black', 'linestyle': '-', 'marker': 'v'}, + {'color': 'blue', 'linestyle': '--', 'marker': '<'}, + {'color': 'black', 'linestyle': '-', 'marker': '>'}, + {'color': 'blue', 'linestyle': '--', 'marker': 'D'}, + ] + + n = len(u_list) + num_styles = len(styles) + + ordinalENO = get_ordinal_numbers(iorder) + ordinalRK = get_ordinal_numbers(solver.rk) + + plt.figure("OneFLOW-CFD Solver", figsize=(10, 6)) + plt.title(f'1D Convection Equation at t = {solver.T:.3f} using {iorder}{ordinalENO}-order ENO and {solver.rk}{ordinalRK}-order Runge-Kutta methods') + for i in range(0, n): + lable = 'Numerical (Rusanov)ENO' + str(iorder) + ' T='+str(dt_list[i]) + style = styles[i % num_styles] + plt.plot(xcc, u_list[i], marker=style['marker'], markerfacecolor='none', linestyle=style['linestyle'], color=style['color'], \ + markersize=5, linewidth=1.0, alpha=1.0, label=f'{lable}') + plt.plot(xcc, u_analytical, 'r--', label='Analytical') + plt.xlabel('x') + plt.ylabel('u') + plt.legend() + plt.grid(True, color='gray', linestyle='--', linewidth=0.5, alpha=0.7) + plt.tight_layout() + plt.show() + +def RunEno(solver, mesh, iorder): + eno = Eno(solver, mesh, iorder) + init_coef(eno.iorder, eno.coef) + init_field(eno) + + simu_time = solver.T + t = 0.0 + dt = solver.dt + while t < simu_time: + runge_kutta(eno) + if t + dt > simu_time: + dt = simu_time - t + t += dt + #print(f'T={t:.3f},runge_kutta{solver.rk},ENO{eno.iorder},{fluxnames[solver.iflux]} FLUX') + #visualize(eno) + return np.copy(eno.u[eno.ist:eno.ied+1]) + +def performEnoOrderAnalysis(): + iorder_max = 7 + mesh = Mesh() + solver = Solver() + #计算理论解 + u_analytical = analytical_solution(mesh.xcc, solver.T, solver.c, mesh.L) + + u_list = [] + for iorder in range(1, iorder_max+1): + u = RunEno(solver, mesh, iorder) + u_list.append(u) + + plot_eno_OrderAnalysis(solver, mesh.xcc, u_list, u_analytical) + +def performEnoTimestepAnalysis(): + mesh = Mesh() + solver = Solver() + #计算理论解 + u_analytical = analytical_solution(mesh.xcc, solver.T, solver.c, mesh.L) + + u_list = [] + dt_list = [] + solver.dt = 0.025 + #solver.dt = 0.025/16 + n = 12 + solver.rk = 1 + iorder = 4 + for i in range(0, n): + u = RunEno(solver, mesh, iorder) + u_list.append(u) + dt_list.append(solver.dt) + print(f'i={i+1},N={n},T={solver.T:.3f},dt={solver.dt},nt={int(solver.T/solver.dt)},runge_kutta{solver.rk},ENO{iorder},{fluxnames[solver.iflux]} FLUX') + solver.dt /= 2 + + plot_eno_TimestepAnalysis(solver, mesh.xcc, u_list, u_analytical, dt_list, iorder) + +def main(): + #performEnoOrderAnalysis() + performEnoTimestepAnalysis() + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/example/1d-linear-convection/eno/rusanov/timestep/rk1-eno/eno4/01/plot.py b/example/1d-linear-convection/eno/rusanov/timestep/rk1-eno/eno4/01/plot.py new file mode 100644 index 00000000..e389044c --- /dev/null +++ b/example/1d-linear-convection/eno/rusanov/timestep/rk1-eno/eno4/01/plot.py @@ -0,0 +1,53 @@ +import numpy as np +import matplotlib.pyplot as plt +import csv +import sys + +nvar = len(sys.argv) +print('nvar=',nvar) +print('sys.argv=',sys.argv) + +order = 1 +if nvar >= 2: + var = sys.argv[1] + print('var=',var) + order = int(var) + +print('order=',order) + +x_list = [] +u_list = [] + +with open('solution.plt', newline='') as csvfile: + #readCSV = csv.reader(csvfile, delimiter= ' ') + icount = 0 + for line in csvfile: + # 去除首尾空格,按连续空格分割 + row = line.strip().split() + #print("row=",row) + x_list.append(row[0]) + u_list.append(row[1]) + icount += 1 + +ni = icount +print("ni=",ni) + +#print("x_list=",x_list) + +x = np.zeros( ni ) +u = np.zeros( ni ) + +for i in range(0, ni): + x[i] = float(x_list[i]) + u[i] = float(u_list[i]) + +labelname = 'Eno' + str(order) + +plt.figure("OneFLOW-CFD Solver", figsize=(8, 6), dpi=100) +plt.plot(x, u, "b-", linewidth=1.0, marker = 's', markerfacecolor='None', label=labelname) +plt.xlabel("$x$") +plt.ylabel("$u$") +plt.title("burgers T=1") +plt.legend() +plt.tight_layout() +plt.show(); \ No newline at end of file diff --git a/example/1d-linear-convection/eno/rusanov/timestep/rk1-eno/eno5/01/eno.py b/example/1d-linear-convection/eno/rusanov/timestep/rk1-eno/eno5/01/eno.py new file mode 100644 index 00000000..5696fab2 --- /dev/null +++ b/example/1d-linear-convection/eno/rusanov/timestep/rk1-eno/eno5/01/eno.py @@ -0,0 +1,426 @@ +import numpy as np +import matplotlib.pyplot as plt + +# 初始条件 +def initial_condition(x): + u0 = np.zeros_like(x) + for i in range(len(x)): + if 0.5 <= x[i] <= 1.0: + u0[i] = 2.0 + else: + u0[i] = 1.0 + return u0 + +# 理论解 +def analytical_solution(x, t, a, L): + # 初始条件沿 x - at 平移 + x_shifted = x - a * t + return initial_condition((x_shifted + L) % L) # 周期边界条件 + +def residual(q, eno): + reconstruction(q, eno) + inviscid_flux(eno.up1_2m, eno.up1_2p, eno.flux, eno) + for i in range(eno.nx): + eno.res[i] = -(eno.flux[i + 1] - eno.flux[i]) / eno.mesh.dx + +def reconstruction(q, eno): + # Choose the stencil by ENO method + eno.dd[0, 0:eno.ntcell-1] = q[0:eno.ntcell-1] + + for m in range(1, eno.iorder): + for j in range(0, eno.ntcell-1): + eno.dd[m, j] = eno.dd[m-1, j+1] - eno.dd[m-1, j] + + for i in range(eno.nx + 1): + eno.il[i] = i - 1 + for m in range(1, eno.iorder): + if abs(eno.dd[m, eno.il[i]-1+eno.ishift]) <= abs(eno.dd[m, eno.il[i]+eno.ishift]): + eno.il[i] -= 1 + + for i in range(eno.nx + 1): + eno.ir[i] = i + for m in range(1, eno.iorder): + if abs(eno.dd[m, eno.ir[i]-1+eno.ishift]) <= abs(eno.dd[m, eno.ir[i]+eno.ishift]): + eno.ir[i] -= 1 + + # Reconstruction u(j+1/2) + for i in range(eno.nx + 1): + k1 = eno.il[i] + k2 = eno.ir[i] + l1 = i - k1 + l2 = i - k2 + eno.up1_2m[i] = 0 + eno.up1_2p[i] = 0 + for m in range(eno.iorder): + eno.up1_2m[i] += q[k1 + eno.ishift + m] * eno.coef[l1, m] + eno.up1_2p[i] += q[k2 + eno.ishift + m] * eno.coef[l2, m] + +fluxnames = [ + 'Rusanov', + 'Engquist-Osher', +] + +def inviscid_flux(up1_2m, up1_2p, flux, eno): + if eno.solver.iflux == 0: + rusanov_flux(up1_2m, up1_2p, flux, eno) + else: + engquist_osher_flux(up1_2m, up1_2p, flux, eno) + +def engquist_osher_flux(up1_2m, up1_2p, flux, eno): + for i in range(eno.nx + 1): + u_L = up1_2m[i] + u_R = up1_2p[i] + + cp = 0.5 * ( eno.solver.c + abs(eno.solver.c) ) + cm = 0.5 * ( eno.solver.c - abs(eno.solver.c) ) + + flux[i] = cp * u_L + cm * u_R + +def rusanov_flux(up1_2m, up1_2p, flux, eno): + for i in range(eno.nx + 1): + u_L = up1_2m[i] + u_R = up1_2p[i] + F_L = eno.solver.c * u_L # 左状态通量 + F_R = eno.solver.c * u_R # 右状态通量 + alpha = abs(eno.solver.c) # 最大波速 + flux[i] = 0.5 * (F_L + F_R) - 0.5 * alpha * (u_R - u_L) + + +def boundary(u, eno): + for i in range(-eno.ighost, 1): + u[eno.ist - 1 + i] = u[eno.ied + i] + for i in range(1, eno.ighost + 2): + u[eno.ied + i] = u[eno.ist - 1 + i] + +def update_oldfield(qn, q): + qn[:] = q[:] + +def init_coef( iorder, coef ): + if iorder == 1: + coef[0] = [1.0] + coef[1] = [1.0] + elif iorder == 2: + coef[0] = [3.0/2.0, -1.0/2.0] + coef[1] = [1.0/2.0, 1.0/2.0] + coef[2] = [-1.0/2.0, 3.0/2.0] + elif iorder == 3: + coef[0] = [ 11.0/6.0, -7.0/6.0, 1.0/3.0 ] + coef[1] = [ 1.0/3.0, 5.0/6.0, -1.0/6.0 ] + coef[2] = [ -1.0/6.0, 5.0/6.0, 1.0/3.0 ] + coef[3] = [ 1.0/3.0, -7.0/6.0, 11.0/6.0 ] + elif iorder == 4: + coef[0] = [ 25.0/12.0, -23.0/12.0, 13.0/12.0, -1.0/4.0 ] + coef[1] = [ 1.0/4.0, 13.0/12.0, -5.0/12.0, 1.0/12.0 ] + coef[2] = [ -1.0/12.0, 7.0/12.0, 7.0/12.0, -1.0/12.0 ] + coef[3] = [ 1.0/12.0, -5.0/12.0, 13.0/12.0, 1.0/4.0 ] + coef[4] = [ -1.0/4.0, 13.0/12.0, -23.0/12.0, 25.0/12.0 ] + elif iorder == 5: + coef[0] = [ 137.0/60.0, -163.0/60.0, 137.0/60.0, -21.0/20.0, 1.0/5.0 ] + coef[1] = [ 1.0/5.0, 77.0/60.0, -43.0/60.0, 17.0/60.0, -1.0/20.0 ] + coef[2] = [ -1.0/20.0, 9.0/20.0, 47.0/60.0, -13.0/60.0, 1.0/30.0 ] + coef[3] = [ 1.0/30.0, -13.0/60.0, 47.0/60.0, 9.0/20.0, -1.0/20.0 ] + coef[4] = [ -1.0/20.0, 17.0/60.0, -43.0/60.0, 77.0/60.0, 1.0/5.0 ] + coef[5] = [ 1.0/5.0, -21.0/20.0, 137.0/60.0, -163.0/60.0, 137.0/60.0 ] + elif iorder == 6: + coef[0] = [ 49.0/20.0, -71.0/20.0, 79.0/20.0, -163.0/60.0, 31.0/30.0, -1.0/6.0 ] + coef[1] = [ 1.0/6.0, 29.0/20.0, -21.0/20.0, 37.0/60.0, -13.0/60.0, 1.0/30.0 ] + coef[2] = [ -1.0/30.0, 11.0/30.0, 19.0/20.0, -23.0/60.0, 7.0/60.0, -1.0/60.0 ] + coef[3] = [ 1.0/60.0, -2.0/15.0, 37.0/60.0, 37.0/60.0, -2.0/15.0, 1.0/60.0 ] + coef[4] = [ -1.0/60.0, 7.0/60.0, -23.0/60.0, 19.0/20.0, 11.0/30.0, -1.0/30.0 ] + coef[5] = [ 1.0/30.0, -13.0/60.0, 37.0/60.0, -21.0/20.0, 29.0/20.0, 1.0/6.0 ] + coef[6] = [ -1.0/6.0, 31.0/30.0, -163.0/60.0, 79.0/20.0, -71.0/20.0, 49.0/20.0 ] + elif iorder == 7: + coef[0] = [ 363.0/140.0, -617.0/140.0, 853.0/140.0, -2341.0/420.0, 667.0/210.0, -43.0/42.0, 1.0/7.0 ] + coef[1] = [ 1.0/7.0, 223.0/140.0, -197.0/140.0, 153.0/140.0, -241.0/420.0, 37.0/210.0, -1.0/42.0 ] + coef[2] = [ -1.0/42.0, 13.0/42.0, 153.0/140.0, -241.0/420.0, 109.0/420.0, -31.0/420.0, 1.0/105.0 ] + coef[3] = [ 1.0/105.0, -19.0/210.0, 107.0/210.0, 319.0/420.0, -101.0/420.0, 5.0/84.0, -1.0/140.0 ] + coef[4] = [ -1.0/140.0, 5.0/84.0, -101.0/420.0, 319.0/420.0, 107.0/210.0, -19.0/210.0, 1.0/105.0 ] + coef[5] = [ 1.0/105.0, -31.0/420.0, 109.0/420.0, -241.0/420.0, 153.0/140.0, 13.0/42.0, -1.0/42.0 ] + coef[6] = [ -1.0/42.0, 37.0/210.0, -241.0/420.0, 153.0/140.0, -197.0/140.0, 223.0/140.0, 1.0/7.0 ] + coef[7] = [ 1.0/7.0, -43.0/42.0, 667.0/210.0, -2341.0/420.0, 853.0/140.0, -617.0/140.0, 363.0/140.0 ] + +def init_field(eno): + for i in range(eno.ist, eno.ied + 1): + j = i - eno.ist + if 0.5 <= eno.mesh.xcc[j] <= 1.0: + eno.u[i] = 2.0 + else: + eno.u[i] = 1.0 + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def runge_kutta(eno): + rk = eno.solver.rk + if rk == 1: + runge_kutta_1(eno) + elif rk == 2: + runge_kutta_2(eno) + else: + runge_kutta_3(eno) + +def runge_kutta_1(eno): + dt = eno.solver.dt + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = eno.u[j] + dt * eno.res[i] + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def runge_kutta_2(eno): + dt = eno.solver.dt + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = eno.u[j] + dt * eno.res[i] + boundary(eno.u, eno) + + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = 0.5 * eno.un[j] + 0.5 * eno.u[j] + 0.5 * dt * eno.res[i] + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def runge_kutta_3(eno): + dt = eno.solver.dt + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = eno.u[j] + dt * eno.res[i] + boundary(eno.u, eno) + + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = 0.75 * eno.un[j] + 0.25 * eno.u[j] + 0.25 * dt * eno.res[i] + boundary(eno.u, eno) + + residual(eno.u, eno) + c1, c2, c3 = 1.0/3.0, 2.0/3.0, 2.0/3.0 + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = c1 * eno.un[j] + c2 * eno.u[j] + c3 * dt * eno.res[i] + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def get_ordinal_numbers(order): + if order == 1: + return 'st' + elif order == 2: + return 'nd' + elif order == 3: + return 'rd' + else: + return 'th' + +def visualize(eno): + with open('solution.plt', 'w') as f: + for i in range(eno.ist, eno.ied + 1): + j = i - eno.ist + f.write(f"{eno.xcc[j]:20.10e}{eno.u[i]:20.10e}\n") + + # 可视化 + u_numerical = np.copy(eno.u[eno.ist:eno.ied+1]) + print(f'u_numerical.size={u_numerical.size}') + print(f'eno.xcc.size={eno.xcc.size}') + #计算理论解 + u_analytical = analytical_solution(eno.mesh.xcc, eno.T, eno.c, eno.L) + print(f'u_analytical.size={u_analytical.size}') + plt.figure("OneFLOW-CFD Solver", figsize=(10, 6)) + plt.scatter(eno.xcc, u_numerical, facecolor="none", edgecolor="blue", s=20, linewidths=0.5, label=f'Numerical (Rusanov)') + plt.plot(eno.xcc, u_analytical, 'r--', label='Analytical') + plt.xlabel('x') + plt.ylabel('u') + ordinal1 = get_ordinal_numbers(eno.iorder) + ordinal2 = get_ordinal_numbers(eno.rk) + plt.title(f'1D Convection Equation at t = {eno.T:.3f} using {eno.iorder}{ordinal1}-order ENO and {eno.rk}{ordinal2}-order Runge-Kutta methods') + plt.legend() + plt.grid(True, color='gray', linestyle='--', linewidth=0.5, alpha=0.7) + plt.tight_layout() + plt.show() + +class Mesh: + def __init__(self): + self.nx = 40 + self.L = 2.0 + self.x = np.zeros(self.nx + 1) + self.xcc = np.zeros(self.nx) + self.init_mesh() + def init_mesh(self): + xstart = 0.0 + xend = self.L + self.dx = (xend - xstart) / self.nx + + for i in range(0, self.nx+1): + self.x[i] = xstart + i * self.dx + + for i in range(0, self.nx): + self.xcc[i] = 0.5 * (self.x[i] + self.x[i + 1]) + +class Solver: + def __init__(self): + self.iflux = 0 + self.rk = 1 + self.c = 1.0 + self.T = 0.625 + self.dt = .0025 + +class Eno: + def __init__(self, solver, mesh, iorder): + self.solver = solver + self.mesh = mesh + self.nx = mesh.nx + self.iorder = iorder + self.ighost = iorder + self.ishift = self.ighost + 1 + self.ist = 0 + self.ishift + self.ied = self.nx - 1 + self.ishift + self.ntcell = self.nx + 2 * self.ishift + self.isize = iorder * (iorder + 1) + + self.il = np.zeros(self.nx + 1, dtype=int) + self.ir = np.zeros(self.nx + 1, dtype=int) + self.coef = np.zeros((iorder + 1, iorder)) + self.dd = np.zeros((iorder, self.ntcell)) + self.up1_2m = np.zeros(self.nx + 1) + self.up1_2p = np.zeros(self.nx + 1) + self.flux = np.zeros(self.nx + 1) + self.res = np.zeros(self.nx) + + # Field module variables + self.u = np.zeros(self.ntcell) + self.un = np.zeros(self.ntcell) + + #self.dt = .0025 + +def plot_eno_OrderAnalysis(solver, xcc, u_list, u_analytical): + # 定义一个包含不同颜色、线形和标记的列表 + styles = [ + {'color': 'black', 'linestyle': '-', 'marker': 'o'}, + {'color': 'blue', 'linestyle': '--', 'marker': 's'}, + {'color': 'black', 'linestyle': '-', 'marker': '^'}, + {'color': 'blue', 'linestyle': '--', 'marker': 'v'}, + {'color': 'black', 'linestyle': '-', 'marker': '<'}, + {'color': 'blue', 'linestyle': '--', 'marker': '>'}, + {'color': 'black', 'linestyle': '-', 'marker': 'D'}, + ] + + n = len(u_list) + num_styles = len(styles) + ordinal = get_ordinal_numbers(solver.rk) + + plt.figure("OneFLOW-CFD Solver", figsize=(10, 6)) + plt.title(f'1D Convection Equation at t = {solver.T:.3f} using [1-7]th-order ENO and {solver.rk}{ordinal}-order Runge-Kutta methods') + for i in range(0, n): + lable = 'Numerical (Rusanov)ENO' + str(i+1) + style = styles[i % num_styles] + plt.plot(xcc, u_list[i], marker=style['marker'], markerfacecolor='none', linestyle=style['linestyle'], color=style['color'], \ + markersize=5, linewidth=0.5, alpha=1.0, label=f'{lable}') + plt.plot(xcc, u_analytical, 'r--', label='Analytical') + plt.xlabel('x') + plt.ylabel('u') + plt.legend() + plt.grid(True, color='gray', linestyle='--', linewidth=0.5, alpha=0.7) + plt.tight_layout() + plt.show() + +def plot_eno_TimestepAnalysis(solver, xcc, u_list, u_analytical, dt_list, iorder): + # 定义一个包含不同颜色、线形和标记的列表 + styles = [ + {'color': 'black', 'linestyle': '-', 'marker': 'o'}, + {'color': 'blue', 'linestyle': '--', 'marker': 's'}, + {'color': 'black', 'linestyle': '-', 'marker': '^'}, + {'color': 'blue', 'linestyle': '--', 'marker': 'v'}, + {'color': 'black', 'linestyle': '-', 'marker': '<'}, + {'color': 'blue', 'linestyle': '--', 'marker': '>'}, + {'color': 'black', 'linestyle': '-', 'marker': 'D'}, + {'color': 'blue', 'linestyle': '--', 'marker': 'o'}, + {'color': 'black', 'linestyle': '-', 'marker': 's'}, + {'color': 'blue', 'linestyle': '--', 'marker': '^'}, + {'color': 'black', 'linestyle': '-', 'marker': 'v'}, + {'color': 'blue', 'linestyle': '--', 'marker': '<'}, + {'color': 'black', 'linestyle': '-', 'marker': '>'}, + {'color': 'blue', 'linestyle': '--', 'marker': 'D'}, + ] + + n = len(u_list) + num_styles = len(styles) + + ordinalENO = get_ordinal_numbers(iorder) + ordinalRK = get_ordinal_numbers(solver.rk) + + plt.figure("OneFLOW-CFD Solver", figsize=(10, 6)) + plt.title(f'1D Convection Equation at t = {solver.T:.3f} using {iorder}{ordinalENO}-order ENO and {solver.rk}{ordinalRK}-order Runge-Kutta methods') + for i in range(0, n): + lable = 'Numerical (Rusanov)ENO' + str(iorder) + ' T='+str(dt_list[i]) + style = styles[i % num_styles] + plt.plot(xcc, u_list[i], marker=style['marker'], markerfacecolor='none', linestyle=style['linestyle'], color=style['color'], \ + markersize=5, linewidth=1.0, alpha=1.0, label=f'{lable}') + plt.plot(xcc, u_analytical, 'r--', label='Analytical') + plt.xlabel('x') + plt.ylabel('u') + plt.legend() + plt.grid(True, color='gray', linestyle='--', linewidth=0.5, alpha=0.7) + plt.tight_layout() + plt.show() + +def RunEno(solver, mesh, iorder): + eno = Eno(solver, mesh, iorder) + init_coef(eno.iorder, eno.coef) + init_field(eno) + + simu_time = solver.T + t = 0.0 + dt = solver.dt + while t < simu_time: + runge_kutta(eno) + if t + dt > simu_time: + dt = simu_time - t + t += dt + #print(f'T={t:.3f},runge_kutta{solver.rk},ENO{eno.iorder},{fluxnames[solver.iflux]} FLUX') + #visualize(eno) + return np.copy(eno.u[eno.ist:eno.ied+1]) + +def performEnoOrderAnalysis(): + iorder_max = 7 + mesh = Mesh() + solver = Solver() + #计算理论解 + u_analytical = analytical_solution(mesh.xcc, solver.T, solver.c, mesh.L) + + u_list = [] + for iorder in range(1, iorder_max+1): + u = RunEno(solver, mesh, iorder) + u_list.append(u) + + plot_eno_OrderAnalysis(solver, mesh.xcc, u_list, u_analytical) + +def performEnoTimestepAnalysis(): + mesh = Mesh() + solver = Solver() + #计算理论解 + u_analytical = analytical_solution(mesh.xcc, solver.T, solver.c, mesh.L) + + u_list = [] + dt_list = [] + solver.dt = 0.025 + #solver.dt = 0.025/16 + n = 12 + solver.rk = 1 + iorder = 5 + for i in range(0, n): + u = RunEno(solver, mesh, iorder) + u_list.append(u) + dt_list.append(solver.dt) + print(f'i={i+1},N={n},T={solver.T:.3f},dt={solver.dt},nt={int(solver.T/solver.dt)},runge_kutta{solver.rk},ENO{iorder},{fluxnames[solver.iflux]} FLUX') + solver.dt /= 2 + + plot_eno_TimestepAnalysis(solver, mesh.xcc, u_list, u_analytical, dt_list, iorder) + +def main(): + #performEnoOrderAnalysis() + performEnoTimestepAnalysis() + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/example/1d-linear-convection/eno/rusanov/timestep/rk1-eno/eno5/01/plot.py b/example/1d-linear-convection/eno/rusanov/timestep/rk1-eno/eno5/01/plot.py new file mode 100644 index 00000000..e389044c --- /dev/null +++ b/example/1d-linear-convection/eno/rusanov/timestep/rk1-eno/eno5/01/plot.py @@ -0,0 +1,53 @@ +import numpy as np +import matplotlib.pyplot as plt +import csv +import sys + +nvar = len(sys.argv) +print('nvar=',nvar) +print('sys.argv=',sys.argv) + +order = 1 +if nvar >= 2: + var = sys.argv[1] + print('var=',var) + order = int(var) + +print('order=',order) + +x_list = [] +u_list = [] + +with open('solution.plt', newline='') as csvfile: + #readCSV = csv.reader(csvfile, delimiter= ' ') + icount = 0 + for line in csvfile: + # 去除首尾空格,按连续空格分割 + row = line.strip().split() + #print("row=",row) + x_list.append(row[0]) + u_list.append(row[1]) + icount += 1 + +ni = icount +print("ni=",ni) + +#print("x_list=",x_list) + +x = np.zeros( ni ) +u = np.zeros( ni ) + +for i in range(0, ni): + x[i] = float(x_list[i]) + u[i] = float(u_list[i]) + +labelname = 'Eno' + str(order) + +plt.figure("OneFLOW-CFD Solver", figsize=(8, 6), dpi=100) +plt.plot(x, u, "b-", linewidth=1.0, marker = 's', markerfacecolor='None', label=labelname) +plt.xlabel("$x$") +plt.ylabel("$u$") +plt.title("burgers T=1") +plt.legend() +plt.tight_layout() +plt.show(); \ No newline at end of file diff --git a/example/1d-linear-convection/eno/rusanov/timestep/rk1-eno/eno6/01/eno.py b/example/1d-linear-convection/eno/rusanov/timestep/rk1-eno/eno6/01/eno.py new file mode 100644 index 00000000..4c40b5cf --- /dev/null +++ b/example/1d-linear-convection/eno/rusanov/timestep/rk1-eno/eno6/01/eno.py @@ -0,0 +1,426 @@ +import numpy as np +import matplotlib.pyplot as plt + +# 初始条件 +def initial_condition(x): + u0 = np.zeros_like(x) + for i in range(len(x)): + if 0.5 <= x[i] <= 1.0: + u0[i] = 2.0 + else: + u0[i] = 1.0 + return u0 + +# 理论解 +def analytical_solution(x, t, a, L): + # 初始条件沿 x - at 平移 + x_shifted = x - a * t + return initial_condition((x_shifted + L) % L) # 周期边界条件 + +def residual(q, eno): + reconstruction(q, eno) + inviscid_flux(eno.up1_2m, eno.up1_2p, eno.flux, eno) + for i in range(eno.nx): + eno.res[i] = -(eno.flux[i + 1] - eno.flux[i]) / eno.mesh.dx + +def reconstruction(q, eno): + # Choose the stencil by ENO method + eno.dd[0, 0:eno.ntcell-1] = q[0:eno.ntcell-1] + + for m in range(1, eno.iorder): + for j in range(0, eno.ntcell-1): + eno.dd[m, j] = eno.dd[m-1, j+1] - eno.dd[m-1, j] + + for i in range(eno.nx + 1): + eno.il[i] = i - 1 + for m in range(1, eno.iorder): + if abs(eno.dd[m, eno.il[i]-1+eno.ishift]) <= abs(eno.dd[m, eno.il[i]+eno.ishift]): + eno.il[i] -= 1 + + for i in range(eno.nx + 1): + eno.ir[i] = i + for m in range(1, eno.iorder): + if abs(eno.dd[m, eno.ir[i]-1+eno.ishift]) <= abs(eno.dd[m, eno.ir[i]+eno.ishift]): + eno.ir[i] -= 1 + + # Reconstruction u(j+1/2) + for i in range(eno.nx + 1): + k1 = eno.il[i] + k2 = eno.ir[i] + l1 = i - k1 + l2 = i - k2 + eno.up1_2m[i] = 0 + eno.up1_2p[i] = 0 + for m in range(eno.iorder): + eno.up1_2m[i] += q[k1 + eno.ishift + m] * eno.coef[l1, m] + eno.up1_2p[i] += q[k2 + eno.ishift + m] * eno.coef[l2, m] + +fluxnames = [ + 'Rusanov', + 'Engquist-Osher', +] + +def inviscid_flux(up1_2m, up1_2p, flux, eno): + if eno.solver.iflux == 0: + rusanov_flux(up1_2m, up1_2p, flux, eno) + else: + engquist_osher_flux(up1_2m, up1_2p, flux, eno) + +def engquist_osher_flux(up1_2m, up1_2p, flux, eno): + for i in range(eno.nx + 1): + u_L = up1_2m[i] + u_R = up1_2p[i] + + cp = 0.5 * ( eno.solver.c + abs(eno.solver.c) ) + cm = 0.5 * ( eno.solver.c - abs(eno.solver.c) ) + + flux[i] = cp * u_L + cm * u_R + +def rusanov_flux(up1_2m, up1_2p, flux, eno): + for i in range(eno.nx + 1): + u_L = up1_2m[i] + u_R = up1_2p[i] + F_L = eno.solver.c * u_L # 左状态通量 + F_R = eno.solver.c * u_R # 右状态通量 + alpha = abs(eno.solver.c) # 最大波速 + flux[i] = 0.5 * (F_L + F_R) - 0.5 * alpha * (u_R - u_L) + + +def boundary(u, eno): + for i in range(-eno.ighost, 1): + u[eno.ist - 1 + i] = u[eno.ied + i] + for i in range(1, eno.ighost + 2): + u[eno.ied + i] = u[eno.ist - 1 + i] + +def update_oldfield(qn, q): + qn[:] = q[:] + +def init_coef( iorder, coef ): + if iorder == 1: + coef[0] = [1.0] + coef[1] = [1.0] + elif iorder == 2: + coef[0] = [3.0/2.0, -1.0/2.0] + coef[1] = [1.0/2.0, 1.0/2.0] + coef[2] = [-1.0/2.0, 3.0/2.0] + elif iorder == 3: + coef[0] = [ 11.0/6.0, -7.0/6.0, 1.0/3.0 ] + coef[1] = [ 1.0/3.0, 5.0/6.0, -1.0/6.0 ] + coef[2] = [ -1.0/6.0, 5.0/6.0, 1.0/3.0 ] + coef[3] = [ 1.0/3.0, -7.0/6.0, 11.0/6.0 ] + elif iorder == 4: + coef[0] = [ 25.0/12.0, -23.0/12.0, 13.0/12.0, -1.0/4.0 ] + coef[1] = [ 1.0/4.0, 13.0/12.0, -5.0/12.0, 1.0/12.0 ] + coef[2] = [ -1.0/12.0, 7.0/12.0, 7.0/12.0, -1.0/12.0 ] + coef[3] = [ 1.0/12.0, -5.0/12.0, 13.0/12.0, 1.0/4.0 ] + coef[4] = [ -1.0/4.0, 13.0/12.0, -23.0/12.0, 25.0/12.0 ] + elif iorder == 5: + coef[0] = [ 137.0/60.0, -163.0/60.0, 137.0/60.0, -21.0/20.0, 1.0/5.0 ] + coef[1] = [ 1.0/5.0, 77.0/60.0, -43.0/60.0, 17.0/60.0, -1.0/20.0 ] + coef[2] = [ -1.0/20.0, 9.0/20.0, 47.0/60.0, -13.0/60.0, 1.0/30.0 ] + coef[3] = [ 1.0/30.0, -13.0/60.0, 47.0/60.0, 9.0/20.0, -1.0/20.0 ] + coef[4] = [ -1.0/20.0, 17.0/60.0, -43.0/60.0, 77.0/60.0, 1.0/5.0 ] + coef[5] = [ 1.0/5.0, -21.0/20.0, 137.0/60.0, -163.0/60.0, 137.0/60.0 ] + elif iorder == 6: + coef[0] = [ 49.0/20.0, -71.0/20.0, 79.0/20.0, -163.0/60.0, 31.0/30.0, -1.0/6.0 ] + coef[1] = [ 1.0/6.0, 29.0/20.0, -21.0/20.0, 37.0/60.0, -13.0/60.0, 1.0/30.0 ] + coef[2] = [ -1.0/30.0, 11.0/30.0, 19.0/20.0, -23.0/60.0, 7.0/60.0, -1.0/60.0 ] + coef[3] = [ 1.0/60.0, -2.0/15.0, 37.0/60.0, 37.0/60.0, -2.0/15.0, 1.0/60.0 ] + coef[4] = [ -1.0/60.0, 7.0/60.0, -23.0/60.0, 19.0/20.0, 11.0/30.0, -1.0/30.0 ] + coef[5] = [ 1.0/30.0, -13.0/60.0, 37.0/60.0, -21.0/20.0, 29.0/20.0, 1.0/6.0 ] + coef[6] = [ -1.0/6.0, 31.0/30.0, -163.0/60.0, 79.0/20.0, -71.0/20.0, 49.0/20.0 ] + elif iorder == 7: + coef[0] = [ 363.0/140.0, -617.0/140.0, 853.0/140.0, -2341.0/420.0, 667.0/210.0, -43.0/42.0, 1.0/7.0 ] + coef[1] = [ 1.0/7.0, 223.0/140.0, -197.0/140.0, 153.0/140.0, -241.0/420.0, 37.0/210.0, -1.0/42.0 ] + coef[2] = [ -1.0/42.0, 13.0/42.0, 153.0/140.0, -241.0/420.0, 109.0/420.0, -31.0/420.0, 1.0/105.0 ] + coef[3] = [ 1.0/105.0, -19.0/210.0, 107.0/210.0, 319.0/420.0, -101.0/420.0, 5.0/84.0, -1.0/140.0 ] + coef[4] = [ -1.0/140.0, 5.0/84.0, -101.0/420.0, 319.0/420.0, 107.0/210.0, -19.0/210.0, 1.0/105.0 ] + coef[5] = [ 1.0/105.0, -31.0/420.0, 109.0/420.0, -241.0/420.0, 153.0/140.0, 13.0/42.0, -1.0/42.0 ] + coef[6] = [ -1.0/42.0, 37.0/210.0, -241.0/420.0, 153.0/140.0, -197.0/140.0, 223.0/140.0, 1.0/7.0 ] + coef[7] = [ 1.0/7.0, -43.0/42.0, 667.0/210.0, -2341.0/420.0, 853.0/140.0, -617.0/140.0, 363.0/140.0 ] + +def init_field(eno): + for i in range(eno.ist, eno.ied + 1): + j = i - eno.ist + if 0.5 <= eno.mesh.xcc[j] <= 1.0: + eno.u[i] = 2.0 + else: + eno.u[i] = 1.0 + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def runge_kutta(eno): + rk = eno.solver.rk + if rk == 1: + runge_kutta_1(eno) + elif rk == 2: + runge_kutta_2(eno) + else: + runge_kutta_3(eno) + +def runge_kutta_1(eno): + dt = eno.solver.dt + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = eno.u[j] + dt * eno.res[i] + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def runge_kutta_2(eno): + dt = eno.solver.dt + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = eno.u[j] + dt * eno.res[i] + boundary(eno.u, eno) + + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = 0.5 * eno.un[j] + 0.5 * eno.u[j] + 0.5 * dt * eno.res[i] + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def runge_kutta_3(eno): + dt = eno.solver.dt + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = eno.u[j] + dt * eno.res[i] + boundary(eno.u, eno) + + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = 0.75 * eno.un[j] + 0.25 * eno.u[j] + 0.25 * dt * eno.res[i] + boundary(eno.u, eno) + + residual(eno.u, eno) + c1, c2, c3 = 1.0/3.0, 2.0/3.0, 2.0/3.0 + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = c1 * eno.un[j] + c2 * eno.u[j] + c3 * dt * eno.res[i] + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def get_ordinal_numbers(order): + if order == 1: + return 'st' + elif order == 2: + return 'nd' + elif order == 3: + return 'rd' + else: + return 'th' + +def visualize(eno): + with open('solution.plt', 'w') as f: + for i in range(eno.ist, eno.ied + 1): + j = i - eno.ist + f.write(f"{eno.xcc[j]:20.10e}{eno.u[i]:20.10e}\n") + + # 可视化 + u_numerical = np.copy(eno.u[eno.ist:eno.ied+1]) + print(f'u_numerical.size={u_numerical.size}') + print(f'eno.xcc.size={eno.xcc.size}') + #计算理论解 + u_analytical = analytical_solution(eno.mesh.xcc, eno.T, eno.c, eno.L) + print(f'u_analytical.size={u_analytical.size}') + plt.figure("OneFLOW-CFD Solver", figsize=(10, 6)) + plt.scatter(eno.xcc, u_numerical, facecolor="none", edgecolor="blue", s=20, linewidths=0.5, label=f'Numerical (Rusanov)') + plt.plot(eno.xcc, u_analytical, 'r--', label='Analytical') + plt.xlabel('x') + plt.ylabel('u') + ordinal1 = get_ordinal_numbers(eno.iorder) + ordinal2 = get_ordinal_numbers(eno.rk) + plt.title(f'1D Convection Equation at t = {eno.T:.3f} using {eno.iorder}{ordinal1}-order ENO and {eno.rk}{ordinal2}-order Runge-Kutta methods') + plt.legend() + plt.grid(True, color='gray', linestyle='--', linewidth=0.5, alpha=0.7) + plt.tight_layout() + plt.show() + +class Mesh: + def __init__(self): + self.nx = 40 + self.L = 2.0 + self.x = np.zeros(self.nx + 1) + self.xcc = np.zeros(self.nx) + self.init_mesh() + def init_mesh(self): + xstart = 0.0 + xend = self.L + self.dx = (xend - xstart) / self.nx + + for i in range(0, self.nx+1): + self.x[i] = xstart + i * self.dx + + for i in range(0, self.nx): + self.xcc[i] = 0.5 * (self.x[i] + self.x[i + 1]) + +class Solver: + def __init__(self): + self.iflux = 0 + self.rk = 1 + self.c = 1.0 + self.T = 0.625 + self.dt = .0025 + +class Eno: + def __init__(self, solver, mesh, iorder): + self.solver = solver + self.mesh = mesh + self.nx = mesh.nx + self.iorder = iorder + self.ighost = iorder + self.ishift = self.ighost + 1 + self.ist = 0 + self.ishift + self.ied = self.nx - 1 + self.ishift + self.ntcell = self.nx + 2 * self.ishift + self.isize = iorder * (iorder + 1) + + self.il = np.zeros(self.nx + 1, dtype=int) + self.ir = np.zeros(self.nx + 1, dtype=int) + self.coef = np.zeros((iorder + 1, iorder)) + self.dd = np.zeros((iorder, self.ntcell)) + self.up1_2m = np.zeros(self.nx + 1) + self.up1_2p = np.zeros(self.nx + 1) + self.flux = np.zeros(self.nx + 1) + self.res = np.zeros(self.nx) + + # Field module variables + self.u = np.zeros(self.ntcell) + self.un = np.zeros(self.ntcell) + + #self.dt = .0025 + +def plot_eno_OrderAnalysis(solver, xcc, u_list, u_analytical): + # 定义一个包含不同颜色、线形和标记的列表 + styles = [ + {'color': 'black', 'linestyle': '-', 'marker': 'o'}, + {'color': 'blue', 'linestyle': '--', 'marker': 's'}, + {'color': 'black', 'linestyle': '-', 'marker': '^'}, + {'color': 'blue', 'linestyle': '--', 'marker': 'v'}, + {'color': 'black', 'linestyle': '-', 'marker': '<'}, + {'color': 'blue', 'linestyle': '--', 'marker': '>'}, + {'color': 'black', 'linestyle': '-', 'marker': 'D'}, + ] + + n = len(u_list) + num_styles = len(styles) + ordinal = get_ordinal_numbers(solver.rk) + + plt.figure("OneFLOW-CFD Solver", figsize=(10, 6)) + plt.title(f'1D Convection Equation at t = {solver.T:.3f} using [1-7]th-order ENO and {solver.rk}{ordinal}-order Runge-Kutta methods') + for i in range(0, n): + lable = 'Numerical (Rusanov)ENO' + str(i+1) + style = styles[i % num_styles] + plt.plot(xcc, u_list[i], marker=style['marker'], markerfacecolor='none', linestyle=style['linestyle'], color=style['color'], \ + markersize=5, linewidth=0.5, alpha=1.0, label=f'{lable}') + plt.plot(xcc, u_analytical, 'r--', label='Analytical') + plt.xlabel('x') + plt.ylabel('u') + plt.legend() + plt.grid(True, color='gray', linestyle='--', linewidth=0.5, alpha=0.7) + plt.tight_layout() + plt.show() + +def plot_eno_TimestepAnalysis(solver, xcc, u_list, u_analytical, dt_list, iorder): + # 定义一个包含不同颜色、线形和标记的列表 + styles = [ + {'color': 'black', 'linestyle': '-', 'marker': 'o'}, + {'color': 'blue', 'linestyle': '--', 'marker': 's'}, + {'color': 'black', 'linestyle': '-', 'marker': '^'}, + {'color': 'blue', 'linestyle': '--', 'marker': 'v'}, + {'color': 'black', 'linestyle': '-', 'marker': '<'}, + {'color': 'blue', 'linestyle': '--', 'marker': '>'}, + {'color': 'black', 'linestyle': '-', 'marker': 'D'}, + {'color': 'blue', 'linestyle': '--', 'marker': 'o'}, + {'color': 'black', 'linestyle': '-', 'marker': 's'}, + {'color': 'blue', 'linestyle': '--', 'marker': '^'}, + {'color': 'black', 'linestyle': '-', 'marker': 'v'}, + {'color': 'blue', 'linestyle': '--', 'marker': '<'}, + {'color': 'black', 'linestyle': '-', 'marker': '>'}, + {'color': 'blue', 'linestyle': '--', 'marker': 'D'}, + ] + + n = len(u_list) + num_styles = len(styles) + + ordinalENO = get_ordinal_numbers(iorder) + ordinalRK = get_ordinal_numbers(solver.rk) + + plt.figure("OneFLOW-CFD Solver", figsize=(10, 6)) + plt.title(f'1D Convection Equation at t = {solver.T:.3f} using {iorder}{ordinalENO}-order ENO and {solver.rk}{ordinalRK}-order Runge-Kutta methods') + for i in range(0, n): + lable = 'Numerical (Rusanov)ENO' + str(iorder) + ' T='+str(dt_list[i]) + style = styles[i % num_styles] + plt.plot(xcc, u_list[i], marker=style['marker'], markerfacecolor='none', linestyle=style['linestyle'], color=style['color'], \ + markersize=5, linewidth=1.0, alpha=1.0, label=f'{lable}') + plt.plot(xcc, u_analytical, 'r--', label='Analytical') + plt.xlabel('x') + plt.ylabel('u') + plt.legend() + plt.grid(True, color='gray', linestyle='--', linewidth=0.5, alpha=0.7) + plt.tight_layout() + plt.show() + +def RunEno(solver, mesh, iorder): + eno = Eno(solver, mesh, iorder) + init_coef(eno.iorder, eno.coef) + init_field(eno) + + simu_time = solver.T + t = 0.0 + dt = solver.dt + while t < simu_time: + runge_kutta(eno) + if t + dt > simu_time: + dt = simu_time - t + t += dt + #print(f'T={t:.3f},runge_kutta{solver.rk},ENO{eno.iorder},{fluxnames[solver.iflux]} FLUX') + #visualize(eno) + return np.copy(eno.u[eno.ist:eno.ied+1]) + +def performEnoOrderAnalysis(): + iorder_max = 7 + mesh = Mesh() + solver = Solver() + #计算理论解 + u_analytical = analytical_solution(mesh.xcc, solver.T, solver.c, mesh.L) + + u_list = [] + for iorder in range(1, iorder_max+1): + u = RunEno(solver, mesh, iorder) + u_list.append(u) + + plot_eno_OrderAnalysis(solver, mesh.xcc, u_list, u_analytical) + +def performEnoTimestepAnalysis(): + mesh = Mesh() + solver = Solver() + #计算理论解 + u_analytical = analytical_solution(mesh.xcc, solver.T, solver.c, mesh.L) + + u_list = [] + dt_list = [] + solver.dt = 0.025 + #solver.dt = 0.025/16 + n = 12 + solver.rk = 1 + iorder = 6 + for i in range(0, n): + u = RunEno(solver, mesh, iorder) + u_list.append(u) + dt_list.append(solver.dt) + print(f'i={i+1},N={n},T={solver.T:.3f},dt={solver.dt},nt={int(solver.T/solver.dt)},runge_kutta{solver.rk},ENO{iorder},{fluxnames[solver.iflux]} FLUX') + solver.dt /= 2 + + plot_eno_TimestepAnalysis(solver, mesh.xcc, u_list, u_analytical, dt_list, iorder) + +def main(): + #performEnoOrderAnalysis() + performEnoTimestepAnalysis() + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/example/1d-linear-convection/eno/rusanov/timestep/rk1-eno/eno6/01/plot.py b/example/1d-linear-convection/eno/rusanov/timestep/rk1-eno/eno6/01/plot.py new file mode 100644 index 00000000..e389044c --- /dev/null +++ b/example/1d-linear-convection/eno/rusanov/timestep/rk1-eno/eno6/01/plot.py @@ -0,0 +1,53 @@ +import numpy as np +import matplotlib.pyplot as plt +import csv +import sys + +nvar = len(sys.argv) +print('nvar=',nvar) +print('sys.argv=',sys.argv) + +order = 1 +if nvar >= 2: + var = sys.argv[1] + print('var=',var) + order = int(var) + +print('order=',order) + +x_list = [] +u_list = [] + +with open('solution.plt', newline='') as csvfile: + #readCSV = csv.reader(csvfile, delimiter= ' ') + icount = 0 + for line in csvfile: + # 去除首尾空格,按连续空格分割 + row = line.strip().split() + #print("row=",row) + x_list.append(row[0]) + u_list.append(row[1]) + icount += 1 + +ni = icount +print("ni=",ni) + +#print("x_list=",x_list) + +x = np.zeros( ni ) +u = np.zeros( ni ) + +for i in range(0, ni): + x[i] = float(x_list[i]) + u[i] = float(u_list[i]) + +labelname = 'Eno' + str(order) + +plt.figure("OneFLOW-CFD Solver", figsize=(8, 6), dpi=100) +plt.plot(x, u, "b-", linewidth=1.0, marker = 's', markerfacecolor='None', label=labelname) +plt.xlabel("$x$") +plt.ylabel("$u$") +plt.title("burgers T=1") +plt.legend() +plt.tight_layout() +plt.show(); \ No newline at end of file diff --git a/example/1d-linear-convection/eno/rusanov/timestep/rk1-eno/eno7/01/eno.py b/example/1d-linear-convection/eno/rusanov/timestep/rk1-eno/eno7/01/eno.py new file mode 100644 index 00000000..ea5b8758 --- /dev/null +++ b/example/1d-linear-convection/eno/rusanov/timestep/rk1-eno/eno7/01/eno.py @@ -0,0 +1,426 @@ +import numpy as np +import matplotlib.pyplot as plt + +# 初始条件 +def initial_condition(x): + u0 = np.zeros_like(x) + for i in range(len(x)): + if 0.5 <= x[i] <= 1.0: + u0[i] = 2.0 + else: + u0[i] = 1.0 + return u0 + +# 理论解 +def analytical_solution(x, t, a, L): + # 初始条件沿 x - at 平移 + x_shifted = x - a * t + return initial_condition((x_shifted + L) % L) # 周期边界条件 + +def residual(q, eno): + reconstruction(q, eno) + inviscid_flux(eno.up1_2m, eno.up1_2p, eno.flux, eno) + for i in range(eno.nx): + eno.res[i] = -(eno.flux[i + 1] - eno.flux[i]) / eno.mesh.dx + +def reconstruction(q, eno): + # Choose the stencil by ENO method + eno.dd[0, 0:eno.ntcell-1] = q[0:eno.ntcell-1] + + for m in range(1, eno.iorder): + for j in range(0, eno.ntcell-1): + eno.dd[m, j] = eno.dd[m-1, j+1] - eno.dd[m-1, j] + + for i in range(eno.nx + 1): + eno.il[i] = i - 1 + for m in range(1, eno.iorder): + if abs(eno.dd[m, eno.il[i]-1+eno.ishift]) <= abs(eno.dd[m, eno.il[i]+eno.ishift]): + eno.il[i] -= 1 + + for i in range(eno.nx + 1): + eno.ir[i] = i + for m in range(1, eno.iorder): + if abs(eno.dd[m, eno.ir[i]-1+eno.ishift]) <= abs(eno.dd[m, eno.ir[i]+eno.ishift]): + eno.ir[i] -= 1 + + # Reconstruction u(j+1/2) + for i in range(eno.nx + 1): + k1 = eno.il[i] + k2 = eno.ir[i] + l1 = i - k1 + l2 = i - k2 + eno.up1_2m[i] = 0 + eno.up1_2p[i] = 0 + for m in range(eno.iorder): + eno.up1_2m[i] += q[k1 + eno.ishift + m] * eno.coef[l1, m] + eno.up1_2p[i] += q[k2 + eno.ishift + m] * eno.coef[l2, m] + +fluxnames = [ + 'Rusanov', + 'Engquist-Osher', +] + +def inviscid_flux(up1_2m, up1_2p, flux, eno): + if eno.solver.iflux == 0: + rusanov_flux(up1_2m, up1_2p, flux, eno) + else: + engquist_osher_flux(up1_2m, up1_2p, flux, eno) + +def engquist_osher_flux(up1_2m, up1_2p, flux, eno): + for i in range(eno.nx + 1): + u_L = up1_2m[i] + u_R = up1_2p[i] + + cp = 0.5 * ( eno.solver.c + abs(eno.solver.c) ) + cm = 0.5 * ( eno.solver.c - abs(eno.solver.c) ) + + flux[i] = cp * u_L + cm * u_R + +def rusanov_flux(up1_2m, up1_2p, flux, eno): + for i in range(eno.nx + 1): + u_L = up1_2m[i] + u_R = up1_2p[i] + F_L = eno.solver.c * u_L # 左状态通量 + F_R = eno.solver.c * u_R # 右状态通量 + alpha = abs(eno.solver.c) # 最大波速 + flux[i] = 0.5 * (F_L + F_R) - 0.5 * alpha * (u_R - u_L) + + +def boundary(u, eno): + for i in range(-eno.ighost, 1): + u[eno.ist - 1 + i] = u[eno.ied + i] + for i in range(1, eno.ighost + 2): + u[eno.ied + i] = u[eno.ist - 1 + i] + +def update_oldfield(qn, q): + qn[:] = q[:] + +def init_coef( iorder, coef ): + if iorder == 1: + coef[0] = [1.0] + coef[1] = [1.0] + elif iorder == 2: + coef[0] = [3.0/2.0, -1.0/2.0] + coef[1] = [1.0/2.0, 1.0/2.0] + coef[2] = [-1.0/2.0, 3.0/2.0] + elif iorder == 3: + coef[0] = [ 11.0/6.0, -7.0/6.0, 1.0/3.0 ] + coef[1] = [ 1.0/3.0, 5.0/6.0, -1.0/6.0 ] + coef[2] = [ -1.0/6.0, 5.0/6.0, 1.0/3.0 ] + coef[3] = [ 1.0/3.0, -7.0/6.0, 11.0/6.0 ] + elif iorder == 4: + coef[0] = [ 25.0/12.0, -23.0/12.0, 13.0/12.0, -1.0/4.0 ] + coef[1] = [ 1.0/4.0, 13.0/12.0, -5.0/12.0, 1.0/12.0 ] + coef[2] = [ -1.0/12.0, 7.0/12.0, 7.0/12.0, -1.0/12.0 ] + coef[3] = [ 1.0/12.0, -5.0/12.0, 13.0/12.0, 1.0/4.0 ] + coef[4] = [ -1.0/4.0, 13.0/12.0, -23.0/12.0, 25.0/12.0 ] + elif iorder == 5: + coef[0] = [ 137.0/60.0, -163.0/60.0, 137.0/60.0, -21.0/20.0, 1.0/5.0 ] + coef[1] = [ 1.0/5.0, 77.0/60.0, -43.0/60.0, 17.0/60.0, -1.0/20.0 ] + coef[2] = [ -1.0/20.0, 9.0/20.0, 47.0/60.0, -13.0/60.0, 1.0/30.0 ] + coef[3] = [ 1.0/30.0, -13.0/60.0, 47.0/60.0, 9.0/20.0, -1.0/20.0 ] + coef[4] = [ -1.0/20.0, 17.0/60.0, -43.0/60.0, 77.0/60.0, 1.0/5.0 ] + coef[5] = [ 1.0/5.0, -21.0/20.0, 137.0/60.0, -163.0/60.0, 137.0/60.0 ] + elif iorder == 6: + coef[0] = [ 49.0/20.0, -71.0/20.0, 79.0/20.0, -163.0/60.0, 31.0/30.0, -1.0/6.0 ] + coef[1] = [ 1.0/6.0, 29.0/20.0, -21.0/20.0, 37.0/60.0, -13.0/60.0, 1.0/30.0 ] + coef[2] = [ -1.0/30.0, 11.0/30.0, 19.0/20.0, -23.0/60.0, 7.0/60.0, -1.0/60.0 ] + coef[3] = [ 1.0/60.0, -2.0/15.0, 37.0/60.0, 37.0/60.0, -2.0/15.0, 1.0/60.0 ] + coef[4] = [ -1.0/60.0, 7.0/60.0, -23.0/60.0, 19.0/20.0, 11.0/30.0, -1.0/30.0 ] + coef[5] = [ 1.0/30.0, -13.0/60.0, 37.0/60.0, -21.0/20.0, 29.0/20.0, 1.0/6.0 ] + coef[6] = [ -1.0/6.0, 31.0/30.0, -163.0/60.0, 79.0/20.0, -71.0/20.0, 49.0/20.0 ] + elif iorder == 7: + coef[0] = [ 363.0/140.0, -617.0/140.0, 853.0/140.0, -2341.0/420.0, 667.0/210.0, -43.0/42.0, 1.0/7.0 ] + coef[1] = [ 1.0/7.0, 223.0/140.0, -197.0/140.0, 153.0/140.0, -241.0/420.0, 37.0/210.0, -1.0/42.0 ] + coef[2] = [ -1.0/42.0, 13.0/42.0, 153.0/140.0, -241.0/420.0, 109.0/420.0, -31.0/420.0, 1.0/105.0 ] + coef[3] = [ 1.0/105.0, -19.0/210.0, 107.0/210.0, 319.0/420.0, -101.0/420.0, 5.0/84.0, -1.0/140.0 ] + coef[4] = [ -1.0/140.0, 5.0/84.0, -101.0/420.0, 319.0/420.0, 107.0/210.0, -19.0/210.0, 1.0/105.0 ] + coef[5] = [ 1.0/105.0, -31.0/420.0, 109.0/420.0, -241.0/420.0, 153.0/140.0, 13.0/42.0, -1.0/42.0 ] + coef[6] = [ -1.0/42.0, 37.0/210.0, -241.0/420.0, 153.0/140.0, -197.0/140.0, 223.0/140.0, 1.0/7.0 ] + coef[7] = [ 1.0/7.0, -43.0/42.0, 667.0/210.0, -2341.0/420.0, 853.0/140.0, -617.0/140.0, 363.0/140.0 ] + +def init_field(eno): + for i in range(eno.ist, eno.ied + 1): + j = i - eno.ist + if 0.5 <= eno.mesh.xcc[j] <= 1.0: + eno.u[i] = 2.0 + else: + eno.u[i] = 1.0 + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def runge_kutta(eno): + rk = eno.solver.rk + if rk == 1: + runge_kutta_1(eno) + elif rk == 2: + runge_kutta_2(eno) + else: + runge_kutta_3(eno) + +def runge_kutta_1(eno): + dt = eno.solver.dt + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = eno.u[j] + dt * eno.res[i] + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def runge_kutta_2(eno): + dt = eno.solver.dt + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = eno.u[j] + dt * eno.res[i] + boundary(eno.u, eno) + + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = 0.5 * eno.un[j] + 0.5 * eno.u[j] + 0.5 * dt * eno.res[i] + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def runge_kutta_3(eno): + dt = eno.solver.dt + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = eno.u[j] + dt * eno.res[i] + boundary(eno.u, eno) + + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = 0.75 * eno.un[j] + 0.25 * eno.u[j] + 0.25 * dt * eno.res[i] + boundary(eno.u, eno) + + residual(eno.u, eno) + c1, c2, c3 = 1.0/3.0, 2.0/3.0, 2.0/3.0 + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = c1 * eno.un[j] + c2 * eno.u[j] + c3 * dt * eno.res[i] + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def get_ordinal_numbers(order): + if order == 1: + return 'st' + elif order == 2: + return 'nd' + elif order == 3: + return 'rd' + else: + return 'th' + +def visualize(eno): + with open('solution.plt', 'w') as f: + for i in range(eno.ist, eno.ied + 1): + j = i - eno.ist + f.write(f"{eno.xcc[j]:20.10e}{eno.u[i]:20.10e}\n") + + # 可视化 + u_numerical = np.copy(eno.u[eno.ist:eno.ied+1]) + print(f'u_numerical.size={u_numerical.size}') + print(f'eno.xcc.size={eno.xcc.size}') + #计算理论解 + u_analytical = analytical_solution(eno.mesh.xcc, eno.T, eno.c, eno.L) + print(f'u_analytical.size={u_analytical.size}') + plt.figure("OneFLOW-CFD Solver", figsize=(10, 6)) + plt.scatter(eno.xcc, u_numerical, facecolor="none", edgecolor="blue", s=20, linewidths=0.5, label=f'Numerical (Rusanov)') + plt.plot(eno.xcc, u_analytical, 'r--', label='Analytical') + plt.xlabel('x') + plt.ylabel('u') + ordinal1 = get_ordinal_numbers(eno.iorder) + ordinal2 = get_ordinal_numbers(eno.rk) + plt.title(f'1D Convection Equation at t = {eno.T:.3f} using {eno.iorder}{ordinal1}-order ENO and {eno.rk}{ordinal2}-order Runge-Kutta methods') + plt.legend() + plt.grid(True, color='gray', linestyle='--', linewidth=0.5, alpha=0.7) + plt.tight_layout() + plt.show() + +class Mesh: + def __init__(self): + self.nx = 40 + self.L = 2.0 + self.x = np.zeros(self.nx + 1) + self.xcc = np.zeros(self.nx) + self.init_mesh() + def init_mesh(self): + xstart = 0.0 + xend = self.L + self.dx = (xend - xstart) / self.nx + + for i in range(0, self.nx+1): + self.x[i] = xstart + i * self.dx + + for i in range(0, self.nx): + self.xcc[i] = 0.5 * (self.x[i] + self.x[i + 1]) + +class Solver: + def __init__(self): + self.iflux = 0 + self.rk = 1 + self.c = 1.0 + self.T = 0.625 + self.dt = .0025 + +class Eno: + def __init__(self, solver, mesh, iorder): + self.solver = solver + self.mesh = mesh + self.nx = mesh.nx + self.iorder = iorder + self.ighost = iorder + self.ishift = self.ighost + 1 + self.ist = 0 + self.ishift + self.ied = self.nx - 1 + self.ishift + self.ntcell = self.nx + 2 * self.ishift + self.isize = iorder * (iorder + 1) + + self.il = np.zeros(self.nx + 1, dtype=int) + self.ir = np.zeros(self.nx + 1, dtype=int) + self.coef = np.zeros((iorder + 1, iorder)) + self.dd = np.zeros((iorder, self.ntcell)) + self.up1_2m = np.zeros(self.nx + 1) + self.up1_2p = np.zeros(self.nx + 1) + self.flux = np.zeros(self.nx + 1) + self.res = np.zeros(self.nx) + + # Field module variables + self.u = np.zeros(self.ntcell) + self.un = np.zeros(self.ntcell) + + #self.dt = .0025 + +def plot_eno_OrderAnalysis(solver, xcc, u_list, u_analytical): + # 定义一个包含不同颜色、线形和标记的列表 + styles = [ + {'color': 'black', 'linestyle': '-', 'marker': 'o'}, + {'color': 'blue', 'linestyle': '--', 'marker': 's'}, + {'color': 'black', 'linestyle': '-', 'marker': '^'}, + {'color': 'blue', 'linestyle': '--', 'marker': 'v'}, + {'color': 'black', 'linestyle': '-', 'marker': '<'}, + {'color': 'blue', 'linestyle': '--', 'marker': '>'}, + {'color': 'black', 'linestyle': '-', 'marker': 'D'}, + ] + + n = len(u_list) + num_styles = len(styles) + ordinal = get_ordinal_numbers(solver.rk) + + plt.figure("OneFLOW-CFD Solver", figsize=(10, 6)) + plt.title(f'1D Convection Equation at t = {solver.T:.3f} using [1-7]th-order ENO and {solver.rk}{ordinal}-order Runge-Kutta methods') + for i in range(0, n): + lable = 'Numerical (Rusanov)ENO' + str(i+1) + style = styles[i % num_styles] + plt.plot(xcc, u_list[i], marker=style['marker'], markerfacecolor='none', linestyle=style['linestyle'], color=style['color'], \ + markersize=5, linewidth=0.5, alpha=1.0, label=f'{lable}') + plt.plot(xcc, u_analytical, 'r--', label='Analytical') + plt.xlabel('x') + plt.ylabel('u') + plt.legend() + plt.grid(True, color='gray', linestyle='--', linewidth=0.5, alpha=0.7) + plt.tight_layout() + plt.show() + +def plot_eno_TimestepAnalysis(solver, xcc, u_list, u_analytical, dt_list, iorder): + # 定义一个包含不同颜色、线形和标记的列表 + styles = [ + {'color': 'black', 'linestyle': '-', 'marker': 'o'}, + {'color': 'blue', 'linestyle': '--', 'marker': 's'}, + {'color': 'black', 'linestyle': '-', 'marker': '^'}, + {'color': 'blue', 'linestyle': '--', 'marker': 'v'}, + {'color': 'black', 'linestyle': '-', 'marker': '<'}, + {'color': 'blue', 'linestyle': '--', 'marker': '>'}, + {'color': 'black', 'linestyle': '-', 'marker': 'D'}, + {'color': 'blue', 'linestyle': '--', 'marker': 'o'}, + {'color': 'black', 'linestyle': '-', 'marker': 's'}, + {'color': 'blue', 'linestyle': '--', 'marker': '^'}, + {'color': 'black', 'linestyle': '-', 'marker': 'v'}, + {'color': 'blue', 'linestyle': '--', 'marker': '<'}, + {'color': 'black', 'linestyle': '-', 'marker': '>'}, + {'color': 'blue', 'linestyle': '--', 'marker': 'D'}, + ] + + n = len(u_list) + num_styles = len(styles) + + ordinalENO = get_ordinal_numbers(iorder) + ordinalRK = get_ordinal_numbers(solver.rk) + + plt.figure("OneFLOW-CFD Solver", figsize=(10, 6)) + plt.title(f'1D Convection Equation at t = {solver.T:.3f} using {iorder}{ordinalENO}-order ENO and {solver.rk}{ordinalRK}-order Runge-Kutta methods') + for i in range(0, n): + lable = 'Numerical (Rusanov)ENO' + str(iorder) + ' T='+str(dt_list[i]) + style = styles[i % num_styles] + plt.plot(xcc, u_list[i], marker=style['marker'], markerfacecolor='none', linestyle=style['linestyle'], color=style['color'], \ + markersize=5, linewidth=1.0, alpha=1.0, label=f'{lable}') + plt.plot(xcc, u_analytical, 'r--', label='Analytical') + plt.xlabel('x') + plt.ylabel('u') + plt.legend() + plt.grid(True, color='gray', linestyle='--', linewidth=0.5, alpha=0.7) + plt.tight_layout() + plt.show() + +def RunEno(solver, mesh, iorder): + eno = Eno(solver, mesh, iorder) + init_coef(eno.iorder, eno.coef) + init_field(eno) + + simu_time = solver.T + t = 0.0 + dt = solver.dt + while t < simu_time: + runge_kutta(eno) + if t + dt > simu_time: + dt = simu_time - t + t += dt + #print(f'T={t:.3f},runge_kutta{solver.rk},ENO{eno.iorder},{fluxnames[solver.iflux]} FLUX') + #visualize(eno) + return np.copy(eno.u[eno.ist:eno.ied+1]) + +def performEnoOrderAnalysis(): + iorder_max = 7 + mesh = Mesh() + solver = Solver() + #计算理论解 + u_analytical = analytical_solution(mesh.xcc, solver.T, solver.c, mesh.L) + + u_list = [] + for iorder in range(1, iorder_max+1): + u = RunEno(solver, mesh, iorder) + u_list.append(u) + + plot_eno_OrderAnalysis(solver, mesh.xcc, u_list, u_analytical) + +def performEnoTimestepAnalysis(): + mesh = Mesh() + solver = Solver() + #计算理论解 + u_analytical = analytical_solution(mesh.xcc, solver.T, solver.c, mesh.L) + + u_list = [] + dt_list = [] + solver.dt = 0.025/2 + #solver.dt = 0.025/16 + n = 12 + solver.rk = 1 + iorder = 7 + for i in range(0, n): + u = RunEno(solver, mesh, iorder) + u_list.append(u) + dt_list.append(solver.dt) + print(f'i={i+1},N={n},T={solver.T:.3f},dt={solver.dt},nt={int(solver.T/solver.dt)},runge_kutta{solver.rk},ENO{iorder},{fluxnames[solver.iflux]} FLUX') + solver.dt /= 2 + + plot_eno_TimestepAnalysis(solver, mesh.xcc, u_list, u_analytical, dt_list, iorder) + +def main(): + #performEnoOrderAnalysis() + performEnoTimestepAnalysis() + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/example/1d-linear-convection/eno/rusanov/timestep/rk1-eno/eno7/01/plot.py b/example/1d-linear-convection/eno/rusanov/timestep/rk1-eno/eno7/01/plot.py new file mode 100644 index 00000000..e389044c --- /dev/null +++ b/example/1d-linear-convection/eno/rusanov/timestep/rk1-eno/eno7/01/plot.py @@ -0,0 +1,53 @@ +import numpy as np +import matplotlib.pyplot as plt +import csv +import sys + +nvar = len(sys.argv) +print('nvar=',nvar) +print('sys.argv=',sys.argv) + +order = 1 +if nvar >= 2: + var = sys.argv[1] + print('var=',var) + order = int(var) + +print('order=',order) + +x_list = [] +u_list = [] + +with open('solution.plt', newline='') as csvfile: + #readCSV = csv.reader(csvfile, delimiter= ' ') + icount = 0 + for line in csvfile: + # 去除首尾空格,按连续空格分割 + row = line.strip().split() + #print("row=",row) + x_list.append(row[0]) + u_list.append(row[1]) + icount += 1 + +ni = icount +print("ni=",ni) + +#print("x_list=",x_list) + +x = np.zeros( ni ) +u = np.zeros( ni ) + +for i in range(0, ni): + x[i] = float(x_list[i]) + u[i] = float(u_list[i]) + +labelname = 'Eno' + str(order) + +plt.figure("OneFLOW-CFD Solver", figsize=(8, 6), dpi=100) +plt.plot(x, u, "b-", linewidth=1.0, marker = 's', markerfacecolor='None', label=labelname) +plt.xlabel("$x$") +plt.ylabel("$u$") +plt.title("burgers T=1") +plt.legend() +plt.tight_layout() +plt.show(); \ No newline at end of file diff --git a/example/1d-linear-convection/eno/rusanov/timestep/rk1-eno1/01/eno.py b/example/1d-linear-convection/eno/rusanov/timestep/rk1-eno1/01/eno.py new file mode 100644 index 00000000..b9bda0d6 --- /dev/null +++ b/example/1d-linear-convection/eno/rusanov/timestep/rk1-eno1/01/eno.py @@ -0,0 +1,360 @@ +import numpy as np +import matplotlib.pyplot as plt + +# 初始条件 +def initial_condition(x): + u0 = np.zeros_like(x) + for i in range(len(x)): + if 0.5 <= x[i] <= 1.0: + u0[i] = 2.0 + else: + u0[i] = 1.0 + return u0 + +# 理论解 +def analytical_solution(x, t, a, L): + # 初始条件沿 x - at 平移 + x_shifted = x - a * t + return initial_condition((x_shifted + L) % L) # 周期边界条件 + +def residual(q, eno): + reconstruction(q, eno) + inviscid_flux(eno.up1_2m, eno.up1_2p, eno.flux, eno) + for i in range(eno.nx): + eno.res[i] = -(eno.flux[i + 1] - eno.flux[i]) / eno.mesh.dx + +def reconstruction(q, eno): + # Choose the stencil by ENO method + eno.dd[0, 0:eno.ntcell-1] = q[0:eno.ntcell-1] + + for m in range(1, eno.iorder): + for j in range(0, eno.ntcell-1): + eno.dd[m, j] = eno.dd[m-1, j+1] - eno.dd[m-1, j] + + for i in range(eno.nx + 1): + eno.il[i] = i - 1 + for m in range(1, eno.iorder): + if abs(eno.dd[m, eno.il[i]-1+eno.ishift]) <= abs(eno.dd[m, eno.il[i]+eno.ishift]): + eno.il[i] -= 1 + + for i in range(eno.nx + 1): + eno.ir[i] = i + for m in range(1, eno.iorder): + if abs(eno.dd[m, eno.ir[i]-1+eno.ishift]) <= abs(eno.dd[m, eno.ir[i]+eno.ishift]): + eno.ir[i] -= 1 + + # Reconstruction u(j+1/2) + for i in range(eno.nx + 1): + k1 = eno.il[i] + k2 = eno.ir[i] + l1 = i - k1 + l2 = i - k2 + eno.up1_2m[i] = 0 + eno.up1_2p[i] = 0 + for m in range(eno.iorder): + eno.up1_2m[i] += q[k1 + eno.ishift + m] * eno.coef[l1, m] + eno.up1_2p[i] += q[k2 + eno.ishift + m] * eno.coef[l2, m] + +fluxnames = [ + 'Rusanov', + 'Engquist-Osher', +] + +def inviscid_flux(up1_2m, up1_2p, flux, eno): + if eno.solver.iflux == 0: + rusanov_flux(up1_2m, up1_2p, flux, eno) + else: + engquist_osher_flux(up1_2m, up1_2p, flux, eno) + +def engquist_osher_flux(up1_2m, up1_2p, flux, eno): + for i in range(eno.nx + 1): + u_L = up1_2m[i] + u_R = up1_2p[i] + + cp = 0.5 * ( eno.solver.c + abs(eno.solver.c) ) + cm = 0.5 * ( eno.solver.c - abs(eno.solver.c) ) + + flux[i] = cp * u_L + cm * u_R + +def rusanov_flux(up1_2m, up1_2p, flux, eno): + for i in range(eno.nx + 1): + u_L = up1_2m[i] + u_R = up1_2p[i] + F_L = eno.solver.c * u_L # 左状态通量 + F_R = eno.solver.c * u_R # 右状态通量 + alpha = abs(eno.solver.c) # 最大波速 + flux[i] = 0.5 * (F_L + F_R) - 0.5 * alpha * (u_R - u_L) + + +def boundary(u, eno): + for i in range(-eno.ighost, 1): + u[eno.ist - 1 + i] = u[eno.ied + i] + for i in range(1, eno.ighost + 2): + u[eno.ied + i] = u[eno.ist - 1 + i] + +def update_oldfield(qn, q): + qn[:] = q[:] + +def init_coef( iorder, coef ): + if iorder == 1: + coef[0] = [1.0] + coef[1] = [1.0] + elif iorder == 2: + coef[0] = [3.0/2.0, -1.0/2.0] + coef[1] = [1.0/2.0, 1.0/2.0] + coef[2] = [-1.0/2.0, 3.0/2.0] + elif iorder == 3: + coef[0] = [ 11.0/6.0, -7.0/6.0, 1.0/3.0 ] + coef[1] = [ 1.0/3.0, 5.0/6.0, -1.0/6.0 ] + coef[2] = [ -1.0/6.0, 5.0/6.0, 1.0/3.0 ] + coef[3] = [ 1.0/3.0, -7.0/6.0, 11.0/6.0 ] + elif iorder == 4: + coef[0] = [ 25.0/12.0, -23.0/12.0, 13.0/12.0, -1.0/4.0 ] + coef[1] = [ 1.0/4.0, 13.0/12.0, -5.0/12.0, 1.0/12.0 ] + coef[2] = [ -1.0/12.0, 7.0/12.0, 7.0/12.0, -1.0/12.0 ] + coef[3] = [ 1.0/12.0, -5.0/12.0, 13.0/12.0, 1.0/4.0 ] + coef[4] = [ -1.0/4.0, 13.0/12.0, -23.0/12.0, 25.0/12.0 ] + elif iorder == 5: + coef[0] = [ 137.0/60.0, -163.0/60.0, 137.0/60.0, -21.0/20.0, 1.0/5.0 ] + coef[1] = [ 1.0/5.0, 77.0/60.0, -43.0/60.0, 17.0/60.0, -1.0/20.0 ] + coef[2] = [ -1.0/20.0, 9.0/20.0, 47.0/60.0, -13.0/60.0, 1.0/30.0 ] + coef[3] = [ 1.0/30.0, -13.0/60.0, 47.0/60.0, 9.0/20.0, -1.0/20.0 ] + coef[4] = [ -1.0/20.0, 17.0/60.0, -43.0/60.0, 77.0/60.0, 1.0/5.0 ] + coef[5] = [ 1.0/5.0, -21.0/20.0, 137.0/60.0, -163.0/60.0, 137.0/60.0 ] + elif iorder == 6: + coef[0] = [ 49.0/20.0, -71.0/20.0, 79.0/20.0, -163.0/60.0, 31.0/30.0, -1.0/6.0 ] + coef[1] = [ 1.0/6.0, 29.0/20.0, -21.0/20.0, 37.0/60.0, -13.0/60.0, 1.0/30.0 ] + coef[2] = [ -1.0/30.0, 11.0/30.0, 19.0/20.0, -23.0/60.0, 7.0/60.0, -1.0/60.0 ] + coef[3] = [ 1.0/60.0, -2.0/15.0, 37.0/60.0, 37.0/60.0, -2.0/15.0, 1.0/60.0 ] + coef[4] = [ -1.0/60.0, 7.0/60.0, -23.0/60.0, 19.0/20.0, 11.0/30.0, -1.0/30.0 ] + coef[5] = [ 1.0/30.0, -13.0/60.0, 37.0/60.0, -21.0/20.0, 29.0/20.0, 1.0/6.0 ] + coef[6] = [ -1.0/6.0, 31.0/30.0, -163.0/60.0, 79.0/20.0, -71.0/20.0, 49.0/20.0 ] + elif iorder == 7: + coef[0] = [ 363.0/140.0, -617.0/140.0, 853.0/140.0, -2341.0/420.0, 667.0/210.0, -43.0/42.0, 1.0/7.0 ] + coef[1] = [ 1.0/7.0, 223.0/140.0, -197.0/140.0, 153.0/140.0, -241.0/420.0, 37.0/210.0, -1.0/42.0 ] + coef[2] = [ -1.0/42.0, 13.0/42.0, 153.0/140.0, -241.0/420.0, 109.0/420.0, -31.0/420.0, 1.0/105.0 ] + coef[3] = [ 1.0/105.0, -19.0/210.0, 107.0/210.0, 319.0/420.0, -101.0/420.0, 5.0/84.0, -1.0/140.0 ] + coef[4] = [ -1.0/140.0, 5.0/84.0, -101.0/420.0, 319.0/420.0, 107.0/210.0, -19.0/210.0, 1.0/105.0 ] + coef[5] = [ 1.0/105.0, -31.0/420.0, 109.0/420.0, -241.0/420.0, 153.0/140.0, 13.0/42.0, -1.0/42.0 ] + coef[6] = [ -1.0/42.0, 37.0/210.0, -241.0/420.0, 153.0/140.0, -197.0/140.0, 223.0/140.0, 1.0/7.0 ] + coef[7] = [ 1.0/7.0, -43.0/42.0, 667.0/210.0, -2341.0/420.0, 853.0/140.0, -617.0/140.0, 363.0/140.0 ] + +def init_field(eno): + for i in range(eno.ist, eno.ied + 1): + j = i - eno.ist + if 0.5 <= eno.mesh.xcc[j] <= 1.0: + eno.u[i] = 2.0 + else: + eno.u[i] = 1.0 + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def runge_kutta(eno): + rk = eno.solver.rk + if rk == 1: + runge_kutta_1(eno) + elif rk == 2: + runge_kutta_2(eno) + else: + runge_kutta_3(eno) + +def runge_kutta_1(eno): + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = eno.u[j] + eno.dt * eno.res[i] + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def runge_kutta_2(eno): + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = eno.u[j] + eno.dt * eno.res[i] + boundary(eno.u, eno) + + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = 0.5 * eno.un[j] + 0.5 * eno.u[j] + 0.5 * eno.dt * eno.res[i] + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def runge_kutta_3(eno): + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = eno.u[j] + eno.dt * eno.res[i] + boundary(eno.u, eno) + + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = 0.75 * eno.un[j] + 0.25 * eno.u[j] + 0.25 * eno.dt * eno.res[i] + boundary(eno.u, eno) + + residual(eno.u, eno) + c1, c2, c3 = 1.0/3.0, 2.0/3.0, 2.0/3.0 + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = c1 * eno.un[j] + c2 * eno.u[j] + c3 * eno.dt * eno.res[i] + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def get_ordinal_numbers(order): + if order == 1: + return 'st' + elif order == 2: + return 'nd' + elif order == 3: + return 'rd' + else: + return 'th' + +def visualize(eno): + with open('solution.plt', 'w') as f: + for i in range(eno.ist, eno.ied + 1): + j = i - eno.ist + f.write(f"{eno.xcc[j]:20.10e}{eno.u[i]:20.10e}\n") + + # 可视化 + u_numerical = np.copy(eno.u[eno.ist:eno.ied+1]) + print(f'u_numerical.size={u_numerical.size}') + print(f'eno.xcc.size={eno.xcc.size}') + #计算理论解 + u_analytical = analytical_solution(eno.mesh.xcc, eno.T, eno.c, eno.L) + print(f'u_analytical.size={u_analytical.size}') + plt.figure("OneFLOW-CFD Solver", figsize=(10, 6)) + plt.scatter(eno.xcc, u_numerical, facecolor="none", edgecolor="blue", s=20, linewidths=0.5, label=f'Numerical (Rusanov)') + plt.plot(eno.xcc, u_analytical, 'r--', label='Analytical') + plt.xlabel('x') + plt.ylabel('u') + ordinal1 = get_ordinal_numbers(eno.iorder) + ordinal2 = get_ordinal_numbers(eno.rk) + plt.title(f'1D Convection Equation at t = {eno.T:.3f} using {eno.iorder}{ordinal1}-order ENO and {eno.rk}{ordinal2}-order Runge-Kutta methods') + plt.legend() + plt.grid(True, color='gray', linestyle='--', linewidth=0.5, alpha=0.7) + plt.tight_layout() + plt.show() + +class Mesh: + def __init__(self): + self.nx = 40 + self.L = 2.0 + self.x = np.zeros(self.nx + 1) + self.xcc = np.zeros(self.nx) + self.init_mesh() + def init_mesh(self): + xstart = 0.0 + xend = self.L + self.dx = (xend - xstart) / self.nx + + for i in range(0, self.nx+1): + self.x[i] = xstart + i * self.dx + + for i in range(0, self.nx): + self.xcc[i] = 0.5 * (self.x[i] + self.x[i + 1]) + +class Solver: + def __init__(self): + self.iflux = 0 + self.rk = 2 + self.c = 1.0 + self.T = 0.625 + +class Eno: + def __init__(self, solver, mesh, iorder): + self.solver = solver + self.mesh = mesh + self.nx = mesh.nx + self.iorder = iorder + self.ighost = iorder + self.ishift = self.ighost + 1 + self.ist = 0 + self.ishift + self.ied = self.nx - 1 + self.ishift + self.ntcell = self.nx + 2 * self.ishift + self.isize = iorder * (iorder + 1) + + self.il = np.zeros(self.nx + 1, dtype=int) + self.ir = np.zeros(self.nx + 1, dtype=int) + self.coef = np.zeros((iorder + 1, iorder)) + self.dd = np.zeros((iorder, self.ntcell)) + self.up1_2m = np.zeros(self.nx + 1) + self.up1_2p = np.zeros(self.nx + 1) + self.flux = np.zeros(self.nx + 1) + self.res = np.zeros(self.nx) + + # Field module variables + self.u = np.zeros(self.ntcell) + self.un = np.zeros(self.ntcell) + + self.dt = .0025 + +def plot_eno_field(solver, xcc, u_list, u_analytical): + # 定义一个包含不同颜色、线形和标记的列表 + styles = [ + {'color': 'black', 'linestyle': '-', 'marker': 'o'}, + {'color': 'blue', 'linestyle': '--', 'marker': 's'}, + {'color': 'black', 'linestyle': '-', 'marker': '^'}, + {'color': 'blue', 'linestyle': '--', 'marker': 'v'}, + {'color': 'black', 'linestyle': '-', 'marker': '<'}, + {'color': 'blue', 'linestyle': '--', 'marker': '>'}, + {'color': 'black', 'linestyle': '-', 'marker': 'D'}, + ] + + n = len(u_list) + num_styles = len(styles) + ordinal = get_ordinal_numbers(solver.rk) + + plt.figure("OneFLOW-CFD Solver", figsize=(10, 6)) + plt.title(f'1D Convection Equation at t = {solver.T:.3f} using [1-7]th-order ENO and {solver.rk}{ordinal}-order Runge-Kutta methods') + for i in range(0, n): + lable = 'Numerical (Rusanov)ENO' + str(i+1) + style = styles[i % num_styles] + plt.plot(xcc, u_list[i], marker=style['marker'], markerfacecolor='none', linestyle=style['linestyle'], color=style['color'], \ + markersize=5, linewidth=0.5, alpha=1.0, label=f'{lable}') + plt.plot(xcc, u_analytical, 'r--', label='Analytical') + plt.xlabel('x') + plt.ylabel('u') + plt.legend() + plt.grid(True, color='gray', linestyle='--', linewidth=0.5, alpha=0.7) + plt.tight_layout() + plt.show() + +def RunEno(solver, mesh, iorder): + eno = Eno(solver, mesh, iorder) + init_coef(eno.iorder, eno.coef) + init_field(eno) + + simu_time = solver.T + t = 0.0 + dt = eno.dt + while t < simu_time: + runge_kutta(eno) + if t + dt > simu_time: + dt = simu_time - t + t += dt + print(f'T={t:.3f},runge_kutta{solver.rk},ENO{eno.iorder},{fluxnames[solver.iflux]} FLUX') + #visualize(eno) + return np.copy(eno.u[eno.ist:eno.ied+1]) + +def performEnoOrderAnalysis(): + iorder_max = 7 + mesh = Mesh() + solver = Solver() + #计算理论解 + u_analytical = analytical_solution(mesh.xcc, solver.T, solver.c, mesh.L) + + u_list = [] + for iorder in range(1, iorder_max+1): + u = RunEno(solver, mesh, iorder) + u_list.append(u) + + plot_eno_field(solver, mesh.xcc, u_list, u_analytical) + +def main(): + performEnoOrderAnalysis() + + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/example/1d-linear-convection/eno/rusanov/timestep/rk1-eno1/01/plot.py b/example/1d-linear-convection/eno/rusanov/timestep/rk1-eno1/01/plot.py new file mode 100644 index 00000000..e389044c --- /dev/null +++ b/example/1d-linear-convection/eno/rusanov/timestep/rk1-eno1/01/plot.py @@ -0,0 +1,53 @@ +import numpy as np +import matplotlib.pyplot as plt +import csv +import sys + +nvar = len(sys.argv) +print('nvar=',nvar) +print('sys.argv=',sys.argv) + +order = 1 +if nvar >= 2: + var = sys.argv[1] + print('var=',var) + order = int(var) + +print('order=',order) + +x_list = [] +u_list = [] + +with open('solution.plt', newline='') as csvfile: + #readCSV = csv.reader(csvfile, delimiter= ' ') + icount = 0 + for line in csvfile: + # 去除首尾空格,按连续空格分割 + row = line.strip().split() + #print("row=",row) + x_list.append(row[0]) + u_list.append(row[1]) + icount += 1 + +ni = icount +print("ni=",ni) + +#print("x_list=",x_list) + +x = np.zeros( ni ) +u = np.zeros( ni ) + +for i in range(0, ni): + x[i] = float(x_list[i]) + u[i] = float(u_list[i]) + +labelname = 'Eno' + str(order) + +plt.figure("OneFLOW-CFD Solver", figsize=(8, 6), dpi=100) +plt.plot(x, u, "b-", linewidth=1.0, marker = 's', markerfacecolor='None', label=labelname) +plt.xlabel("$x$") +plt.ylabel("$u$") +plt.title("burgers T=1") +plt.legend() +plt.tight_layout() +plt.show(); \ No newline at end of file diff --git a/example/1d-linear-convection/eno/rusanov/timestep/rk1-eno1/01a/eno.py b/example/1d-linear-convection/eno/rusanov/timestep/rk1-eno1/01a/eno.py new file mode 100644 index 00000000..9696be66 --- /dev/null +++ b/example/1d-linear-convection/eno/rusanov/timestep/rk1-eno1/01a/eno.py @@ -0,0 +1,415 @@ +import numpy as np +import matplotlib.pyplot as plt + +# 初始条件 +def initial_condition(x): + u0 = np.zeros_like(x) + for i in range(len(x)): + if 0.5 <= x[i] <= 1.0: + u0[i] = 2.0 + else: + u0[i] = 1.0 + return u0 + +# 理论解 +def analytical_solution(x, t, a, L): + # 初始条件沿 x - at 平移 + x_shifted = x - a * t + return initial_condition((x_shifted + L) % L) # 周期边界条件 + +def residual(q, eno): + reconstruction(q, eno) + inviscid_flux(eno.up1_2m, eno.up1_2p, eno.flux, eno) + for i in range(eno.nx): + eno.res[i] = -(eno.flux[i + 1] - eno.flux[i]) / eno.mesh.dx + +def reconstruction(q, eno): + # Choose the stencil by ENO method + eno.dd[0, 0:eno.ntcell-1] = q[0:eno.ntcell-1] + + for m in range(1, eno.iorder): + for j in range(0, eno.ntcell-1): + eno.dd[m, j] = eno.dd[m-1, j+1] - eno.dd[m-1, j] + + for i in range(eno.nx + 1): + eno.il[i] = i - 1 + for m in range(1, eno.iorder): + if abs(eno.dd[m, eno.il[i]-1+eno.ishift]) <= abs(eno.dd[m, eno.il[i]+eno.ishift]): + eno.il[i] -= 1 + + for i in range(eno.nx + 1): + eno.ir[i] = i + for m in range(1, eno.iorder): + if abs(eno.dd[m, eno.ir[i]-1+eno.ishift]) <= abs(eno.dd[m, eno.ir[i]+eno.ishift]): + eno.ir[i] -= 1 + + # Reconstruction u(j+1/2) + for i in range(eno.nx + 1): + k1 = eno.il[i] + k2 = eno.ir[i] + l1 = i - k1 + l2 = i - k2 + eno.up1_2m[i] = 0 + eno.up1_2p[i] = 0 + for m in range(eno.iorder): + eno.up1_2m[i] += q[k1 + eno.ishift + m] * eno.coef[l1, m] + eno.up1_2p[i] += q[k2 + eno.ishift + m] * eno.coef[l2, m] + +fluxnames = [ + 'Rusanov', + 'Engquist-Osher', +] + +def inviscid_flux(up1_2m, up1_2p, flux, eno): + if eno.solver.iflux == 0: + rusanov_flux(up1_2m, up1_2p, flux, eno) + else: + engquist_osher_flux(up1_2m, up1_2p, flux, eno) + +def engquist_osher_flux(up1_2m, up1_2p, flux, eno): + for i in range(eno.nx + 1): + u_L = up1_2m[i] + u_R = up1_2p[i] + + cp = 0.5 * ( eno.solver.c + abs(eno.solver.c) ) + cm = 0.5 * ( eno.solver.c - abs(eno.solver.c) ) + + flux[i] = cp * u_L + cm * u_R + +def rusanov_flux(up1_2m, up1_2p, flux, eno): + for i in range(eno.nx + 1): + u_L = up1_2m[i] + u_R = up1_2p[i] + F_L = eno.solver.c * u_L # 左状态通量 + F_R = eno.solver.c * u_R # 右状态通量 + alpha = abs(eno.solver.c) # 最大波速 + flux[i] = 0.5 * (F_L + F_R) - 0.5 * alpha * (u_R - u_L) + + +def boundary(u, eno): + for i in range(-eno.ighost, 1): + u[eno.ist - 1 + i] = u[eno.ied + i] + for i in range(1, eno.ighost + 2): + u[eno.ied + i] = u[eno.ist - 1 + i] + +def update_oldfield(qn, q): + qn[:] = q[:] + +def init_coef( iorder, coef ): + if iorder == 1: + coef[0] = [1.0] + coef[1] = [1.0] + elif iorder == 2: + coef[0] = [3.0/2.0, -1.0/2.0] + coef[1] = [1.0/2.0, 1.0/2.0] + coef[2] = [-1.0/2.0, 3.0/2.0] + elif iorder == 3: + coef[0] = [ 11.0/6.0, -7.0/6.0, 1.0/3.0 ] + coef[1] = [ 1.0/3.0, 5.0/6.0, -1.0/6.0 ] + coef[2] = [ -1.0/6.0, 5.0/6.0, 1.0/3.0 ] + coef[3] = [ 1.0/3.0, -7.0/6.0, 11.0/6.0 ] + elif iorder == 4: + coef[0] = [ 25.0/12.0, -23.0/12.0, 13.0/12.0, -1.0/4.0 ] + coef[1] = [ 1.0/4.0, 13.0/12.0, -5.0/12.0, 1.0/12.0 ] + coef[2] = [ -1.0/12.0, 7.0/12.0, 7.0/12.0, -1.0/12.0 ] + coef[3] = [ 1.0/12.0, -5.0/12.0, 13.0/12.0, 1.0/4.0 ] + coef[4] = [ -1.0/4.0, 13.0/12.0, -23.0/12.0, 25.0/12.0 ] + elif iorder == 5: + coef[0] = [ 137.0/60.0, -163.0/60.0, 137.0/60.0, -21.0/20.0, 1.0/5.0 ] + coef[1] = [ 1.0/5.0, 77.0/60.0, -43.0/60.0, 17.0/60.0, -1.0/20.0 ] + coef[2] = [ -1.0/20.0, 9.0/20.0, 47.0/60.0, -13.0/60.0, 1.0/30.0 ] + coef[3] = [ 1.0/30.0, -13.0/60.0, 47.0/60.0, 9.0/20.0, -1.0/20.0 ] + coef[4] = [ -1.0/20.0, 17.0/60.0, -43.0/60.0, 77.0/60.0, 1.0/5.0 ] + coef[5] = [ 1.0/5.0, -21.0/20.0, 137.0/60.0, -163.0/60.0, 137.0/60.0 ] + elif iorder == 6: + coef[0] = [ 49.0/20.0, -71.0/20.0, 79.0/20.0, -163.0/60.0, 31.0/30.0, -1.0/6.0 ] + coef[1] = [ 1.0/6.0, 29.0/20.0, -21.0/20.0, 37.0/60.0, -13.0/60.0, 1.0/30.0 ] + coef[2] = [ -1.0/30.0, 11.0/30.0, 19.0/20.0, -23.0/60.0, 7.0/60.0, -1.0/60.0 ] + coef[3] = [ 1.0/60.0, -2.0/15.0, 37.0/60.0, 37.0/60.0, -2.0/15.0, 1.0/60.0 ] + coef[4] = [ -1.0/60.0, 7.0/60.0, -23.0/60.0, 19.0/20.0, 11.0/30.0, -1.0/30.0 ] + coef[5] = [ 1.0/30.0, -13.0/60.0, 37.0/60.0, -21.0/20.0, 29.0/20.0, 1.0/6.0 ] + coef[6] = [ -1.0/6.0, 31.0/30.0, -163.0/60.0, 79.0/20.0, -71.0/20.0, 49.0/20.0 ] + elif iorder == 7: + coef[0] = [ 363.0/140.0, -617.0/140.0, 853.0/140.0, -2341.0/420.0, 667.0/210.0, -43.0/42.0, 1.0/7.0 ] + coef[1] = [ 1.0/7.0, 223.0/140.0, -197.0/140.0, 153.0/140.0, -241.0/420.0, 37.0/210.0, -1.0/42.0 ] + coef[2] = [ -1.0/42.0, 13.0/42.0, 153.0/140.0, -241.0/420.0, 109.0/420.0, -31.0/420.0, 1.0/105.0 ] + coef[3] = [ 1.0/105.0, -19.0/210.0, 107.0/210.0, 319.0/420.0, -101.0/420.0, 5.0/84.0, -1.0/140.0 ] + coef[4] = [ -1.0/140.0, 5.0/84.0, -101.0/420.0, 319.0/420.0, 107.0/210.0, -19.0/210.0, 1.0/105.0 ] + coef[5] = [ 1.0/105.0, -31.0/420.0, 109.0/420.0, -241.0/420.0, 153.0/140.0, 13.0/42.0, -1.0/42.0 ] + coef[6] = [ -1.0/42.0, 37.0/210.0, -241.0/420.0, 153.0/140.0, -197.0/140.0, 223.0/140.0, 1.0/7.0 ] + coef[7] = [ 1.0/7.0, -43.0/42.0, 667.0/210.0, -2341.0/420.0, 853.0/140.0, -617.0/140.0, 363.0/140.0 ] + +def init_field(eno): + for i in range(eno.ist, eno.ied + 1): + j = i - eno.ist + if 0.5 <= eno.mesh.xcc[j] <= 1.0: + eno.u[i] = 2.0 + else: + eno.u[i] = 1.0 + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def runge_kutta(eno): + rk = eno.solver.rk + if rk == 1: + runge_kutta_1(eno) + elif rk == 2: + runge_kutta_2(eno) + else: + runge_kutta_3(eno) + +def runge_kutta_1(eno): + dt = eno.solver.dt + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = eno.u[j] + dt * eno.res[i] + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def runge_kutta_2(eno): + dt = eno.solver.dt + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = eno.u[j] + dt * eno.res[i] + boundary(eno.u, eno) + + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = 0.5 * eno.un[j] + 0.5 * eno.u[j] + 0.5 * dt * eno.res[i] + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def runge_kutta_3(eno): + dt = eno.solver.dt + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = eno.u[j] + dt * eno.res[i] + boundary(eno.u, eno) + + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = 0.75 * eno.un[j] + 0.25 * eno.u[j] + 0.25 * dt * eno.res[i] + boundary(eno.u, eno) + + residual(eno.u, eno) + c1, c2, c3 = 1.0/3.0, 2.0/3.0, 2.0/3.0 + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = c1 * eno.un[j] + c2 * eno.u[j] + c3 * dt * eno.res[i] + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def get_ordinal_numbers(order): + if order == 1: + return 'st' + elif order == 2: + return 'nd' + elif order == 3: + return 'rd' + else: + return 'th' + +def visualize(eno): + with open('solution.plt', 'w') as f: + for i in range(eno.ist, eno.ied + 1): + j = i - eno.ist + f.write(f"{eno.xcc[j]:20.10e}{eno.u[i]:20.10e}\n") + + # 可视化 + u_numerical = np.copy(eno.u[eno.ist:eno.ied+1]) + print(f'u_numerical.size={u_numerical.size}') + print(f'eno.xcc.size={eno.xcc.size}') + #计算理论解 + u_analytical = analytical_solution(eno.mesh.xcc, eno.T, eno.c, eno.L) + print(f'u_analytical.size={u_analytical.size}') + plt.figure("OneFLOW-CFD Solver", figsize=(10, 6)) + plt.scatter(eno.xcc, u_numerical, facecolor="none", edgecolor="blue", s=20, linewidths=0.5, label=f'Numerical (Rusanov)') + plt.plot(eno.xcc, u_analytical, 'r--', label='Analytical') + plt.xlabel('x') + plt.ylabel('u') + ordinal1 = get_ordinal_numbers(eno.iorder) + ordinal2 = get_ordinal_numbers(eno.rk) + plt.title(f'1D Convection Equation at t = {eno.T:.3f} using {eno.iorder}{ordinal1}-order ENO and {eno.rk}{ordinal2}-order Runge-Kutta methods') + plt.legend() + plt.grid(True, color='gray', linestyle='--', linewidth=0.5, alpha=0.7) + plt.tight_layout() + plt.show() + +class Mesh: + def __init__(self): + self.nx = 40 + self.L = 2.0 + self.x = np.zeros(self.nx + 1) + self.xcc = np.zeros(self.nx) + self.init_mesh() + def init_mesh(self): + xstart = 0.0 + xend = self.L + self.dx = (xend - xstart) / self.nx + + for i in range(0, self.nx+1): + self.x[i] = xstart + i * self.dx + + for i in range(0, self.nx): + self.xcc[i] = 0.5 * (self.x[i] + self.x[i + 1]) + +class Solver: + def __init__(self): + self.iflux = 0 + self.rk = 1 + self.c = 1.0 + self.T = 0.625 + self.dt = .0025 + +class Eno: + def __init__(self, solver, mesh, iorder): + self.solver = solver + self.mesh = mesh + self.nx = mesh.nx + self.iorder = iorder + self.ighost = iorder + self.ishift = self.ighost + 1 + self.ist = 0 + self.ishift + self.ied = self.nx - 1 + self.ishift + self.ntcell = self.nx + 2 * self.ishift + self.isize = iorder * (iorder + 1) + + self.il = np.zeros(self.nx + 1, dtype=int) + self.ir = np.zeros(self.nx + 1, dtype=int) + self.coef = np.zeros((iorder + 1, iorder)) + self.dd = np.zeros((iorder, self.ntcell)) + self.up1_2m = np.zeros(self.nx + 1) + self.up1_2p = np.zeros(self.nx + 1) + self.flux = np.zeros(self.nx + 1) + self.res = np.zeros(self.nx) + + # Field module variables + self.u = np.zeros(self.ntcell) + self.un = np.zeros(self.ntcell) + + #self.dt = .0025 + +def plot_eno_OrderAnalysis(solver, xcc, u_list, u_analytical): + # 定义一个包含不同颜色、线形和标记的列表 + styles = [ + {'color': 'black', 'linestyle': '-', 'marker': 'o'}, + {'color': 'blue', 'linestyle': '--', 'marker': 's'}, + {'color': 'black', 'linestyle': '-', 'marker': '^'}, + {'color': 'blue', 'linestyle': '--', 'marker': 'v'}, + {'color': 'black', 'linestyle': '-', 'marker': '<'}, + {'color': 'blue', 'linestyle': '--', 'marker': '>'}, + {'color': 'black', 'linestyle': '-', 'marker': 'D'}, + ] + + n = len(u_list) + num_styles = len(styles) + ordinal = get_ordinal_numbers(solver.rk) + + plt.figure("OneFLOW-CFD Solver", figsize=(10, 6)) + plt.title(f'1D Convection Equation at t = {solver.T:.3f} using [1-7]th-order ENO and {solver.rk}{ordinal}-order Runge-Kutta methods') + for i in range(0, n): + lable = 'Numerical (Rusanov)ENO' + str(i+1) + style = styles[i % num_styles] + plt.plot(xcc, u_list[i], marker=style['marker'], markerfacecolor='none', linestyle=style['linestyle'], color=style['color'], \ + markersize=5, linewidth=0.5, alpha=1.0, label=f'{lable}') + plt.plot(xcc, u_analytical, 'r--', label='Analytical') + plt.xlabel('x') + plt.ylabel('u') + plt.legend() + plt.grid(True, color='gray', linestyle='--', linewidth=0.5, alpha=0.7) + plt.tight_layout() + plt.show() + +def plot_eno_TimestepAnalysis(solver, xcc, u_list, u_analytical, dt_list, iorder): + # 定义一个包含不同颜色、线形和标记的列表 + styles = [ + {'color': 'black', 'linestyle': '-', 'marker': 'o'}, + {'color': 'blue', 'linestyle': '--', 'marker': 's'}, + {'color': 'black', 'linestyle': '-', 'marker': '^'}, + {'color': 'blue', 'linestyle': '--', 'marker': 'v'}, + {'color': 'black', 'linestyle': '-', 'marker': '<'}, + {'color': 'blue', 'linestyle': '--', 'marker': '>'}, + {'color': 'black', 'linestyle': '-', 'marker': 'D'}, + ] + + n = len(u_list) + num_styles = len(styles) + ordinal = get_ordinal_numbers(solver.rk) + + plt.figure("OneFLOW-CFD Solver", figsize=(10, 6)) + plt.title(f'1D Convection Equation at t = {solver.T:.3f} using [iorder]th-order ENO and {solver.rk}{ordinal}-order Runge-Kutta methods') + for i in range(0, n): + lable = 'Numerical (Rusanov)ENO' + str(iorder) + ' T='+str(dt_list[i]) + style = styles[i % num_styles] + plt.plot(xcc, u_list[i], marker=style['marker'], markerfacecolor='none', linestyle=style['linestyle'], color=style['color'], \ + markersize=5, linewidth=0.5, alpha=1.0, label=f'{lable}') + plt.plot(xcc, u_analytical, 'r--', label='Analytical') + plt.xlabel('x') + plt.ylabel('u') + plt.legend() + plt.grid(True, color='gray', linestyle='--', linewidth=0.5, alpha=0.7) + plt.tight_layout() + plt.show() + +def RunEno(solver, mesh, iorder): + eno = Eno(solver, mesh, iorder) + init_coef(eno.iorder, eno.coef) + init_field(eno) + + simu_time = solver.T + t = 0.0 + dt = solver.dt + while t < simu_time: + runge_kutta(eno) + if t + dt > simu_time: + dt = simu_time - t + t += dt + print(f'T={t:.3f},runge_kutta{solver.rk},ENO{eno.iorder},{fluxnames[solver.iflux]} FLUX') + #visualize(eno) + return np.copy(eno.u[eno.ist:eno.ied+1]) + +def performEnoOrderAnalysis(): + iorder_max = 7 + mesh = Mesh() + solver = Solver() + #计算理论解 + u_analytical = analytical_solution(mesh.xcc, solver.T, solver.c, mesh.L) + + u_list = [] + for iorder in range(1, iorder_max+1): + u = RunEno(solver, mesh, iorder) + u_list.append(u) + + plot_eno_OrderAnalysis(solver, mesh.xcc, u_list, u_analytical) + +def performEnoTimestepAnalysis(): + mesh = Mesh() + solver = Solver() + #计算理论解 + u_analytical = analytical_solution(mesh.xcc, solver.T, solver.c, mesh.L) + + u_list = [] + dt_list = [] + solver.dt = 0.025 + n = 16 + iorder = 1 + for i in range(0, n): + u = RunEno(solver, mesh, iorder) + u_list.append(u) + dt_list.append(solver.dt) + print(f'T={solver.T:.3f},dt={solver.dt},nt={int(solver.T/solver.dt)}') + solver.dt /= 2 + + plot_eno_TimestepAnalysis(solver, mesh.xcc, u_list, u_analytical, dt_list, iorder) + +def main(): + #performEnoOrderAnalysis() + performEnoTimestepAnalysis() + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/example/1d-linear-convection/eno/rusanov/timestep/rk1-eno1/01a/plot.py b/example/1d-linear-convection/eno/rusanov/timestep/rk1-eno1/01a/plot.py new file mode 100644 index 00000000..e389044c --- /dev/null +++ b/example/1d-linear-convection/eno/rusanov/timestep/rk1-eno1/01a/plot.py @@ -0,0 +1,53 @@ +import numpy as np +import matplotlib.pyplot as plt +import csv +import sys + +nvar = len(sys.argv) +print('nvar=',nvar) +print('sys.argv=',sys.argv) + +order = 1 +if nvar >= 2: + var = sys.argv[1] + print('var=',var) + order = int(var) + +print('order=',order) + +x_list = [] +u_list = [] + +with open('solution.plt', newline='') as csvfile: + #readCSV = csv.reader(csvfile, delimiter= ' ') + icount = 0 + for line in csvfile: + # 去除首尾空格,按连续空格分割 + row = line.strip().split() + #print("row=",row) + x_list.append(row[0]) + u_list.append(row[1]) + icount += 1 + +ni = icount +print("ni=",ni) + +#print("x_list=",x_list) + +x = np.zeros( ni ) +u = np.zeros( ni ) + +for i in range(0, ni): + x[i] = float(x_list[i]) + u[i] = float(u_list[i]) + +labelname = 'Eno' + str(order) + +plt.figure("OneFLOW-CFD Solver", figsize=(8, 6), dpi=100) +plt.plot(x, u, "b-", linewidth=1.0, marker = 's', markerfacecolor='None', label=labelname) +plt.xlabel("$x$") +plt.ylabel("$u$") +plt.title("burgers T=1") +plt.legend() +plt.tight_layout() +plt.show(); \ No newline at end of file diff --git a/example/1d-linear-convection/eno/rusanov/timestep/rk1-eno2/01/eno.py b/example/1d-linear-convection/eno/rusanov/timestep/rk1-eno2/01/eno.py new file mode 100644 index 00000000..0f55e28d --- /dev/null +++ b/example/1d-linear-convection/eno/rusanov/timestep/rk1-eno2/01/eno.py @@ -0,0 +1,426 @@ +import numpy as np +import matplotlib.pyplot as plt + +# 初始条件 +def initial_condition(x): + u0 = np.zeros_like(x) + for i in range(len(x)): + if 0.5 <= x[i] <= 1.0: + u0[i] = 2.0 + else: + u0[i] = 1.0 + return u0 + +# 理论解 +def analytical_solution(x, t, a, L): + # 初始条件沿 x - at 平移 + x_shifted = x - a * t + return initial_condition((x_shifted + L) % L) # 周期边界条件 + +def residual(q, eno): + reconstruction(q, eno) + inviscid_flux(eno.up1_2m, eno.up1_2p, eno.flux, eno) + for i in range(eno.nx): + eno.res[i] = -(eno.flux[i + 1] - eno.flux[i]) / eno.mesh.dx + +def reconstruction(q, eno): + # Choose the stencil by ENO method + eno.dd[0, 0:eno.ntcell-1] = q[0:eno.ntcell-1] + + for m in range(1, eno.iorder): + for j in range(0, eno.ntcell-1): + eno.dd[m, j] = eno.dd[m-1, j+1] - eno.dd[m-1, j] + + for i in range(eno.nx + 1): + eno.il[i] = i - 1 + for m in range(1, eno.iorder): + if abs(eno.dd[m, eno.il[i]-1+eno.ishift]) <= abs(eno.dd[m, eno.il[i]+eno.ishift]): + eno.il[i] -= 1 + + for i in range(eno.nx + 1): + eno.ir[i] = i + for m in range(1, eno.iorder): + if abs(eno.dd[m, eno.ir[i]-1+eno.ishift]) <= abs(eno.dd[m, eno.ir[i]+eno.ishift]): + eno.ir[i] -= 1 + + # Reconstruction u(j+1/2) + for i in range(eno.nx + 1): + k1 = eno.il[i] + k2 = eno.ir[i] + l1 = i - k1 + l2 = i - k2 + eno.up1_2m[i] = 0 + eno.up1_2p[i] = 0 + for m in range(eno.iorder): + eno.up1_2m[i] += q[k1 + eno.ishift + m] * eno.coef[l1, m] + eno.up1_2p[i] += q[k2 + eno.ishift + m] * eno.coef[l2, m] + +fluxnames = [ + 'Rusanov', + 'Engquist-Osher', +] + +def inviscid_flux(up1_2m, up1_2p, flux, eno): + if eno.solver.iflux == 0: + rusanov_flux(up1_2m, up1_2p, flux, eno) + else: + engquist_osher_flux(up1_2m, up1_2p, flux, eno) + +def engquist_osher_flux(up1_2m, up1_2p, flux, eno): + for i in range(eno.nx + 1): + u_L = up1_2m[i] + u_R = up1_2p[i] + + cp = 0.5 * ( eno.solver.c + abs(eno.solver.c) ) + cm = 0.5 * ( eno.solver.c - abs(eno.solver.c) ) + + flux[i] = cp * u_L + cm * u_R + +def rusanov_flux(up1_2m, up1_2p, flux, eno): + for i in range(eno.nx + 1): + u_L = up1_2m[i] + u_R = up1_2p[i] + F_L = eno.solver.c * u_L # 左状态通量 + F_R = eno.solver.c * u_R # 右状态通量 + alpha = abs(eno.solver.c) # 最大波速 + flux[i] = 0.5 * (F_L + F_R) - 0.5 * alpha * (u_R - u_L) + + +def boundary(u, eno): + for i in range(-eno.ighost, 1): + u[eno.ist - 1 + i] = u[eno.ied + i] + for i in range(1, eno.ighost + 2): + u[eno.ied + i] = u[eno.ist - 1 + i] + +def update_oldfield(qn, q): + qn[:] = q[:] + +def init_coef( iorder, coef ): + if iorder == 1: + coef[0] = [1.0] + coef[1] = [1.0] + elif iorder == 2: + coef[0] = [3.0/2.0, -1.0/2.0] + coef[1] = [1.0/2.0, 1.0/2.0] + coef[2] = [-1.0/2.0, 3.0/2.0] + elif iorder == 3: + coef[0] = [ 11.0/6.0, -7.0/6.0, 1.0/3.0 ] + coef[1] = [ 1.0/3.0, 5.0/6.0, -1.0/6.0 ] + coef[2] = [ -1.0/6.0, 5.0/6.0, 1.0/3.0 ] + coef[3] = [ 1.0/3.0, -7.0/6.0, 11.0/6.0 ] + elif iorder == 4: + coef[0] = [ 25.0/12.0, -23.0/12.0, 13.0/12.0, -1.0/4.0 ] + coef[1] = [ 1.0/4.0, 13.0/12.0, -5.0/12.0, 1.0/12.0 ] + coef[2] = [ -1.0/12.0, 7.0/12.0, 7.0/12.0, -1.0/12.0 ] + coef[3] = [ 1.0/12.0, -5.0/12.0, 13.0/12.0, 1.0/4.0 ] + coef[4] = [ -1.0/4.0, 13.0/12.0, -23.0/12.0, 25.0/12.0 ] + elif iorder == 5: + coef[0] = [ 137.0/60.0, -163.0/60.0, 137.0/60.0, -21.0/20.0, 1.0/5.0 ] + coef[1] = [ 1.0/5.0, 77.0/60.0, -43.0/60.0, 17.0/60.0, -1.0/20.0 ] + coef[2] = [ -1.0/20.0, 9.0/20.0, 47.0/60.0, -13.0/60.0, 1.0/30.0 ] + coef[3] = [ 1.0/30.0, -13.0/60.0, 47.0/60.0, 9.0/20.0, -1.0/20.0 ] + coef[4] = [ -1.0/20.0, 17.0/60.0, -43.0/60.0, 77.0/60.0, 1.0/5.0 ] + coef[5] = [ 1.0/5.0, -21.0/20.0, 137.0/60.0, -163.0/60.0, 137.0/60.0 ] + elif iorder == 6: + coef[0] = [ 49.0/20.0, -71.0/20.0, 79.0/20.0, -163.0/60.0, 31.0/30.0, -1.0/6.0 ] + coef[1] = [ 1.0/6.0, 29.0/20.0, -21.0/20.0, 37.0/60.0, -13.0/60.0, 1.0/30.0 ] + coef[2] = [ -1.0/30.0, 11.0/30.0, 19.0/20.0, -23.0/60.0, 7.0/60.0, -1.0/60.0 ] + coef[3] = [ 1.0/60.0, -2.0/15.0, 37.0/60.0, 37.0/60.0, -2.0/15.0, 1.0/60.0 ] + coef[4] = [ -1.0/60.0, 7.0/60.0, -23.0/60.0, 19.0/20.0, 11.0/30.0, -1.0/30.0 ] + coef[5] = [ 1.0/30.0, -13.0/60.0, 37.0/60.0, -21.0/20.0, 29.0/20.0, 1.0/6.0 ] + coef[6] = [ -1.0/6.0, 31.0/30.0, -163.0/60.0, 79.0/20.0, -71.0/20.0, 49.0/20.0 ] + elif iorder == 7: + coef[0] = [ 363.0/140.0, -617.0/140.0, 853.0/140.0, -2341.0/420.0, 667.0/210.0, -43.0/42.0, 1.0/7.0 ] + coef[1] = [ 1.0/7.0, 223.0/140.0, -197.0/140.0, 153.0/140.0, -241.0/420.0, 37.0/210.0, -1.0/42.0 ] + coef[2] = [ -1.0/42.0, 13.0/42.0, 153.0/140.0, -241.0/420.0, 109.0/420.0, -31.0/420.0, 1.0/105.0 ] + coef[3] = [ 1.0/105.0, -19.0/210.0, 107.0/210.0, 319.0/420.0, -101.0/420.0, 5.0/84.0, -1.0/140.0 ] + coef[4] = [ -1.0/140.0, 5.0/84.0, -101.0/420.0, 319.0/420.0, 107.0/210.0, -19.0/210.0, 1.0/105.0 ] + coef[5] = [ 1.0/105.0, -31.0/420.0, 109.0/420.0, -241.0/420.0, 153.0/140.0, 13.0/42.0, -1.0/42.0 ] + coef[6] = [ -1.0/42.0, 37.0/210.0, -241.0/420.0, 153.0/140.0, -197.0/140.0, 223.0/140.0, 1.0/7.0 ] + coef[7] = [ 1.0/7.0, -43.0/42.0, 667.0/210.0, -2341.0/420.0, 853.0/140.0, -617.0/140.0, 363.0/140.0 ] + +def init_field(eno): + for i in range(eno.ist, eno.ied + 1): + j = i - eno.ist + if 0.5 <= eno.mesh.xcc[j] <= 1.0: + eno.u[i] = 2.0 + else: + eno.u[i] = 1.0 + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def runge_kutta(eno): + rk = eno.solver.rk + if rk == 1: + runge_kutta_1(eno) + elif rk == 2: + runge_kutta_2(eno) + else: + runge_kutta_3(eno) + +def runge_kutta_1(eno): + dt = eno.solver.dt + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = eno.u[j] + dt * eno.res[i] + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def runge_kutta_2(eno): + dt = eno.solver.dt + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = eno.u[j] + dt * eno.res[i] + boundary(eno.u, eno) + + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = 0.5 * eno.un[j] + 0.5 * eno.u[j] + 0.5 * dt * eno.res[i] + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def runge_kutta_3(eno): + dt = eno.solver.dt + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = eno.u[j] + dt * eno.res[i] + boundary(eno.u, eno) + + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = 0.75 * eno.un[j] + 0.25 * eno.u[j] + 0.25 * dt * eno.res[i] + boundary(eno.u, eno) + + residual(eno.u, eno) + c1, c2, c3 = 1.0/3.0, 2.0/3.0, 2.0/3.0 + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = c1 * eno.un[j] + c2 * eno.u[j] + c3 * dt * eno.res[i] + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def get_ordinal_numbers(order): + if order == 1: + return 'st' + elif order == 2: + return 'nd' + elif order == 3: + return 'rd' + else: + return 'th' + +def visualize(eno): + with open('solution.plt', 'w') as f: + for i in range(eno.ist, eno.ied + 1): + j = i - eno.ist + f.write(f"{eno.xcc[j]:20.10e}{eno.u[i]:20.10e}\n") + + # 可视化 + u_numerical = np.copy(eno.u[eno.ist:eno.ied+1]) + print(f'u_numerical.size={u_numerical.size}') + print(f'eno.xcc.size={eno.xcc.size}') + #计算理论解 + u_analytical = analytical_solution(eno.mesh.xcc, eno.T, eno.c, eno.L) + print(f'u_analytical.size={u_analytical.size}') + plt.figure("OneFLOW-CFD Solver", figsize=(10, 6)) + plt.scatter(eno.xcc, u_numerical, facecolor="none", edgecolor="blue", s=20, linewidths=0.5, label=f'Numerical (Rusanov)') + plt.plot(eno.xcc, u_analytical, 'r--', label='Analytical') + plt.xlabel('x') + plt.ylabel('u') + ordinal1 = get_ordinal_numbers(eno.iorder) + ordinal2 = get_ordinal_numbers(eno.rk) + plt.title(f'1D Convection Equation at t = {eno.T:.3f} using {eno.iorder}{ordinal1}-order ENO and {eno.rk}{ordinal2}-order Runge-Kutta methods') + plt.legend() + plt.grid(True, color='gray', linestyle='--', linewidth=0.5, alpha=0.7) + plt.tight_layout() + plt.show() + +class Mesh: + def __init__(self): + self.nx = 40 + self.L = 2.0 + self.x = np.zeros(self.nx + 1) + self.xcc = np.zeros(self.nx) + self.init_mesh() + def init_mesh(self): + xstart = 0.0 + xend = self.L + self.dx = (xend - xstart) / self.nx + + for i in range(0, self.nx+1): + self.x[i] = xstart + i * self.dx + + for i in range(0, self.nx): + self.xcc[i] = 0.5 * (self.x[i] + self.x[i + 1]) + +class Solver: + def __init__(self): + self.iflux = 0 + self.rk = 1 + self.c = 1.0 + self.T = 0.625 + self.dt = .0025 + +class Eno: + def __init__(self, solver, mesh, iorder): + self.solver = solver + self.mesh = mesh + self.nx = mesh.nx + self.iorder = iorder + self.ighost = iorder + self.ishift = self.ighost + 1 + self.ist = 0 + self.ishift + self.ied = self.nx - 1 + self.ishift + self.ntcell = self.nx + 2 * self.ishift + self.isize = iorder * (iorder + 1) + + self.il = np.zeros(self.nx + 1, dtype=int) + self.ir = np.zeros(self.nx + 1, dtype=int) + self.coef = np.zeros((iorder + 1, iorder)) + self.dd = np.zeros((iorder, self.ntcell)) + self.up1_2m = np.zeros(self.nx + 1) + self.up1_2p = np.zeros(self.nx + 1) + self.flux = np.zeros(self.nx + 1) + self.res = np.zeros(self.nx) + + # Field module variables + self.u = np.zeros(self.ntcell) + self.un = np.zeros(self.ntcell) + + #self.dt = .0025 + +def plot_eno_OrderAnalysis(solver, xcc, u_list, u_analytical): + # 定义一个包含不同颜色、线形和标记的列表 + styles = [ + {'color': 'black', 'linestyle': '-', 'marker': 'o'}, + {'color': 'blue', 'linestyle': '--', 'marker': 's'}, + {'color': 'black', 'linestyle': '-', 'marker': '^'}, + {'color': 'blue', 'linestyle': '--', 'marker': 'v'}, + {'color': 'black', 'linestyle': '-', 'marker': '<'}, + {'color': 'blue', 'linestyle': '--', 'marker': '>'}, + {'color': 'black', 'linestyle': '-', 'marker': 'D'}, + ] + + n = len(u_list) + num_styles = len(styles) + ordinal = get_ordinal_numbers(solver.rk) + + plt.figure("OneFLOW-CFD Solver", figsize=(10, 6)) + plt.title(f'1D Convection Equation at t = {solver.T:.3f} using [1-7]th-order ENO and {solver.rk}{ordinal}-order Runge-Kutta methods') + for i in range(0, n): + lable = 'Numerical (Rusanov)ENO' + str(i+1) + style = styles[i % num_styles] + plt.plot(xcc, u_list[i], marker=style['marker'], markerfacecolor='none', linestyle=style['linestyle'], color=style['color'], \ + markersize=5, linewidth=0.5, alpha=1.0, label=f'{lable}') + plt.plot(xcc, u_analytical, 'r--', label='Analytical') + plt.xlabel('x') + plt.ylabel('u') + plt.legend() + plt.grid(True, color='gray', linestyle='--', linewidth=0.5, alpha=0.7) + plt.tight_layout() + plt.show() + +def plot_eno_TimestepAnalysis(solver, xcc, u_list, u_analytical, dt_list, iorder): + # 定义一个包含不同颜色、线形和标记的列表 + styles = [ + {'color': 'black', 'linestyle': '-', 'marker': 'o'}, + {'color': 'blue', 'linestyle': '--', 'marker': 's'}, + {'color': 'black', 'linestyle': '-', 'marker': '^'}, + {'color': 'blue', 'linestyle': '--', 'marker': 'v'}, + {'color': 'black', 'linestyle': '-', 'marker': '<'}, + {'color': 'blue', 'linestyle': '--', 'marker': '>'}, + {'color': 'black', 'linestyle': '-', 'marker': 'D'}, + {'color': 'blue', 'linestyle': '--', 'marker': 'o'}, + {'color': 'black', 'linestyle': '-', 'marker': 's'}, + {'color': 'blue', 'linestyle': '--', 'marker': '^'}, + {'color': 'black', 'linestyle': '-', 'marker': 'v'}, + {'color': 'blue', 'linestyle': '--', 'marker': '<'}, + {'color': 'black', 'linestyle': '-', 'marker': '>'}, + {'color': 'blue', 'linestyle': '--', 'marker': 'D'}, + ] + + n = len(u_list) + num_styles = len(styles) + + ordinalENO = get_ordinal_numbers(iorder) + ordinalRK = get_ordinal_numbers(solver.rk) + + plt.figure("OneFLOW-CFD Solver", figsize=(10, 6)) + plt.title(f'1D Convection Equation at t = {solver.T:.3f} using {iorder}{ordinalENO}-order ENO and {solver.rk}{ordinalRK}-order Runge-Kutta methods') + for i in range(0, n): + lable = 'Numerical (Rusanov)ENO' + str(iorder) + ' T='+str(dt_list[i]) + style = styles[i % num_styles] + plt.plot(xcc, u_list[i], marker=style['marker'], markerfacecolor='none', linestyle=style['linestyle'], color=style['color'], \ + markersize=5, linewidth=1.0, alpha=1.0, label=f'{lable}') + plt.plot(xcc, u_analytical, 'r--', label='Analytical') + plt.xlabel('x') + plt.ylabel('u') + plt.legend() + plt.grid(True, color='gray', linestyle='--', linewidth=0.5, alpha=0.7) + plt.tight_layout() + plt.show() + +def RunEno(solver, mesh, iorder): + eno = Eno(solver, mesh, iorder) + init_coef(eno.iorder, eno.coef) + init_field(eno) + + simu_time = solver.T + t = 0.0 + dt = solver.dt + while t < simu_time: + runge_kutta(eno) + if t + dt > simu_time: + dt = simu_time - t + t += dt + #print(f'T={t:.3f},runge_kutta{solver.rk},ENO{eno.iorder},{fluxnames[solver.iflux]} FLUX') + #visualize(eno) + return np.copy(eno.u[eno.ist:eno.ied+1]) + +def performEnoOrderAnalysis(): + iorder_max = 7 + mesh = Mesh() + solver = Solver() + #计算理论解 + u_analytical = analytical_solution(mesh.xcc, solver.T, solver.c, mesh.L) + + u_list = [] + for iorder in range(1, iorder_max+1): + u = RunEno(solver, mesh, iorder) + u_list.append(u) + + plot_eno_OrderAnalysis(solver, mesh.xcc, u_list, u_analytical) + +def performEnoTimestepAnalysis(): + mesh = Mesh() + solver = Solver() + #计算理论解 + u_analytical = analytical_solution(mesh.xcc, solver.T, solver.c, mesh.L) + + u_list = [] + dt_list = [] + solver.dt = 0.025 + #solver.dt = 0.025/16 + n = 12 + solver.rk = 1 + iorder = 2 + for i in range(0, n): + u = RunEno(solver, mesh, iorder) + u_list.append(u) + dt_list.append(solver.dt) + print(f'i={i+1},N={n},T={solver.T:.3f},dt={solver.dt},nt={int(solver.T/solver.dt)},runge_kutta{solver.rk},ENO{iorder},{fluxnames[solver.iflux]} FLUX') + solver.dt /= 2 + + plot_eno_TimestepAnalysis(solver, mesh.xcc, u_list, u_analytical, dt_list, iorder) + +def main(): + #performEnoOrderAnalysis() + performEnoTimestepAnalysis() + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/example/1d-linear-convection/eno/rusanov/timestep/rk1-eno2/01/plot.py b/example/1d-linear-convection/eno/rusanov/timestep/rk1-eno2/01/plot.py new file mode 100644 index 00000000..e389044c --- /dev/null +++ b/example/1d-linear-convection/eno/rusanov/timestep/rk1-eno2/01/plot.py @@ -0,0 +1,53 @@ +import numpy as np +import matplotlib.pyplot as plt +import csv +import sys + +nvar = len(sys.argv) +print('nvar=',nvar) +print('sys.argv=',sys.argv) + +order = 1 +if nvar >= 2: + var = sys.argv[1] + print('var=',var) + order = int(var) + +print('order=',order) + +x_list = [] +u_list = [] + +with open('solution.plt', newline='') as csvfile: + #readCSV = csv.reader(csvfile, delimiter= ' ') + icount = 0 + for line in csvfile: + # 去除首尾空格,按连续空格分割 + row = line.strip().split() + #print("row=",row) + x_list.append(row[0]) + u_list.append(row[1]) + icount += 1 + +ni = icount +print("ni=",ni) + +#print("x_list=",x_list) + +x = np.zeros( ni ) +u = np.zeros( ni ) + +for i in range(0, ni): + x[i] = float(x_list[i]) + u[i] = float(u_list[i]) + +labelname = 'Eno' + str(order) + +plt.figure("OneFLOW-CFD Solver", figsize=(8, 6), dpi=100) +plt.plot(x, u, "b-", linewidth=1.0, marker = 's', markerfacecolor='None', label=labelname) +plt.xlabel("$x$") +plt.ylabel("$u$") +plt.title("burgers T=1") +plt.legend() +plt.tight_layout() +plt.show(); \ No newline at end of file diff --git a/example/1d-linear-convection/eno/rusanov/timestep/rk2-eno/eno1/01/eno.py b/example/1d-linear-convection/eno/rusanov/timestep/rk2-eno/eno1/01/eno.py new file mode 100644 index 00000000..4501b9f4 --- /dev/null +++ b/example/1d-linear-convection/eno/rusanov/timestep/rk2-eno/eno1/01/eno.py @@ -0,0 +1,426 @@ +import numpy as np +import matplotlib.pyplot as plt + +# 初始条件 +def initial_condition(x): + u0 = np.zeros_like(x) + for i in range(len(x)): + if 0.5 <= x[i] <= 1.0: + u0[i] = 2.0 + else: + u0[i] = 1.0 + return u0 + +# 理论解 +def analytical_solution(x, t, a, L): + # 初始条件沿 x - at 平移 + x_shifted = x - a * t + return initial_condition((x_shifted + L) % L) # 周期边界条件 + +def residual(q, eno): + reconstruction(q, eno) + inviscid_flux(eno.up1_2m, eno.up1_2p, eno.flux, eno) + for i in range(eno.nx): + eno.res[i] = -(eno.flux[i + 1] - eno.flux[i]) / eno.mesh.dx + +def reconstruction(q, eno): + # Choose the stencil by ENO method + eno.dd[0, 0:eno.ntcell-1] = q[0:eno.ntcell-1] + + for m in range(1, eno.iorder): + for j in range(0, eno.ntcell-1): + eno.dd[m, j] = eno.dd[m-1, j+1] - eno.dd[m-1, j] + + for i in range(eno.nx + 1): + eno.il[i] = i - 1 + for m in range(1, eno.iorder): + if abs(eno.dd[m, eno.il[i]-1+eno.ishift]) <= abs(eno.dd[m, eno.il[i]+eno.ishift]): + eno.il[i] -= 1 + + for i in range(eno.nx + 1): + eno.ir[i] = i + for m in range(1, eno.iorder): + if abs(eno.dd[m, eno.ir[i]-1+eno.ishift]) <= abs(eno.dd[m, eno.ir[i]+eno.ishift]): + eno.ir[i] -= 1 + + # Reconstruction u(j+1/2) + for i in range(eno.nx + 1): + k1 = eno.il[i] + k2 = eno.ir[i] + l1 = i - k1 + l2 = i - k2 + eno.up1_2m[i] = 0 + eno.up1_2p[i] = 0 + for m in range(eno.iorder): + eno.up1_2m[i] += q[k1 + eno.ishift + m] * eno.coef[l1, m] + eno.up1_2p[i] += q[k2 + eno.ishift + m] * eno.coef[l2, m] + +fluxnames = [ + 'Rusanov', + 'Engquist-Osher', +] + +def inviscid_flux(up1_2m, up1_2p, flux, eno): + if eno.solver.iflux == 0: + rusanov_flux(up1_2m, up1_2p, flux, eno) + else: + engquist_osher_flux(up1_2m, up1_2p, flux, eno) + +def engquist_osher_flux(up1_2m, up1_2p, flux, eno): + for i in range(eno.nx + 1): + u_L = up1_2m[i] + u_R = up1_2p[i] + + cp = 0.5 * ( eno.solver.c + abs(eno.solver.c) ) + cm = 0.5 * ( eno.solver.c - abs(eno.solver.c) ) + + flux[i] = cp * u_L + cm * u_R + +def rusanov_flux(up1_2m, up1_2p, flux, eno): + for i in range(eno.nx + 1): + u_L = up1_2m[i] + u_R = up1_2p[i] + F_L = eno.solver.c * u_L # 左状态通量 + F_R = eno.solver.c * u_R # 右状态通量 + alpha = abs(eno.solver.c) # 最大波速 + flux[i] = 0.5 * (F_L + F_R) - 0.5 * alpha * (u_R - u_L) + + +def boundary(u, eno): + for i in range(-eno.ighost, 1): + u[eno.ist - 1 + i] = u[eno.ied + i] + for i in range(1, eno.ighost + 2): + u[eno.ied + i] = u[eno.ist - 1 + i] + +def update_oldfield(qn, q): + qn[:] = q[:] + +def init_coef( iorder, coef ): + if iorder == 1: + coef[0] = [1.0] + coef[1] = [1.0] + elif iorder == 2: + coef[0] = [3.0/2.0, -1.0/2.0] + coef[1] = [1.0/2.0, 1.0/2.0] + coef[2] = [-1.0/2.0, 3.0/2.0] + elif iorder == 3: + coef[0] = [ 11.0/6.0, -7.0/6.0, 1.0/3.0 ] + coef[1] = [ 1.0/3.0, 5.0/6.0, -1.0/6.0 ] + coef[2] = [ -1.0/6.0, 5.0/6.0, 1.0/3.0 ] + coef[3] = [ 1.0/3.0, -7.0/6.0, 11.0/6.0 ] + elif iorder == 4: + coef[0] = [ 25.0/12.0, -23.0/12.0, 13.0/12.0, -1.0/4.0 ] + coef[1] = [ 1.0/4.0, 13.0/12.0, -5.0/12.0, 1.0/12.0 ] + coef[2] = [ -1.0/12.0, 7.0/12.0, 7.0/12.0, -1.0/12.0 ] + coef[3] = [ 1.0/12.0, -5.0/12.0, 13.0/12.0, 1.0/4.0 ] + coef[4] = [ -1.0/4.0, 13.0/12.0, -23.0/12.0, 25.0/12.0 ] + elif iorder == 5: + coef[0] = [ 137.0/60.0, -163.0/60.0, 137.0/60.0, -21.0/20.0, 1.0/5.0 ] + coef[1] = [ 1.0/5.0, 77.0/60.0, -43.0/60.0, 17.0/60.0, -1.0/20.0 ] + coef[2] = [ -1.0/20.0, 9.0/20.0, 47.0/60.0, -13.0/60.0, 1.0/30.0 ] + coef[3] = [ 1.0/30.0, -13.0/60.0, 47.0/60.0, 9.0/20.0, -1.0/20.0 ] + coef[4] = [ -1.0/20.0, 17.0/60.0, -43.0/60.0, 77.0/60.0, 1.0/5.0 ] + coef[5] = [ 1.0/5.0, -21.0/20.0, 137.0/60.0, -163.0/60.0, 137.0/60.0 ] + elif iorder == 6: + coef[0] = [ 49.0/20.0, -71.0/20.0, 79.0/20.0, -163.0/60.0, 31.0/30.0, -1.0/6.0 ] + coef[1] = [ 1.0/6.0, 29.0/20.0, -21.0/20.0, 37.0/60.0, -13.0/60.0, 1.0/30.0 ] + coef[2] = [ -1.0/30.0, 11.0/30.0, 19.0/20.0, -23.0/60.0, 7.0/60.0, -1.0/60.0 ] + coef[3] = [ 1.0/60.0, -2.0/15.0, 37.0/60.0, 37.0/60.0, -2.0/15.0, 1.0/60.0 ] + coef[4] = [ -1.0/60.0, 7.0/60.0, -23.0/60.0, 19.0/20.0, 11.0/30.0, -1.0/30.0 ] + coef[5] = [ 1.0/30.0, -13.0/60.0, 37.0/60.0, -21.0/20.0, 29.0/20.0, 1.0/6.0 ] + coef[6] = [ -1.0/6.0, 31.0/30.0, -163.0/60.0, 79.0/20.0, -71.0/20.0, 49.0/20.0 ] + elif iorder == 7: + coef[0] = [ 363.0/140.0, -617.0/140.0, 853.0/140.0, -2341.0/420.0, 667.0/210.0, -43.0/42.0, 1.0/7.0 ] + coef[1] = [ 1.0/7.0, 223.0/140.0, -197.0/140.0, 153.0/140.0, -241.0/420.0, 37.0/210.0, -1.0/42.0 ] + coef[2] = [ -1.0/42.0, 13.0/42.0, 153.0/140.0, -241.0/420.0, 109.0/420.0, -31.0/420.0, 1.0/105.0 ] + coef[3] = [ 1.0/105.0, -19.0/210.0, 107.0/210.0, 319.0/420.0, -101.0/420.0, 5.0/84.0, -1.0/140.0 ] + coef[4] = [ -1.0/140.0, 5.0/84.0, -101.0/420.0, 319.0/420.0, 107.0/210.0, -19.0/210.0, 1.0/105.0 ] + coef[5] = [ 1.0/105.0, -31.0/420.0, 109.0/420.0, -241.0/420.0, 153.0/140.0, 13.0/42.0, -1.0/42.0 ] + coef[6] = [ -1.0/42.0, 37.0/210.0, -241.0/420.0, 153.0/140.0, -197.0/140.0, 223.0/140.0, 1.0/7.0 ] + coef[7] = [ 1.0/7.0, -43.0/42.0, 667.0/210.0, -2341.0/420.0, 853.0/140.0, -617.0/140.0, 363.0/140.0 ] + +def init_field(eno): + for i in range(eno.ist, eno.ied + 1): + j = i - eno.ist + if 0.5 <= eno.mesh.xcc[j] <= 1.0: + eno.u[i] = 2.0 + else: + eno.u[i] = 1.0 + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def runge_kutta(eno): + rk = eno.solver.rk + if rk == 1: + runge_kutta_1(eno) + elif rk == 2: + runge_kutta_2(eno) + else: + runge_kutta_3(eno) + +def runge_kutta_1(eno): + dt = eno.solver.dt + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = eno.u[j] + dt * eno.res[i] + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def runge_kutta_2(eno): + dt = eno.solver.dt + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = eno.u[j] + dt * eno.res[i] + boundary(eno.u, eno) + + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = 0.5 * eno.un[j] + 0.5 * eno.u[j] + 0.5 * dt * eno.res[i] + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def runge_kutta_3(eno): + dt = eno.solver.dt + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = eno.u[j] + dt * eno.res[i] + boundary(eno.u, eno) + + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = 0.75 * eno.un[j] + 0.25 * eno.u[j] + 0.25 * dt * eno.res[i] + boundary(eno.u, eno) + + residual(eno.u, eno) + c1, c2, c3 = 1.0/3.0, 2.0/3.0, 2.0/3.0 + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = c1 * eno.un[j] + c2 * eno.u[j] + c3 * dt * eno.res[i] + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def get_ordinal_numbers(order): + if order == 1: + return 'st' + elif order == 2: + return 'nd' + elif order == 3: + return 'rd' + else: + return 'th' + +def visualize(eno): + with open('solution.plt', 'w') as f: + for i in range(eno.ist, eno.ied + 1): + j = i - eno.ist + f.write(f"{eno.xcc[j]:20.10e}{eno.u[i]:20.10e}\n") + + # 可视化 + u_numerical = np.copy(eno.u[eno.ist:eno.ied+1]) + print(f'u_numerical.size={u_numerical.size}') + print(f'eno.xcc.size={eno.xcc.size}') + #计算理论解 + u_analytical = analytical_solution(eno.mesh.xcc, eno.T, eno.c, eno.L) + print(f'u_analytical.size={u_analytical.size}') + plt.figure("OneFLOW-CFD Solver", figsize=(10, 6)) + plt.scatter(eno.xcc, u_numerical, facecolor="none", edgecolor="blue", s=20, linewidths=0.5, label=f'Numerical (Rusanov)') + plt.plot(eno.xcc, u_analytical, 'r--', label='Analytical') + plt.xlabel('x') + plt.ylabel('u') + ordinal1 = get_ordinal_numbers(eno.iorder) + ordinal2 = get_ordinal_numbers(eno.rk) + plt.title(f'1D Convection Equation at t = {eno.T:.3f} using {eno.iorder}{ordinal1}-order ENO and {eno.rk}{ordinal2}-order Runge-Kutta methods') + plt.legend() + plt.grid(True, color='gray', linestyle='--', linewidth=0.5, alpha=0.7) + plt.tight_layout() + plt.show() + +class Mesh: + def __init__(self): + self.nx = 40 + self.L = 2.0 + self.x = np.zeros(self.nx + 1) + self.xcc = np.zeros(self.nx) + self.init_mesh() + def init_mesh(self): + xstart = 0.0 + xend = self.L + self.dx = (xend - xstart) / self.nx + + for i in range(0, self.nx+1): + self.x[i] = xstart + i * self.dx + + for i in range(0, self.nx): + self.xcc[i] = 0.5 * (self.x[i] + self.x[i + 1]) + +class Solver: + def __init__(self): + self.iflux = 0 + self.rk = 1 + self.c = 1.0 + self.T = 0.625 + self.dt = .0025 + +class Eno: + def __init__(self, solver, mesh, iorder): + self.solver = solver + self.mesh = mesh + self.nx = mesh.nx + self.iorder = iorder + self.ighost = iorder + self.ishift = self.ighost + 1 + self.ist = 0 + self.ishift + self.ied = self.nx - 1 + self.ishift + self.ntcell = self.nx + 2 * self.ishift + self.isize = iorder * (iorder + 1) + + self.il = np.zeros(self.nx + 1, dtype=int) + self.ir = np.zeros(self.nx + 1, dtype=int) + self.coef = np.zeros((iorder + 1, iorder)) + self.dd = np.zeros((iorder, self.ntcell)) + self.up1_2m = np.zeros(self.nx + 1) + self.up1_2p = np.zeros(self.nx + 1) + self.flux = np.zeros(self.nx + 1) + self.res = np.zeros(self.nx) + + # Field module variables + self.u = np.zeros(self.ntcell) + self.un = np.zeros(self.ntcell) + + #self.dt = .0025 + +def plot_eno_OrderAnalysis(solver, xcc, u_list, u_analytical): + # 定义一个包含不同颜色、线形和标记的列表 + styles = [ + {'color': 'black', 'linestyle': '-', 'marker': 'o'}, + {'color': 'blue', 'linestyle': '--', 'marker': 's'}, + {'color': 'black', 'linestyle': '-', 'marker': '^'}, + {'color': 'blue', 'linestyle': '--', 'marker': 'v'}, + {'color': 'black', 'linestyle': '-', 'marker': '<'}, + {'color': 'blue', 'linestyle': '--', 'marker': '>'}, + {'color': 'black', 'linestyle': '-', 'marker': 'D'}, + ] + + n = len(u_list) + num_styles = len(styles) + ordinal = get_ordinal_numbers(solver.rk) + + plt.figure("OneFLOW-CFD Solver", figsize=(10, 6)) + plt.title(f'1D Convection Equation at t = {solver.T:.3f} using [1-7]th-order ENO and {solver.rk}{ordinal}-order Runge-Kutta methods') + for i in range(0, n): + lable = 'Numerical (Rusanov)ENO' + str(i+1) + style = styles[i % num_styles] + plt.plot(xcc, u_list[i], marker=style['marker'], markerfacecolor='none', linestyle=style['linestyle'], color=style['color'], \ + markersize=5, linewidth=0.5, alpha=1.0, label=f'{lable}') + plt.plot(xcc, u_analytical, 'r--', label='Analytical') + plt.xlabel('x') + plt.ylabel('u') + plt.legend() + plt.grid(True, color='gray', linestyle='--', linewidth=0.5, alpha=0.7) + plt.tight_layout() + plt.show() + +def plot_eno_TimestepAnalysis(solver, xcc, u_list, u_analytical, dt_list, iorder): + # 定义一个包含不同颜色、线形和标记的列表 + styles = [ + {'color': 'black', 'linestyle': '-', 'marker': 'o'}, + {'color': 'blue', 'linestyle': '--', 'marker': 's'}, + {'color': 'black', 'linestyle': '-', 'marker': '^'}, + {'color': 'blue', 'linestyle': '--', 'marker': 'v'}, + {'color': 'black', 'linestyle': '-', 'marker': '<'}, + {'color': 'blue', 'linestyle': '--', 'marker': '>'}, + {'color': 'black', 'linestyle': '-', 'marker': 'D'}, + {'color': 'blue', 'linestyle': '--', 'marker': 'o'}, + {'color': 'black', 'linestyle': '-', 'marker': 's'}, + {'color': 'blue', 'linestyle': '--', 'marker': '^'}, + {'color': 'black', 'linestyle': '-', 'marker': 'v'}, + {'color': 'blue', 'linestyle': '--', 'marker': '<'}, + {'color': 'black', 'linestyle': '-', 'marker': '>'}, + {'color': 'blue', 'linestyle': '--', 'marker': 'D'}, + ] + + n = len(u_list) + num_styles = len(styles) + + ordinalENO = get_ordinal_numbers(iorder) + ordinalRK = get_ordinal_numbers(solver.rk) + + plt.figure("OneFLOW-CFD Solver", figsize=(10, 6)) + plt.title(f'1D Convection Equation at t = {solver.T:.3f} using {iorder}{ordinalENO}-order ENO and {solver.rk}{ordinalRK}-order Runge-Kutta methods') + for i in range(0, n): + lable = 'Numerical (Rusanov)ENO' + str(iorder) + ' T='+str(dt_list[i]) + style = styles[i % num_styles] + plt.plot(xcc, u_list[i], marker=style['marker'], markerfacecolor='none', linestyle=style['linestyle'], color=style['color'], \ + markersize=5, linewidth=1.0, alpha=1.0, label=f'{lable}') + plt.plot(xcc, u_analytical, 'r--', label='Analytical') + plt.xlabel('x') + plt.ylabel('u') + plt.legend() + plt.grid(True, color='gray', linestyle='--', linewidth=0.5, alpha=0.7) + plt.tight_layout() + plt.show() + +def RunEno(solver, mesh, iorder): + eno = Eno(solver, mesh, iorder) + init_coef(eno.iorder, eno.coef) + init_field(eno) + + simu_time = solver.T + t = 0.0 + dt = solver.dt + while t < simu_time: + runge_kutta(eno) + if t + dt > simu_time: + dt = simu_time - t + t += dt + #print(f'T={t:.3f},runge_kutta{solver.rk},ENO{eno.iorder},{fluxnames[solver.iflux]} FLUX') + #visualize(eno) + return np.copy(eno.u[eno.ist:eno.ied+1]) + +def performEnoOrderAnalysis(): + iorder_max = 7 + mesh = Mesh() + solver = Solver() + #计算理论解 + u_analytical = analytical_solution(mesh.xcc, solver.T, solver.c, mesh.L) + + u_list = [] + for iorder in range(1, iorder_max+1): + u = RunEno(solver, mesh, iorder) + u_list.append(u) + + plot_eno_OrderAnalysis(solver, mesh.xcc, u_list, u_analytical) + +def performEnoTimestepAnalysis(): + mesh = Mesh() + solver = Solver() + #计算理论解 + u_analytical = analytical_solution(mesh.xcc, solver.T, solver.c, mesh.L) + + u_list = [] + dt_list = [] + solver.dt = 0.025 + #solver.dt = 0.025/16 + n = 12 + solver.rk = 2 + iorder = 1 + for i in range(0, n): + u = RunEno(solver, mesh, iorder) + u_list.append(u) + dt_list.append(solver.dt) + print(f'i={i+1},N={n},T={solver.T:.3f},dt={solver.dt},nt={int(solver.T/solver.dt)},runge_kutta{solver.rk},ENO{iorder},{fluxnames[solver.iflux]} FLUX') + solver.dt /= 2 + + plot_eno_TimestepAnalysis(solver, mesh.xcc, u_list, u_analytical, dt_list, iorder) + +def main(): + #performEnoOrderAnalysis() + performEnoTimestepAnalysis() + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/example/1d-linear-convection/eno/rusanov/timestep/rk2-eno/eno1/01/plot.py b/example/1d-linear-convection/eno/rusanov/timestep/rk2-eno/eno1/01/plot.py new file mode 100644 index 00000000..e389044c --- /dev/null +++ b/example/1d-linear-convection/eno/rusanov/timestep/rk2-eno/eno1/01/plot.py @@ -0,0 +1,53 @@ +import numpy as np +import matplotlib.pyplot as plt +import csv +import sys + +nvar = len(sys.argv) +print('nvar=',nvar) +print('sys.argv=',sys.argv) + +order = 1 +if nvar >= 2: + var = sys.argv[1] + print('var=',var) + order = int(var) + +print('order=',order) + +x_list = [] +u_list = [] + +with open('solution.plt', newline='') as csvfile: + #readCSV = csv.reader(csvfile, delimiter= ' ') + icount = 0 + for line in csvfile: + # 去除首尾空格,按连续空格分割 + row = line.strip().split() + #print("row=",row) + x_list.append(row[0]) + u_list.append(row[1]) + icount += 1 + +ni = icount +print("ni=",ni) + +#print("x_list=",x_list) + +x = np.zeros( ni ) +u = np.zeros( ni ) + +for i in range(0, ni): + x[i] = float(x_list[i]) + u[i] = float(u_list[i]) + +labelname = 'Eno' + str(order) + +plt.figure("OneFLOW-CFD Solver", figsize=(8, 6), dpi=100) +plt.plot(x, u, "b-", linewidth=1.0, marker = 's', markerfacecolor='None', label=labelname) +plt.xlabel("$x$") +plt.ylabel("$u$") +plt.title("burgers T=1") +plt.legend() +plt.tight_layout() +plt.show(); \ No newline at end of file diff --git a/example/1d-linear-convection/eno/rusanov/timestep/rk2-eno/eno2/01/eno.py b/example/1d-linear-convection/eno/rusanov/timestep/rk2-eno/eno2/01/eno.py new file mode 100644 index 00000000..957bb149 --- /dev/null +++ b/example/1d-linear-convection/eno/rusanov/timestep/rk2-eno/eno2/01/eno.py @@ -0,0 +1,426 @@ +import numpy as np +import matplotlib.pyplot as plt + +# 初始条件 +def initial_condition(x): + u0 = np.zeros_like(x) + for i in range(len(x)): + if 0.5 <= x[i] <= 1.0: + u0[i] = 2.0 + else: + u0[i] = 1.0 + return u0 + +# 理论解 +def analytical_solution(x, t, a, L): + # 初始条件沿 x - at 平移 + x_shifted = x - a * t + return initial_condition((x_shifted + L) % L) # 周期边界条件 + +def residual(q, eno): + reconstruction(q, eno) + inviscid_flux(eno.up1_2m, eno.up1_2p, eno.flux, eno) + for i in range(eno.nx): + eno.res[i] = -(eno.flux[i + 1] - eno.flux[i]) / eno.mesh.dx + +def reconstruction(q, eno): + # Choose the stencil by ENO method + eno.dd[0, 0:eno.ntcell-1] = q[0:eno.ntcell-1] + + for m in range(1, eno.iorder): + for j in range(0, eno.ntcell-1): + eno.dd[m, j] = eno.dd[m-1, j+1] - eno.dd[m-1, j] + + for i in range(eno.nx + 1): + eno.il[i] = i - 1 + for m in range(1, eno.iorder): + if abs(eno.dd[m, eno.il[i]-1+eno.ishift]) <= abs(eno.dd[m, eno.il[i]+eno.ishift]): + eno.il[i] -= 1 + + for i in range(eno.nx + 1): + eno.ir[i] = i + for m in range(1, eno.iorder): + if abs(eno.dd[m, eno.ir[i]-1+eno.ishift]) <= abs(eno.dd[m, eno.ir[i]+eno.ishift]): + eno.ir[i] -= 1 + + # Reconstruction u(j+1/2) + for i in range(eno.nx + 1): + k1 = eno.il[i] + k2 = eno.ir[i] + l1 = i - k1 + l2 = i - k2 + eno.up1_2m[i] = 0 + eno.up1_2p[i] = 0 + for m in range(eno.iorder): + eno.up1_2m[i] += q[k1 + eno.ishift + m] * eno.coef[l1, m] + eno.up1_2p[i] += q[k2 + eno.ishift + m] * eno.coef[l2, m] + +fluxnames = [ + 'Rusanov', + 'Engquist-Osher', +] + +def inviscid_flux(up1_2m, up1_2p, flux, eno): + if eno.solver.iflux == 0: + rusanov_flux(up1_2m, up1_2p, flux, eno) + else: + engquist_osher_flux(up1_2m, up1_2p, flux, eno) + +def engquist_osher_flux(up1_2m, up1_2p, flux, eno): + for i in range(eno.nx + 1): + u_L = up1_2m[i] + u_R = up1_2p[i] + + cp = 0.5 * ( eno.solver.c + abs(eno.solver.c) ) + cm = 0.5 * ( eno.solver.c - abs(eno.solver.c) ) + + flux[i] = cp * u_L + cm * u_R + +def rusanov_flux(up1_2m, up1_2p, flux, eno): + for i in range(eno.nx + 1): + u_L = up1_2m[i] + u_R = up1_2p[i] + F_L = eno.solver.c * u_L # 左状态通量 + F_R = eno.solver.c * u_R # 右状态通量 + alpha = abs(eno.solver.c) # 最大波速 + flux[i] = 0.5 * (F_L + F_R) - 0.5 * alpha * (u_R - u_L) + + +def boundary(u, eno): + for i in range(-eno.ighost, 1): + u[eno.ist - 1 + i] = u[eno.ied + i] + for i in range(1, eno.ighost + 2): + u[eno.ied + i] = u[eno.ist - 1 + i] + +def update_oldfield(qn, q): + qn[:] = q[:] + +def init_coef( iorder, coef ): + if iorder == 1: + coef[0] = [1.0] + coef[1] = [1.0] + elif iorder == 2: + coef[0] = [3.0/2.0, -1.0/2.0] + coef[1] = [1.0/2.0, 1.0/2.0] + coef[2] = [-1.0/2.0, 3.0/2.0] + elif iorder == 3: + coef[0] = [ 11.0/6.0, -7.0/6.0, 1.0/3.0 ] + coef[1] = [ 1.0/3.0, 5.0/6.0, -1.0/6.0 ] + coef[2] = [ -1.0/6.0, 5.0/6.0, 1.0/3.0 ] + coef[3] = [ 1.0/3.0, -7.0/6.0, 11.0/6.0 ] + elif iorder == 4: + coef[0] = [ 25.0/12.0, -23.0/12.0, 13.0/12.0, -1.0/4.0 ] + coef[1] = [ 1.0/4.0, 13.0/12.0, -5.0/12.0, 1.0/12.0 ] + coef[2] = [ -1.0/12.0, 7.0/12.0, 7.0/12.0, -1.0/12.0 ] + coef[3] = [ 1.0/12.0, -5.0/12.0, 13.0/12.0, 1.0/4.0 ] + coef[4] = [ -1.0/4.0, 13.0/12.0, -23.0/12.0, 25.0/12.0 ] + elif iorder == 5: + coef[0] = [ 137.0/60.0, -163.0/60.0, 137.0/60.0, -21.0/20.0, 1.0/5.0 ] + coef[1] = [ 1.0/5.0, 77.0/60.0, -43.0/60.0, 17.0/60.0, -1.0/20.0 ] + coef[2] = [ -1.0/20.0, 9.0/20.0, 47.0/60.0, -13.0/60.0, 1.0/30.0 ] + coef[3] = [ 1.0/30.0, -13.0/60.0, 47.0/60.0, 9.0/20.0, -1.0/20.0 ] + coef[4] = [ -1.0/20.0, 17.0/60.0, -43.0/60.0, 77.0/60.0, 1.0/5.0 ] + coef[5] = [ 1.0/5.0, -21.0/20.0, 137.0/60.0, -163.0/60.0, 137.0/60.0 ] + elif iorder == 6: + coef[0] = [ 49.0/20.0, -71.0/20.0, 79.0/20.0, -163.0/60.0, 31.0/30.0, -1.0/6.0 ] + coef[1] = [ 1.0/6.0, 29.0/20.0, -21.0/20.0, 37.0/60.0, -13.0/60.0, 1.0/30.0 ] + coef[2] = [ -1.0/30.0, 11.0/30.0, 19.0/20.0, -23.0/60.0, 7.0/60.0, -1.0/60.0 ] + coef[3] = [ 1.0/60.0, -2.0/15.0, 37.0/60.0, 37.0/60.0, -2.0/15.0, 1.0/60.0 ] + coef[4] = [ -1.0/60.0, 7.0/60.0, -23.0/60.0, 19.0/20.0, 11.0/30.0, -1.0/30.0 ] + coef[5] = [ 1.0/30.0, -13.0/60.0, 37.0/60.0, -21.0/20.0, 29.0/20.0, 1.0/6.0 ] + coef[6] = [ -1.0/6.0, 31.0/30.0, -163.0/60.0, 79.0/20.0, -71.0/20.0, 49.0/20.0 ] + elif iorder == 7: + coef[0] = [ 363.0/140.0, -617.0/140.0, 853.0/140.0, -2341.0/420.0, 667.0/210.0, -43.0/42.0, 1.0/7.0 ] + coef[1] = [ 1.0/7.0, 223.0/140.0, -197.0/140.0, 153.0/140.0, -241.0/420.0, 37.0/210.0, -1.0/42.0 ] + coef[2] = [ -1.0/42.0, 13.0/42.0, 153.0/140.0, -241.0/420.0, 109.0/420.0, -31.0/420.0, 1.0/105.0 ] + coef[3] = [ 1.0/105.0, -19.0/210.0, 107.0/210.0, 319.0/420.0, -101.0/420.0, 5.0/84.0, -1.0/140.0 ] + coef[4] = [ -1.0/140.0, 5.0/84.0, -101.0/420.0, 319.0/420.0, 107.0/210.0, -19.0/210.0, 1.0/105.0 ] + coef[5] = [ 1.0/105.0, -31.0/420.0, 109.0/420.0, -241.0/420.0, 153.0/140.0, 13.0/42.0, -1.0/42.0 ] + coef[6] = [ -1.0/42.0, 37.0/210.0, -241.0/420.0, 153.0/140.0, -197.0/140.0, 223.0/140.0, 1.0/7.0 ] + coef[7] = [ 1.0/7.0, -43.0/42.0, 667.0/210.0, -2341.0/420.0, 853.0/140.0, -617.0/140.0, 363.0/140.0 ] + +def init_field(eno): + for i in range(eno.ist, eno.ied + 1): + j = i - eno.ist + if 0.5 <= eno.mesh.xcc[j] <= 1.0: + eno.u[i] = 2.0 + else: + eno.u[i] = 1.0 + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def runge_kutta(eno): + rk = eno.solver.rk + if rk == 1: + runge_kutta_1(eno) + elif rk == 2: + runge_kutta_2(eno) + else: + runge_kutta_3(eno) + +def runge_kutta_1(eno): + dt = eno.solver.dt + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = eno.u[j] + dt * eno.res[i] + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def runge_kutta_2(eno): + dt = eno.solver.dt + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = eno.u[j] + dt * eno.res[i] + boundary(eno.u, eno) + + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = 0.5 * eno.un[j] + 0.5 * eno.u[j] + 0.5 * dt * eno.res[i] + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def runge_kutta_3(eno): + dt = eno.solver.dt + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = eno.u[j] + dt * eno.res[i] + boundary(eno.u, eno) + + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = 0.75 * eno.un[j] + 0.25 * eno.u[j] + 0.25 * dt * eno.res[i] + boundary(eno.u, eno) + + residual(eno.u, eno) + c1, c2, c3 = 1.0/3.0, 2.0/3.0, 2.0/3.0 + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = c1 * eno.un[j] + c2 * eno.u[j] + c3 * dt * eno.res[i] + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def get_ordinal_numbers(order): + if order == 1: + return 'st' + elif order == 2: + return 'nd' + elif order == 3: + return 'rd' + else: + return 'th' + +def visualize(eno): + with open('solution.plt', 'w') as f: + for i in range(eno.ist, eno.ied + 1): + j = i - eno.ist + f.write(f"{eno.xcc[j]:20.10e}{eno.u[i]:20.10e}\n") + + # 可视化 + u_numerical = np.copy(eno.u[eno.ist:eno.ied+1]) + print(f'u_numerical.size={u_numerical.size}') + print(f'eno.xcc.size={eno.xcc.size}') + #计算理论解 + u_analytical = analytical_solution(eno.mesh.xcc, eno.T, eno.c, eno.L) + print(f'u_analytical.size={u_analytical.size}') + plt.figure("OneFLOW-CFD Solver", figsize=(10, 6)) + plt.scatter(eno.xcc, u_numerical, facecolor="none", edgecolor="blue", s=20, linewidths=0.5, label=f'Numerical (Rusanov)') + plt.plot(eno.xcc, u_analytical, 'r--', label='Analytical') + plt.xlabel('x') + plt.ylabel('u') + ordinal1 = get_ordinal_numbers(eno.iorder) + ordinal2 = get_ordinal_numbers(eno.rk) + plt.title(f'1D Convection Equation at t = {eno.T:.3f} using {eno.iorder}{ordinal1}-order ENO and {eno.rk}{ordinal2}-order Runge-Kutta methods') + plt.legend() + plt.grid(True, color='gray', linestyle='--', linewidth=0.5, alpha=0.7) + plt.tight_layout() + plt.show() + +class Mesh: + def __init__(self): + self.nx = 40 + self.L = 2.0 + self.x = np.zeros(self.nx + 1) + self.xcc = np.zeros(self.nx) + self.init_mesh() + def init_mesh(self): + xstart = 0.0 + xend = self.L + self.dx = (xend - xstart) / self.nx + + for i in range(0, self.nx+1): + self.x[i] = xstart + i * self.dx + + for i in range(0, self.nx): + self.xcc[i] = 0.5 * (self.x[i] + self.x[i + 1]) + +class Solver: + def __init__(self): + self.iflux = 0 + self.rk = 1 + self.c = 1.0 + self.T = 0.625 + self.dt = .0025 + +class Eno: + def __init__(self, solver, mesh, iorder): + self.solver = solver + self.mesh = mesh + self.nx = mesh.nx + self.iorder = iorder + self.ighost = iorder + self.ishift = self.ighost + 1 + self.ist = 0 + self.ishift + self.ied = self.nx - 1 + self.ishift + self.ntcell = self.nx + 2 * self.ishift + self.isize = iorder * (iorder + 1) + + self.il = np.zeros(self.nx + 1, dtype=int) + self.ir = np.zeros(self.nx + 1, dtype=int) + self.coef = np.zeros((iorder + 1, iorder)) + self.dd = np.zeros((iorder, self.ntcell)) + self.up1_2m = np.zeros(self.nx + 1) + self.up1_2p = np.zeros(self.nx + 1) + self.flux = np.zeros(self.nx + 1) + self.res = np.zeros(self.nx) + + # Field module variables + self.u = np.zeros(self.ntcell) + self.un = np.zeros(self.ntcell) + + #self.dt = .0025 + +def plot_eno_OrderAnalysis(solver, xcc, u_list, u_analytical): + # 定义一个包含不同颜色、线形和标记的列表 + styles = [ + {'color': 'black', 'linestyle': '-', 'marker': 'o'}, + {'color': 'blue', 'linestyle': '--', 'marker': 's'}, + {'color': 'black', 'linestyle': '-', 'marker': '^'}, + {'color': 'blue', 'linestyle': '--', 'marker': 'v'}, + {'color': 'black', 'linestyle': '-', 'marker': '<'}, + {'color': 'blue', 'linestyle': '--', 'marker': '>'}, + {'color': 'black', 'linestyle': '-', 'marker': 'D'}, + ] + + n = len(u_list) + num_styles = len(styles) + ordinal = get_ordinal_numbers(solver.rk) + + plt.figure("OneFLOW-CFD Solver", figsize=(10, 6)) + plt.title(f'1D Convection Equation at t = {solver.T:.3f} using [1-7]th-order ENO and {solver.rk}{ordinal}-order Runge-Kutta methods') + for i in range(0, n): + lable = 'Numerical (Rusanov)ENO' + str(i+1) + style = styles[i % num_styles] + plt.plot(xcc, u_list[i], marker=style['marker'], markerfacecolor='none', linestyle=style['linestyle'], color=style['color'], \ + markersize=5, linewidth=0.5, alpha=1.0, label=f'{lable}') + plt.plot(xcc, u_analytical, 'r--', label='Analytical') + plt.xlabel('x') + plt.ylabel('u') + plt.legend() + plt.grid(True, color='gray', linestyle='--', linewidth=0.5, alpha=0.7) + plt.tight_layout() + plt.show() + +def plot_eno_TimestepAnalysis(solver, xcc, u_list, u_analytical, dt_list, iorder): + # 定义一个包含不同颜色、线形和标记的列表 + styles = [ + {'color': 'black', 'linestyle': '-', 'marker': 'o'}, + {'color': 'blue', 'linestyle': '--', 'marker': 's'}, + {'color': 'black', 'linestyle': '-', 'marker': '^'}, + {'color': 'blue', 'linestyle': '--', 'marker': 'v'}, + {'color': 'black', 'linestyle': '-', 'marker': '<'}, + {'color': 'blue', 'linestyle': '--', 'marker': '>'}, + {'color': 'black', 'linestyle': '-', 'marker': 'D'}, + {'color': 'blue', 'linestyle': '--', 'marker': 'o'}, + {'color': 'black', 'linestyle': '-', 'marker': 's'}, + {'color': 'blue', 'linestyle': '--', 'marker': '^'}, + {'color': 'black', 'linestyle': '-', 'marker': 'v'}, + {'color': 'blue', 'linestyle': '--', 'marker': '<'}, + {'color': 'black', 'linestyle': '-', 'marker': '>'}, + {'color': 'blue', 'linestyle': '--', 'marker': 'D'}, + ] + + n = len(u_list) + num_styles = len(styles) + + ordinalENO = get_ordinal_numbers(iorder) + ordinalRK = get_ordinal_numbers(solver.rk) + + plt.figure("OneFLOW-CFD Solver", figsize=(10, 6)) + plt.title(f'1D Convection Equation at t = {solver.T:.3f} using {iorder}{ordinalENO}-order ENO and {solver.rk}{ordinalRK}-order Runge-Kutta methods') + for i in range(0, n): + lable = 'Numerical (Rusanov)ENO' + str(iorder) + ' T='+str(dt_list[i]) + style = styles[i % num_styles] + plt.plot(xcc, u_list[i], marker=style['marker'], markerfacecolor='none', linestyle=style['linestyle'], color=style['color'], \ + markersize=5, linewidth=1.0, alpha=1.0, label=f'{lable}') + plt.plot(xcc, u_analytical, 'r--', label='Analytical') + plt.xlabel('x') + plt.ylabel('u') + plt.legend() + plt.grid(True, color='gray', linestyle='--', linewidth=0.5, alpha=0.7) + plt.tight_layout() + plt.show() + +def RunEno(solver, mesh, iorder): + eno = Eno(solver, mesh, iorder) + init_coef(eno.iorder, eno.coef) + init_field(eno) + + simu_time = solver.T + t = 0.0 + dt = solver.dt + while t < simu_time: + runge_kutta(eno) + if t + dt > simu_time: + dt = simu_time - t + t += dt + #print(f'T={t:.3f},runge_kutta{solver.rk},ENO{eno.iorder},{fluxnames[solver.iflux]} FLUX') + #visualize(eno) + return np.copy(eno.u[eno.ist:eno.ied+1]) + +def performEnoOrderAnalysis(): + iorder_max = 7 + mesh = Mesh() + solver = Solver() + #计算理论解 + u_analytical = analytical_solution(mesh.xcc, solver.T, solver.c, mesh.L) + + u_list = [] + for iorder in range(1, iorder_max+1): + u = RunEno(solver, mesh, iorder) + u_list.append(u) + + plot_eno_OrderAnalysis(solver, mesh.xcc, u_list, u_analytical) + +def performEnoTimestepAnalysis(): + mesh = Mesh() + solver = Solver() + #计算理论解 + u_analytical = analytical_solution(mesh.xcc, solver.T, solver.c, mesh.L) + + u_list = [] + dt_list = [] + solver.dt = 0.025 + #solver.dt = 0.025/16 + n = 12 + solver.rk = 2 + iorder = 2 + for i in range(0, n): + u = RunEno(solver, mesh, iorder) + u_list.append(u) + dt_list.append(solver.dt) + print(f'i={i+1},N={n},T={solver.T:.3f},dt={solver.dt},nt={int(solver.T/solver.dt)},runge_kutta{solver.rk},ENO{iorder},{fluxnames[solver.iflux]} FLUX') + solver.dt /= 2 + + plot_eno_TimestepAnalysis(solver, mesh.xcc, u_list, u_analytical, dt_list, iorder) + +def main(): + #performEnoOrderAnalysis() + performEnoTimestepAnalysis() + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/example/1d-linear-convection/eno/rusanov/timestep/rk2-eno/eno2/01/plot.py b/example/1d-linear-convection/eno/rusanov/timestep/rk2-eno/eno2/01/plot.py new file mode 100644 index 00000000..e389044c --- /dev/null +++ b/example/1d-linear-convection/eno/rusanov/timestep/rk2-eno/eno2/01/plot.py @@ -0,0 +1,53 @@ +import numpy as np +import matplotlib.pyplot as plt +import csv +import sys + +nvar = len(sys.argv) +print('nvar=',nvar) +print('sys.argv=',sys.argv) + +order = 1 +if nvar >= 2: + var = sys.argv[1] + print('var=',var) + order = int(var) + +print('order=',order) + +x_list = [] +u_list = [] + +with open('solution.plt', newline='') as csvfile: + #readCSV = csv.reader(csvfile, delimiter= ' ') + icount = 0 + for line in csvfile: + # 去除首尾空格,按连续空格分割 + row = line.strip().split() + #print("row=",row) + x_list.append(row[0]) + u_list.append(row[1]) + icount += 1 + +ni = icount +print("ni=",ni) + +#print("x_list=",x_list) + +x = np.zeros( ni ) +u = np.zeros( ni ) + +for i in range(0, ni): + x[i] = float(x_list[i]) + u[i] = float(u_list[i]) + +labelname = 'Eno' + str(order) + +plt.figure("OneFLOW-CFD Solver", figsize=(8, 6), dpi=100) +plt.plot(x, u, "b-", linewidth=1.0, marker = 's', markerfacecolor='None', label=labelname) +plt.xlabel("$x$") +plt.ylabel("$u$") +plt.title("burgers T=1") +plt.legend() +plt.tight_layout() +plt.show(); \ No newline at end of file diff --git a/example/1d-linear-convection/eno/rusanov/timestep/rk2-eno/eno3/01/eno.py b/example/1d-linear-convection/eno/rusanov/timestep/rk2-eno/eno3/01/eno.py new file mode 100644 index 00000000..5ef3e8e0 --- /dev/null +++ b/example/1d-linear-convection/eno/rusanov/timestep/rk2-eno/eno3/01/eno.py @@ -0,0 +1,426 @@ +import numpy as np +import matplotlib.pyplot as plt + +# 初始条件 +def initial_condition(x): + u0 = np.zeros_like(x) + for i in range(len(x)): + if 0.5 <= x[i] <= 1.0: + u0[i] = 2.0 + else: + u0[i] = 1.0 + return u0 + +# 理论解 +def analytical_solution(x, t, a, L): + # 初始条件沿 x - at 平移 + x_shifted = x - a * t + return initial_condition((x_shifted + L) % L) # 周期边界条件 + +def residual(q, eno): + reconstruction(q, eno) + inviscid_flux(eno.up1_2m, eno.up1_2p, eno.flux, eno) + for i in range(eno.nx): + eno.res[i] = -(eno.flux[i + 1] - eno.flux[i]) / eno.mesh.dx + +def reconstruction(q, eno): + # Choose the stencil by ENO method + eno.dd[0, 0:eno.ntcell-1] = q[0:eno.ntcell-1] + + for m in range(1, eno.iorder): + for j in range(0, eno.ntcell-1): + eno.dd[m, j] = eno.dd[m-1, j+1] - eno.dd[m-1, j] + + for i in range(eno.nx + 1): + eno.il[i] = i - 1 + for m in range(1, eno.iorder): + if abs(eno.dd[m, eno.il[i]-1+eno.ishift]) <= abs(eno.dd[m, eno.il[i]+eno.ishift]): + eno.il[i] -= 1 + + for i in range(eno.nx + 1): + eno.ir[i] = i + for m in range(1, eno.iorder): + if abs(eno.dd[m, eno.ir[i]-1+eno.ishift]) <= abs(eno.dd[m, eno.ir[i]+eno.ishift]): + eno.ir[i] -= 1 + + # Reconstruction u(j+1/2) + for i in range(eno.nx + 1): + k1 = eno.il[i] + k2 = eno.ir[i] + l1 = i - k1 + l2 = i - k2 + eno.up1_2m[i] = 0 + eno.up1_2p[i] = 0 + for m in range(eno.iorder): + eno.up1_2m[i] += q[k1 + eno.ishift + m] * eno.coef[l1, m] + eno.up1_2p[i] += q[k2 + eno.ishift + m] * eno.coef[l2, m] + +fluxnames = [ + 'Rusanov', + 'Engquist-Osher', +] + +def inviscid_flux(up1_2m, up1_2p, flux, eno): + if eno.solver.iflux == 0: + rusanov_flux(up1_2m, up1_2p, flux, eno) + else: + engquist_osher_flux(up1_2m, up1_2p, flux, eno) + +def engquist_osher_flux(up1_2m, up1_2p, flux, eno): + for i in range(eno.nx + 1): + u_L = up1_2m[i] + u_R = up1_2p[i] + + cp = 0.5 * ( eno.solver.c + abs(eno.solver.c) ) + cm = 0.5 * ( eno.solver.c - abs(eno.solver.c) ) + + flux[i] = cp * u_L + cm * u_R + +def rusanov_flux(up1_2m, up1_2p, flux, eno): + for i in range(eno.nx + 1): + u_L = up1_2m[i] + u_R = up1_2p[i] + F_L = eno.solver.c * u_L # 左状态通量 + F_R = eno.solver.c * u_R # 右状态通量 + alpha = abs(eno.solver.c) # 最大波速 + flux[i] = 0.5 * (F_L + F_R) - 0.5 * alpha * (u_R - u_L) + + +def boundary(u, eno): + for i in range(-eno.ighost, 1): + u[eno.ist - 1 + i] = u[eno.ied + i] + for i in range(1, eno.ighost + 2): + u[eno.ied + i] = u[eno.ist - 1 + i] + +def update_oldfield(qn, q): + qn[:] = q[:] + +def init_coef( iorder, coef ): + if iorder == 1: + coef[0] = [1.0] + coef[1] = [1.0] + elif iorder == 2: + coef[0] = [3.0/2.0, -1.0/2.0] + coef[1] = [1.0/2.0, 1.0/2.0] + coef[2] = [-1.0/2.0, 3.0/2.0] + elif iorder == 3: + coef[0] = [ 11.0/6.0, -7.0/6.0, 1.0/3.0 ] + coef[1] = [ 1.0/3.0, 5.0/6.0, -1.0/6.0 ] + coef[2] = [ -1.0/6.0, 5.0/6.0, 1.0/3.0 ] + coef[3] = [ 1.0/3.0, -7.0/6.0, 11.0/6.0 ] + elif iorder == 4: + coef[0] = [ 25.0/12.0, -23.0/12.0, 13.0/12.0, -1.0/4.0 ] + coef[1] = [ 1.0/4.0, 13.0/12.0, -5.0/12.0, 1.0/12.0 ] + coef[2] = [ -1.0/12.0, 7.0/12.0, 7.0/12.0, -1.0/12.0 ] + coef[3] = [ 1.0/12.0, -5.0/12.0, 13.0/12.0, 1.0/4.0 ] + coef[4] = [ -1.0/4.0, 13.0/12.0, -23.0/12.0, 25.0/12.0 ] + elif iorder == 5: + coef[0] = [ 137.0/60.0, -163.0/60.0, 137.0/60.0, -21.0/20.0, 1.0/5.0 ] + coef[1] = [ 1.0/5.0, 77.0/60.0, -43.0/60.0, 17.0/60.0, -1.0/20.0 ] + coef[2] = [ -1.0/20.0, 9.0/20.0, 47.0/60.0, -13.0/60.0, 1.0/30.0 ] + coef[3] = [ 1.0/30.0, -13.0/60.0, 47.0/60.0, 9.0/20.0, -1.0/20.0 ] + coef[4] = [ -1.0/20.0, 17.0/60.0, -43.0/60.0, 77.0/60.0, 1.0/5.0 ] + coef[5] = [ 1.0/5.0, -21.0/20.0, 137.0/60.0, -163.0/60.0, 137.0/60.0 ] + elif iorder == 6: + coef[0] = [ 49.0/20.0, -71.0/20.0, 79.0/20.0, -163.0/60.0, 31.0/30.0, -1.0/6.0 ] + coef[1] = [ 1.0/6.0, 29.0/20.0, -21.0/20.0, 37.0/60.0, -13.0/60.0, 1.0/30.0 ] + coef[2] = [ -1.0/30.0, 11.0/30.0, 19.0/20.0, -23.0/60.0, 7.0/60.0, -1.0/60.0 ] + coef[3] = [ 1.0/60.0, -2.0/15.0, 37.0/60.0, 37.0/60.0, -2.0/15.0, 1.0/60.0 ] + coef[4] = [ -1.0/60.0, 7.0/60.0, -23.0/60.0, 19.0/20.0, 11.0/30.0, -1.0/30.0 ] + coef[5] = [ 1.0/30.0, -13.0/60.0, 37.0/60.0, -21.0/20.0, 29.0/20.0, 1.0/6.0 ] + coef[6] = [ -1.0/6.0, 31.0/30.0, -163.0/60.0, 79.0/20.0, -71.0/20.0, 49.0/20.0 ] + elif iorder == 7: + coef[0] = [ 363.0/140.0, -617.0/140.0, 853.0/140.0, -2341.0/420.0, 667.0/210.0, -43.0/42.0, 1.0/7.0 ] + coef[1] = [ 1.0/7.0, 223.0/140.0, -197.0/140.0, 153.0/140.0, -241.0/420.0, 37.0/210.0, -1.0/42.0 ] + coef[2] = [ -1.0/42.0, 13.0/42.0, 153.0/140.0, -241.0/420.0, 109.0/420.0, -31.0/420.0, 1.0/105.0 ] + coef[3] = [ 1.0/105.0, -19.0/210.0, 107.0/210.0, 319.0/420.0, -101.0/420.0, 5.0/84.0, -1.0/140.0 ] + coef[4] = [ -1.0/140.0, 5.0/84.0, -101.0/420.0, 319.0/420.0, 107.0/210.0, -19.0/210.0, 1.0/105.0 ] + coef[5] = [ 1.0/105.0, -31.0/420.0, 109.0/420.0, -241.0/420.0, 153.0/140.0, 13.0/42.0, -1.0/42.0 ] + coef[6] = [ -1.0/42.0, 37.0/210.0, -241.0/420.0, 153.0/140.0, -197.0/140.0, 223.0/140.0, 1.0/7.0 ] + coef[7] = [ 1.0/7.0, -43.0/42.0, 667.0/210.0, -2341.0/420.0, 853.0/140.0, -617.0/140.0, 363.0/140.0 ] + +def init_field(eno): + for i in range(eno.ist, eno.ied + 1): + j = i - eno.ist + if 0.5 <= eno.mesh.xcc[j] <= 1.0: + eno.u[i] = 2.0 + else: + eno.u[i] = 1.0 + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def runge_kutta(eno): + rk = eno.solver.rk + if rk == 1: + runge_kutta_1(eno) + elif rk == 2: + runge_kutta_2(eno) + else: + runge_kutta_3(eno) + +def runge_kutta_1(eno): + dt = eno.solver.dt + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = eno.u[j] + dt * eno.res[i] + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def runge_kutta_2(eno): + dt = eno.solver.dt + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = eno.u[j] + dt * eno.res[i] + boundary(eno.u, eno) + + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = 0.5 * eno.un[j] + 0.5 * eno.u[j] + 0.5 * dt * eno.res[i] + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def runge_kutta_3(eno): + dt = eno.solver.dt + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = eno.u[j] + dt * eno.res[i] + boundary(eno.u, eno) + + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = 0.75 * eno.un[j] + 0.25 * eno.u[j] + 0.25 * dt * eno.res[i] + boundary(eno.u, eno) + + residual(eno.u, eno) + c1, c2, c3 = 1.0/3.0, 2.0/3.0, 2.0/3.0 + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = c1 * eno.un[j] + c2 * eno.u[j] + c3 * dt * eno.res[i] + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def get_ordinal_numbers(order): + if order == 1: + return 'st' + elif order == 2: + return 'nd' + elif order == 3: + return 'rd' + else: + return 'th' + +def visualize(eno): + with open('solution.plt', 'w') as f: + for i in range(eno.ist, eno.ied + 1): + j = i - eno.ist + f.write(f"{eno.xcc[j]:20.10e}{eno.u[i]:20.10e}\n") + + # 可视化 + u_numerical = np.copy(eno.u[eno.ist:eno.ied+1]) + print(f'u_numerical.size={u_numerical.size}') + print(f'eno.xcc.size={eno.xcc.size}') + #计算理论解 + u_analytical = analytical_solution(eno.mesh.xcc, eno.T, eno.c, eno.L) + print(f'u_analytical.size={u_analytical.size}') + plt.figure("OneFLOW-CFD Solver", figsize=(10, 6)) + plt.scatter(eno.xcc, u_numerical, facecolor="none", edgecolor="blue", s=20, linewidths=0.5, label=f'Numerical (Rusanov)') + plt.plot(eno.xcc, u_analytical, 'r--', label='Analytical') + plt.xlabel('x') + plt.ylabel('u') + ordinal1 = get_ordinal_numbers(eno.iorder) + ordinal2 = get_ordinal_numbers(eno.rk) + plt.title(f'1D Convection Equation at t = {eno.T:.3f} using {eno.iorder}{ordinal1}-order ENO and {eno.rk}{ordinal2}-order Runge-Kutta methods') + plt.legend() + plt.grid(True, color='gray', linestyle='--', linewidth=0.5, alpha=0.7) + plt.tight_layout() + plt.show() + +class Mesh: + def __init__(self): + self.nx = 40 + self.L = 2.0 + self.x = np.zeros(self.nx + 1) + self.xcc = np.zeros(self.nx) + self.init_mesh() + def init_mesh(self): + xstart = 0.0 + xend = self.L + self.dx = (xend - xstart) / self.nx + + for i in range(0, self.nx+1): + self.x[i] = xstart + i * self.dx + + for i in range(0, self.nx): + self.xcc[i] = 0.5 * (self.x[i] + self.x[i + 1]) + +class Solver: + def __init__(self): + self.iflux = 0 + self.rk = 1 + self.c = 1.0 + self.T = 0.625 + self.dt = .0025 + +class Eno: + def __init__(self, solver, mesh, iorder): + self.solver = solver + self.mesh = mesh + self.nx = mesh.nx + self.iorder = iorder + self.ighost = iorder + self.ishift = self.ighost + 1 + self.ist = 0 + self.ishift + self.ied = self.nx - 1 + self.ishift + self.ntcell = self.nx + 2 * self.ishift + self.isize = iorder * (iorder + 1) + + self.il = np.zeros(self.nx + 1, dtype=int) + self.ir = np.zeros(self.nx + 1, dtype=int) + self.coef = np.zeros((iorder + 1, iorder)) + self.dd = np.zeros((iorder, self.ntcell)) + self.up1_2m = np.zeros(self.nx + 1) + self.up1_2p = np.zeros(self.nx + 1) + self.flux = np.zeros(self.nx + 1) + self.res = np.zeros(self.nx) + + # Field module variables + self.u = np.zeros(self.ntcell) + self.un = np.zeros(self.ntcell) + + #self.dt = .0025 + +def plot_eno_OrderAnalysis(solver, xcc, u_list, u_analytical): + # 定义一个包含不同颜色、线形和标记的列表 + styles = [ + {'color': 'black', 'linestyle': '-', 'marker': 'o'}, + {'color': 'blue', 'linestyle': '--', 'marker': 's'}, + {'color': 'black', 'linestyle': '-', 'marker': '^'}, + {'color': 'blue', 'linestyle': '--', 'marker': 'v'}, + {'color': 'black', 'linestyle': '-', 'marker': '<'}, + {'color': 'blue', 'linestyle': '--', 'marker': '>'}, + {'color': 'black', 'linestyle': '-', 'marker': 'D'}, + ] + + n = len(u_list) + num_styles = len(styles) + ordinal = get_ordinal_numbers(solver.rk) + + plt.figure("OneFLOW-CFD Solver", figsize=(10, 6)) + plt.title(f'1D Convection Equation at t = {solver.T:.3f} using [1-7]th-order ENO and {solver.rk}{ordinal}-order Runge-Kutta methods') + for i in range(0, n): + lable = 'Numerical (Rusanov)ENO' + str(i+1) + style = styles[i % num_styles] + plt.plot(xcc, u_list[i], marker=style['marker'], markerfacecolor='none', linestyle=style['linestyle'], color=style['color'], \ + markersize=5, linewidth=0.5, alpha=1.0, label=f'{lable}') + plt.plot(xcc, u_analytical, 'r--', label='Analytical') + plt.xlabel('x') + plt.ylabel('u') + plt.legend() + plt.grid(True, color='gray', linestyle='--', linewidth=0.5, alpha=0.7) + plt.tight_layout() + plt.show() + +def plot_eno_TimestepAnalysis(solver, xcc, u_list, u_analytical, dt_list, iorder): + # 定义一个包含不同颜色、线形和标记的列表 + styles = [ + {'color': 'black', 'linestyle': '-', 'marker': 'o'}, + {'color': 'blue', 'linestyle': '--', 'marker': 's'}, + {'color': 'black', 'linestyle': '-', 'marker': '^'}, + {'color': 'blue', 'linestyle': '--', 'marker': 'v'}, + {'color': 'black', 'linestyle': '-', 'marker': '<'}, + {'color': 'blue', 'linestyle': '--', 'marker': '>'}, + {'color': 'black', 'linestyle': '-', 'marker': 'D'}, + {'color': 'blue', 'linestyle': '--', 'marker': 'o'}, + {'color': 'black', 'linestyle': '-', 'marker': 's'}, + {'color': 'blue', 'linestyle': '--', 'marker': '^'}, + {'color': 'black', 'linestyle': '-', 'marker': 'v'}, + {'color': 'blue', 'linestyle': '--', 'marker': '<'}, + {'color': 'black', 'linestyle': '-', 'marker': '>'}, + {'color': 'blue', 'linestyle': '--', 'marker': 'D'}, + ] + + n = len(u_list) + num_styles = len(styles) + + ordinalENO = get_ordinal_numbers(iorder) + ordinalRK = get_ordinal_numbers(solver.rk) + + plt.figure("OneFLOW-CFD Solver", figsize=(10, 6)) + plt.title(f'1D Convection Equation at t = {solver.T:.3f} using {iorder}{ordinalENO}-order ENO and {solver.rk}{ordinalRK}-order Runge-Kutta methods') + for i in range(0, n): + lable = 'Numerical (Rusanov)ENO' + str(iorder) + ' T='+str(dt_list[i]) + style = styles[i % num_styles] + plt.plot(xcc, u_list[i], marker=style['marker'], markerfacecolor='none', linestyle=style['linestyle'], color=style['color'], \ + markersize=5, linewidth=1.0, alpha=1.0, label=f'{lable}') + plt.plot(xcc, u_analytical, 'r--', label='Analytical') + plt.xlabel('x') + plt.ylabel('u') + plt.legend() + plt.grid(True, color='gray', linestyle='--', linewidth=0.5, alpha=0.7) + plt.tight_layout() + plt.show() + +def RunEno(solver, mesh, iorder): + eno = Eno(solver, mesh, iorder) + init_coef(eno.iorder, eno.coef) + init_field(eno) + + simu_time = solver.T + t = 0.0 + dt = solver.dt + while t < simu_time: + runge_kutta(eno) + if t + dt > simu_time: + dt = simu_time - t + t += dt + #print(f'T={t:.3f},runge_kutta{solver.rk},ENO{eno.iorder},{fluxnames[solver.iflux]} FLUX') + #visualize(eno) + return np.copy(eno.u[eno.ist:eno.ied+1]) + +def performEnoOrderAnalysis(): + iorder_max = 7 + mesh = Mesh() + solver = Solver() + #计算理论解 + u_analytical = analytical_solution(mesh.xcc, solver.T, solver.c, mesh.L) + + u_list = [] + for iorder in range(1, iorder_max+1): + u = RunEno(solver, mesh, iorder) + u_list.append(u) + + plot_eno_OrderAnalysis(solver, mesh.xcc, u_list, u_analytical) + +def performEnoTimestepAnalysis(): + mesh = Mesh() + solver = Solver() + #计算理论解 + u_analytical = analytical_solution(mesh.xcc, solver.T, solver.c, mesh.L) + + u_list = [] + dt_list = [] + solver.dt = 0.025 + #solver.dt = 0.025/16 + n = 12 + solver.rk = 2 + iorder = 3 + for i in range(0, n): + u = RunEno(solver, mesh, iorder) + u_list.append(u) + dt_list.append(solver.dt) + print(f'i={i+1},N={n},T={solver.T:.3f},dt={solver.dt},nt={int(solver.T/solver.dt)},runge_kutta{solver.rk},ENO{iorder},{fluxnames[solver.iflux]} FLUX') + solver.dt /= 2 + + plot_eno_TimestepAnalysis(solver, mesh.xcc, u_list, u_analytical, dt_list, iorder) + +def main(): + #performEnoOrderAnalysis() + performEnoTimestepAnalysis() + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/example/1d-linear-convection/eno/rusanov/timestep/rk2-eno/eno3/01/plot.py b/example/1d-linear-convection/eno/rusanov/timestep/rk2-eno/eno3/01/plot.py new file mode 100644 index 00000000..e389044c --- /dev/null +++ b/example/1d-linear-convection/eno/rusanov/timestep/rk2-eno/eno3/01/plot.py @@ -0,0 +1,53 @@ +import numpy as np +import matplotlib.pyplot as plt +import csv +import sys + +nvar = len(sys.argv) +print('nvar=',nvar) +print('sys.argv=',sys.argv) + +order = 1 +if nvar >= 2: + var = sys.argv[1] + print('var=',var) + order = int(var) + +print('order=',order) + +x_list = [] +u_list = [] + +with open('solution.plt', newline='') as csvfile: + #readCSV = csv.reader(csvfile, delimiter= ' ') + icount = 0 + for line in csvfile: + # 去除首尾空格,按连续空格分割 + row = line.strip().split() + #print("row=",row) + x_list.append(row[0]) + u_list.append(row[1]) + icount += 1 + +ni = icount +print("ni=",ni) + +#print("x_list=",x_list) + +x = np.zeros( ni ) +u = np.zeros( ni ) + +for i in range(0, ni): + x[i] = float(x_list[i]) + u[i] = float(u_list[i]) + +labelname = 'Eno' + str(order) + +plt.figure("OneFLOW-CFD Solver", figsize=(8, 6), dpi=100) +plt.plot(x, u, "b-", linewidth=1.0, marker = 's', markerfacecolor='None', label=labelname) +plt.xlabel("$x$") +plt.ylabel("$u$") +plt.title("burgers T=1") +plt.legend() +plt.tight_layout() +plt.show(); \ No newline at end of file diff --git a/example/1d-linear-convection/eno/rusanov/timestep/rk2-eno/eno4/01/eno.py b/example/1d-linear-convection/eno/rusanov/timestep/rk2-eno/eno4/01/eno.py new file mode 100644 index 00000000..4f19f721 --- /dev/null +++ b/example/1d-linear-convection/eno/rusanov/timestep/rk2-eno/eno4/01/eno.py @@ -0,0 +1,426 @@ +import numpy as np +import matplotlib.pyplot as plt + +# 初始条件 +def initial_condition(x): + u0 = np.zeros_like(x) + for i in range(len(x)): + if 0.5 <= x[i] <= 1.0: + u0[i] = 2.0 + else: + u0[i] = 1.0 + return u0 + +# 理论解 +def analytical_solution(x, t, a, L): + # 初始条件沿 x - at 平移 + x_shifted = x - a * t + return initial_condition((x_shifted + L) % L) # 周期边界条件 + +def residual(q, eno): + reconstruction(q, eno) + inviscid_flux(eno.up1_2m, eno.up1_2p, eno.flux, eno) + for i in range(eno.nx): + eno.res[i] = -(eno.flux[i + 1] - eno.flux[i]) / eno.mesh.dx + +def reconstruction(q, eno): + # Choose the stencil by ENO method + eno.dd[0, 0:eno.ntcell-1] = q[0:eno.ntcell-1] + + for m in range(1, eno.iorder): + for j in range(0, eno.ntcell-1): + eno.dd[m, j] = eno.dd[m-1, j+1] - eno.dd[m-1, j] + + for i in range(eno.nx + 1): + eno.il[i] = i - 1 + for m in range(1, eno.iorder): + if abs(eno.dd[m, eno.il[i]-1+eno.ishift]) <= abs(eno.dd[m, eno.il[i]+eno.ishift]): + eno.il[i] -= 1 + + for i in range(eno.nx + 1): + eno.ir[i] = i + for m in range(1, eno.iorder): + if abs(eno.dd[m, eno.ir[i]-1+eno.ishift]) <= abs(eno.dd[m, eno.ir[i]+eno.ishift]): + eno.ir[i] -= 1 + + # Reconstruction u(j+1/2) + for i in range(eno.nx + 1): + k1 = eno.il[i] + k2 = eno.ir[i] + l1 = i - k1 + l2 = i - k2 + eno.up1_2m[i] = 0 + eno.up1_2p[i] = 0 + for m in range(eno.iorder): + eno.up1_2m[i] += q[k1 + eno.ishift + m] * eno.coef[l1, m] + eno.up1_2p[i] += q[k2 + eno.ishift + m] * eno.coef[l2, m] + +fluxnames = [ + 'Rusanov', + 'Engquist-Osher', +] + +def inviscid_flux(up1_2m, up1_2p, flux, eno): + if eno.solver.iflux == 0: + rusanov_flux(up1_2m, up1_2p, flux, eno) + else: + engquist_osher_flux(up1_2m, up1_2p, flux, eno) + +def engquist_osher_flux(up1_2m, up1_2p, flux, eno): + for i in range(eno.nx + 1): + u_L = up1_2m[i] + u_R = up1_2p[i] + + cp = 0.5 * ( eno.solver.c + abs(eno.solver.c) ) + cm = 0.5 * ( eno.solver.c - abs(eno.solver.c) ) + + flux[i] = cp * u_L + cm * u_R + +def rusanov_flux(up1_2m, up1_2p, flux, eno): + for i in range(eno.nx + 1): + u_L = up1_2m[i] + u_R = up1_2p[i] + F_L = eno.solver.c * u_L # 左状态通量 + F_R = eno.solver.c * u_R # 右状态通量 + alpha = abs(eno.solver.c) # 最大波速 + flux[i] = 0.5 * (F_L + F_R) - 0.5 * alpha * (u_R - u_L) + + +def boundary(u, eno): + for i in range(-eno.ighost, 1): + u[eno.ist - 1 + i] = u[eno.ied + i] + for i in range(1, eno.ighost + 2): + u[eno.ied + i] = u[eno.ist - 1 + i] + +def update_oldfield(qn, q): + qn[:] = q[:] + +def init_coef( iorder, coef ): + if iorder == 1: + coef[0] = [1.0] + coef[1] = [1.0] + elif iorder == 2: + coef[0] = [3.0/2.0, -1.0/2.0] + coef[1] = [1.0/2.0, 1.0/2.0] + coef[2] = [-1.0/2.0, 3.0/2.0] + elif iorder == 3: + coef[0] = [ 11.0/6.0, -7.0/6.0, 1.0/3.0 ] + coef[1] = [ 1.0/3.0, 5.0/6.0, -1.0/6.0 ] + coef[2] = [ -1.0/6.0, 5.0/6.0, 1.0/3.0 ] + coef[3] = [ 1.0/3.0, -7.0/6.0, 11.0/6.0 ] + elif iorder == 4: + coef[0] = [ 25.0/12.0, -23.0/12.0, 13.0/12.0, -1.0/4.0 ] + coef[1] = [ 1.0/4.0, 13.0/12.0, -5.0/12.0, 1.0/12.0 ] + coef[2] = [ -1.0/12.0, 7.0/12.0, 7.0/12.0, -1.0/12.0 ] + coef[3] = [ 1.0/12.0, -5.0/12.0, 13.0/12.0, 1.0/4.0 ] + coef[4] = [ -1.0/4.0, 13.0/12.0, -23.0/12.0, 25.0/12.0 ] + elif iorder == 5: + coef[0] = [ 137.0/60.0, -163.0/60.0, 137.0/60.0, -21.0/20.0, 1.0/5.0 ] + coef[1] = [ 1.0/5.0, 77.0/60.0, -43.0/60.0, 17.0/60.0, -1.0/20.0 ] + coef[2] = [ -1.0/20.0, 9.0/20.0, 47.0/60.0, -13.0/60.0, 1.0/30.0 ] + coef[3] = [ 1.0/30.0, -13.0/60.0, 47.0/60.0, 9.0/20.0, -1.0/20.0 ] + coef[4] = [ -1.0/20.0, 17.0/60.0, -43.0/60.0, 77.0/60.0, 1.0/5.0 ] + coef[5] = [ 1.0/5.0, -21.0/20.0, 137.0/60.0, -163.0/60.0, 137.0/60.0 ] + elif iorder == 6: + coef[0] = [ 49.0/20.0, -71.0/20.0, 79.0/20.0, -163.0/60.0, 31.0/30.0, -1.0/6.0 ] + coef[1] = [ 1.0/6.0, 29.0/20.0, -21.0/20.0, 37.0/60.0, -13.0/60.0, 1.0/30.0 ] + coef[2] = [ -1.0/30.0, 11.0/30.0, 19.0/20.0, -23.0/60.0, 7.0/60.0, -1.0/60.0 ] + coef[3] = [ 1.0/60.0, -2.0/15.0, 37.0/60.0, 37.0/60.0, -2.0/15.0, 1.0/60.0 ] + coef[4] = [ -1.0/60.0, 7.0/60.0, -23.0/60.0, 19.0/20.0, 11.0/30.0, -1.0/30.0 ] + coef[5] = [ 1.0/30.0, -13.0/60.0, 37.0/60.0, -21.0/20.0, 29.0/20.0, 1.0/6.0 ] + coef[6] = [ -1.0/6.0, 31.0/30.0, -163.0/60.0, 79.0/20.0, -71.0/20.0, 49.0/20.0 ] + elif iorder == 7: + coef[0] = [ 363.0/140.0, -617.0/140.0, 853.0/140.0, -2341.0/420.0, 667.0/210.0, -43.0/42.0, 1.0/7.0 ] + coef[1] = [ 1.0/7.0, 223.0/140.0, -197.0/140.0, 153.0/140.0, -241.0/420.0, 37.0/210.0, -1.0/42.0 ] + coef[2] = [ -1.0/42.0, 13.0/42.0, 153.0/140.0, -241.0/420.0, 109.0/420.0, -31.0/420.0, 1.0/105.0 ] + coef[3] = [ 1.0/105.0, -19.0/210.0, 107.0/210.0, 319.0/420.0, -101.0/420.0, 5.0/84.0, -1.0/140.0 ] + coef[4] = [ -1.0/140.0, 5.0/84.0, -101.0/420.0, 319.0/420.0, 107.0/210.0, -19.0/210.0, 1.0/105.0 ] + coef[5] = [ 1.0/105.0, -31.0/420.0, 109.0/420.0, -241.0/420.0, 153.0/140.0, 13.0/42.0, -1.0/42.0 ] + coef[6] = [ -1.0/42.0, 37.0/210.0, -241.0/420.0, 153.0/140.0, -197.0/140.0, 223.0/140.0, 1.0/7.0 ] + coef[7] = [ 1.0/7.0, -43.0/42.0, 667.0/210.0, -2341.0/420.0, 853.0/140.0, -617.0/140.0, 363.0/140.0 ] + +def init_field(eno): + for i in range(eno.ist, eno.ied + 1): + j = i - eno.ist + if 0.5 <= eno.mesh.xcc[j] <= 1.0: + eno.u[i] = 2.0 + else: + eno.u[i] = 1.0 + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def runge_kutta(eno): + rk = eno.solver.rk + if rk == 1: + runge_kutta_1(eno) + elif rk == 2: + runge_kutta_2(eno) + else: + runge_kutta_3(eno) + +def runge_kutta_1(eno): + dt = eno.solver.dt + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = eno.u[j] + dt * eno.res[i] + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def runge_kutta_2(eno): + dt = eno.solver.dt + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = eno.u[j] + dt * eno.res[i] + boundary(eno.u, eno) + + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = 0.5 * eno.un[j] + 0.5 * eno.u[j] + 0.5 * dt * eno.res[i] + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def runge_kutta_3(eno): + dt = eno.solver.dt + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = eno.u[j] + dt * eno.res[i] + boundary(eno.u, eno) + + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = 0.75 * eno.un[j] + 0.25 * eno.u[j] + 0.25 * dt * eno.res[i] + boundary(eno.u, eno) + + residual(eno.u, eno) + c1, c2, c3 = 1.0/3.0, 2.0/3.0, 2.0/3.0 + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = c1 * eno.un[j] + c2 * eno.u[j] + c3 * dt * eno.res[i] + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def get_ordinal_numbers(order): + if order == 1: + return 'st' + elif order == 2: + return 'nd' + elif order == 3: + return 'rd' + else: + return 'th' + +def visualize(eno): + with open('solution.plt', 'w') as f: + for i in range(eno.ist, eno.ied + 1): + j = i - eno.ist + f.write(f"{eno.xcc[j]:20.10e}{eno.u[i]:20.10e}\n") + + # 可视化 + u_numerical = np.copy(eno.u[eno.ist:eno.ied+1]) + print(f'u_numerical.size={u_numerical.size}') + print(f'eno.xcc.size={eno.xcc.size}') + #计算理论解 + u_analytical = analytical_solution(eno.mesh.xcc, eno.T, eno.c, eno.L) + print(f'u_analytical.size={u_analytical.size}') + plt.figure("OneFLOW-CFD Solver", figsize=(10, 6)) + plt.scatter(eno.xcc, u_numerical, facecolor="none", edgecolor="blue", s=20, linewidths=0.5, label=f'Numerical (Rusanov)') + plt.plot(eno.xcc, u_analytical, 'r--', label='Analytical') + plt.xlabel('x') + plt.ylabel('u') + ordinal1 = get_ordinal_numbers(eno.iorder) + ordinal2 = get_ordinal_numbers(eno.rk) + plt.title(f'1D Convection Equation at t = {eno.T:.3f} using {eno.iorder}{ordinal1}-order ENO and {eno.rk}{ordinal2}-order Runge-Kutta methods') + plt.legend() + plt.grid(True, color='gray', linestyle='--', linewidth=0.5, alpha=0.7) + plt.tight_layout() + plt.show() + +class Mesh: + def __init__(self): + self.nx = 40 + self.L = 2.0 + self.x = np.zeros(self.nx + 1) + self.xcc = np.zeros(self.nx) + self.init_mesh() + def init_mesh(self): + xstart = 0.0 + xend = self.L + self.dx = (xend - xstart) / self.nx + + for i in range(0, self.nx+1): + self.x[i] = xstart + i * self.dx + + for i in range(0, self.nx): + self.xcc[i] = 0.5 * (self.x[i] + self.x[i + 1]) + +class Solver: + def __init__(self): + self.iflux = 0 + self.rk = 1 + self.c = 1.0 + self.T = 0.625 + self.dt = .0025 + +class Eno: + def __init__(self, solver, mesh, iorder): + self.solver = solver + self.mesh = mesh + self.nx = mesh.nx + self.iorder = iorder + self.ighost = iorder + self.ishift = self.ighost + 1 + self.ist = 0 + self.ishift + self.ied = self.nx - 1 + self.ishift + self.ntcell = self.nx + 2 * self.ishift + self.isize = iorder * (iorder + 1) + + self.il = np.zeros(self.nx + 1, dtype=int) + self.ir = np.zeros(self.nx + 1, dtype=int) + self.coef = np.zeros((iorder + 1, iorder)) + self.dd = np.zeros((iorder, self.ntcell)) + self.up1_2m = np.zeros(self.nx + 1) + self.up1_2p = np.zeros(self.nx + 1) + self.flux = np.zeros(self.nx + 1) + self.res = np.zeros(self.nx) + + # Field module variables + self.u = np.zeros(self.ntcell) + self.un = np.zeros(self.ntcell) + + #self.dt = .0025 + +def plot_eno_OrderAnalysis(solver, xcc, u_list, u_analytical): + # 定义一个包含不同颜色、线形和标记的列表 + styles = [ + {'color': 'black', 'linestyle': '-', 'marker': 'o'}, + {'color': 'blue', 'linestyle': '--', 'marker': 's'}, + {'color': 'black', 'linestyle': '-', 'marker': '^'}, + {'color': 'blue', 'linestyle': '--', 'marker': 'v'}, + {'color': 'black', 'linestyle': '-', 'marker': '<'}, + {'color': 'blue', 'linestyle': '--', 'marker': '>'}, + {'color': 'black', 'linestyle': '-', 'marker': 'D'}, + ] + + n = len(u_list) + num_styles = len(styles) + ordinal = get_ordinal_numbers(solver.rk) + + plt.figure("OneFLOW-CFD Solver", figsize=(10, 6)) + plt.title(f'1D Convection Equation at t = {solver.T:.3f} using [1-7]th-order ENO and {solver.rk}{ordinal}-order Runge-Kutta methods') + for i in range(0, n): + lable = 'Numerical (Rusanov)ENO' + str(i+1) + style = styles[i % num_styles] + plt.plot(xcc, u_list[i], marker=style['marker'], markerfacecolor='none', linestyle=style['linestyle'], color=style['color'], \ + markersize=5, linewidth=0.5, alpha=1.0, label=f'{lable}') + plt.plot(xcc, u_analytical, 'r--', label='Analytical') + plt.xlabel('x') + plt.ylabel('u') + plt.legend() + plt.grid(True, color='gray', linestyle='--', linewidth=0.5, alpha=0.7) + plt.tight_layout() + plt.show() + +def plot_eno_TimestepAnalysis(solver, xcc, u_list, u_analytical, dt_list, iorder): + # 定义一个包含不同颜色、线形和标记的列表 + styles = [ + {'color': 'black', 'linestyle': '-', 'marker': 'o'}, + {'color': 'blue', 'linestyle': '--', 'marker': 's'}, + {'color': 'black', 'linestyle': '-', 'marker': '^'}, + {'color': 'blue', 'linestyle': '--', 'marker': 'v'}, + {'color': 'black', 'linestyle': '-', 'marker': '<'}, + {'color': 'blue', 'linestyle': '--', 'marker': '>'}, + {'color': 'black', 'linestyle': '-', 'marker': 'D'}, + {'color': 'blue', 'linestyle': '--', 'marker': 'o'}, + {'color': 'black', 'linestyle': '-', 'marker': 's'}, + {'color': 'blue', 'linestyle': '--', 'marker': '^'}, + {'color': 'black', 'linestyle': '-', 'marker': 'v'}, + {'color': 'blue', 'linestyle': '--', 'marker': '<'}, + {'color': 'black', 'linestyle': '-', 'marker': '>'}, + {'color': 'blue', 'linestyle': '--', 'marker': 'D'}, + ] + + n = len(u_list) + num_styles = len(styles) + + ordinalENO = get_ordinal_numbers(iorder) + ordinalRK = get_ordinal_numbers(solver.rk) + + plt.figure("OneFLOW-CFD Solver", figsize=(10, 6)) + plt.title(f'1D Convection Equation at t = {solver.T:.3f} using {iorder}{ordinalENO}-order ENO and {solver.rk}{ordinalRK}-order Runge-Kutta methods') + for i in range(0, n): + lable = 'Numerical (Rusanov)ENO' + str(iorder) + ' T='+str(dt_list[i]) + style = styles[i % num_styles] + plt.plot(xcc, u_list[i], marker=style['marker'], markerfacecolor='none', linestyle=style['linestyle'], color=style['color'], \ + markersize=5, linewidth=1.0, alpha=1.0, label=f'{lable}') + plt.plot(xcc, u_analytical, 'r--', label='Analytical') + plt.xlabel('x') + plt.ylabel('u') + plt.legend() + plt.grid(True, color='gray', linestyle='--', linewidth=0.5, alpha=0.7) + plt.tight_layout() + plt.show() + +def RunEno(solver, mesh, iorder): + eno = Eno(solver, mesh, iorder) + init_coef(eno.iorder, eno.coef) + init_field(eno) + + simu_time = solver.T + t = 0.0 + dt = solver.dt + while t < simu_time: + runge_kutta(eno) + if t + dt > simu_time: + dt = simu_time - t + t += dt + #print(f'T={t:.3f},runge_kutta{solver.rk},ENO{eno.iorder},{fluxnames[solver.iflux]} FLUX') + #visualize(eno) + return np.copy(eno.u[eno.ist:eno.ied+1]) + +def performEnoOrderAnalysis(): + iorder_max = 7 + mesh = Mesh() + solver = Solver() + #计算理论解 + u_analytical = analytical_solution(mesh.xcc, solver.T, solver.c, mesh.L) + + u_list = [] + for iorder in range(1, iorder_max+1): + u = RunEno(solver, mesh, iorder) + u_list.append(u) + + plot_eno_OrderAnalysis(solver, mesh.xcc, u_list, u_analytical) + +def performEnoTimestepAnalysis(): + mesh = Mesh() + solver = Solver() + #计算理论解 + u_analytical = analytical_solution(mesh.xcc, solver.T, solver.c, mesh.L) + + u_list = [] + dt_list = [] + solver.dt = 0.025/4 + #solver.dt = 0.025/16 + n = 12 + solver.rk = 2 + iorder = 4 + for i in range(0, n): + u = RunEno(solver, mesh, iorder) + u_list.append(u) + dt_list.append(solver.dt) + print(f'i={i+1},N={n},T={solver.T:.3f},dt={solver.dt},nt={int(solver.T/solver.dt)},runge_kutta{solver.rk},ENO{iorder},{fluxnames[solver.iflux]} FLUX') + solver.dt /= 2 + + plot_eno_TimestepAnalysis(solver, mesh.xcc, u_list, u_analytical, dt_list, iorder) + +def main(): + #performEnoOrderAnalysis() + performEnoTimestepAnalysis() + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/example/1d-linear-convection/eno/rusanov/timestep/rk2-eno/eno4/01/plot.py b/example/1d-linear-convection/eno/rusanov/timestep/rk2-eno/eno4/01/plot.py new file mode 100644 index 00000000..e389044c --- /dev/null +++ b/example/1d-linear-convection/eno/rusanov/timestep/rk2-eno/eno4/01/plot.py @@ -0,0 +1,53 @@ +import numpy as np +import matplotlib.pyplot as plt +import csv +import sys + +nvar = len(sys.argv) +print('nvar=',nvar) +print('sys.argv=',sys.argv) + +order = 1 +if nvar >= 2: + var = sys.argv[1] + print('var=',var) + order = int(var) + +print('order=',order) + +x_list = [] +u_list = [] + +with open('solution.plt', newline='') as csvfile: + #readCSV = csv.reader(csvfile, delimiter= ' ') + icount = 0 + for line in csvfile: + # 去除首尾空格,按连续空格分割 + row = line.strip().split() + #print("row=",row) + x_list.append(row[0]) + u_list.append(row[1]) + icount += 1 + +ni = icount +print("ni=",ni) + +#print("x_list=",x_list) + +x = np.zeros( ni ) +u = np.zeros( ni ) + +for i in range(0, ni): + x[i] = float(x_list[i]) + u[i] = float(u_list[i]) + +labelname = 'Eno' + str(order) + +plt.figure("OneFLOW-CFD Solver", figsize=(8, 6), dpi=100) +plt.plot(x, u, "b-", linewidth=1.0, marker = 's', markerfacecolor='None', label=labelname) +plt.xlabel("$x$") +plt.ylabel("$u$") +plt.title("burgers T=1") +plt.legend() +plt.tight_layout() +plt.show(); \ No newline at end of file diff --git a/example/1d-linear-convection/eno/rusanov/timestep/rk2-eno/eno5/01/eno.py b/example/1d-linear-convection/eno/rusanov/timestep/rk2-eno/eno5/01/eno.py new file mode 100644 index 00000000..9cd95dcc --- /dev/null +++ b/example/1d-linear-convection/eno/rusanov/timestep/rk2-eno/eno5/01/eno.py @@ -0,0 +1,426 @@ +import numpy as np +import matplotlib.pyplot as plt + +# 初始条件 +def initial_condition(x): + u0 = np.zeros_like(x) + for i in range(len(x)): + if 0.5 <= x[i] <= 1.0: + u0[i] = 2.0 + else: + u0[i] = 1.0 + return u0 + +# 理论解 +def analytical_solution(x, t, a, L): + # 初始条件沿 x - at 平移 + x_shifted = x - a * t + return initial_condition((x_shifted + L) % L) # 周期边界条件 + +def residual(q, eno): + reconstruction(q, eno) + inviscid_flux(eno.up1_2m, eno.up1_2p, eno.flux, eno) + for i in range(eno.nx): + eno.res[i] = -(eno.flux[i + 1] - eno.flux[i]) / eno.mesh.dx + +def reconstruction(q, eno): + # Choose the stencil by ENO method + eno.dd[0, 0:eno.ntcell-1] = q[0:eno.ntcell-1] + + for m in range(1, eno.iorder): + for j in range(0, eno.ntcell-1): + eno.dd[m, j] = eno.dd[m-1, j+1] - eno.dd[m-1, j] + + for i in range(eno.nx + 1): + eno.il[i] = i - 1 + for m in range(1, eno.iorder): + if abs(eno.dd[m, eno.il[i]-1+eno.ishift]) <= abs(eno.dd[m, eno.il[i]+eno.ishift]): + eno.il[i] -= 1 + + for i in range(eno.nx + 1): + eno.ir[i] = i + for m in range(1, eno.iorder): + if abs(eno.dd[m, eno.ir[i]-1+eno.ishift]) <= abs(eno.dd[m, eno.ir[i]+eno.ishift]): + eno.ir[i] -= 1 + + # Reconstruction u(j+1/2) + for i in range(eno.nx + 1): + k1 = eno.il[i] + k2 = eno.ir[i] + l1 = i - k1 + l2 = i - k2 + eno.up1_2m[i] = 0 + eno.up1_2p[i] = 0 + for m in range(eno.iorder): + eno.up1_2m[i] += q[k1 + eno.ishift + m] * eno.coef[l1, m] + eno.up1_2p[i] += q[k2 + eno.ishift + m] * eno.coef[l2, m] + +fluxnames = [ + 'Rusanov', + 'Engquist-Osher', +] + +def inviscid_flux(up1_2m, up1_2p, flux, eno): + if eno.solver.iflux == 0: + rusanov_flux(up1_2m, up1_2p, flux, eno) + else: + engquist_osher_flux(up1_2m, up1_2p, flux, eno) + +def engquist_osher_flux(up1_2m, up1_2p, flux, eno): + for i in range(eno.nx + 1): + u_L = up1_2m[i] + u_R = up1_2p[i] + + cp = 0.5 * ( eno.solver.c + abs(eno.solver.c) ) + cm = 0.5 * ( eno.solver.c - abs(eno.solver.c) ) + + flux[i] = cp * u_L + cm * u_R + +def rusanov_flux(up1_2m, up1_2p, flux, eno): + for i in range(eno.nx + 1): + u_L = up1_2m[i] + u_R = up1_2p[i] + F_L = eno.solver.c * u_L # 左状态通量 + F_R = eno.solver.c * u_R # 右状态通量 + alpha = abs(eno.solver.c) # 最大波速 + flux[i] = 0.5 * (F_L + F_R) - 0.5 * alpha * (u_R - u_L) + + +def boundary(u, eno): + for i in range(-eno.ighost, 1): + u[eno.ist - 1 + i] = u[eno.ied + i] + for i in range(1, eno.ighost + 2): + u[eno.ied + i] = u[eno.ist - 1 + i] + +def update_oldfield(qn, q): + qn[:] = q[:] + +def init_coef( iorder, coef ): + if iorder == 1: + coef[0] = [1.0] + coef[1] = [1.0] + elif iorder == 2: + coef[0] = [3.0/2.0, -1.0/2.0] + coef[1] = [1.0/2.0, 1.0/2.0] + coef[2] = [-1.0/2.0, 3.0/2.0] + elif iorder == 3: + coef[0] = [ 11.0/6.0, -7.0/6.0, 1.0/3.0 ] + coef[1] = [ 1.0/3.0, 5.0/6.0, -1.0/6.0 ] + coef[2] = [ -1.0/6.0, 5.0/6.0, 1.0/3.0 ] + coef[3] = [ 1.0/3.0, -7.0/6.0, 11.0/6.0 ] + elif iorder == 4: + coef[0] = [ 25.0/12.0, -23.0/12.0, 13.0/12.0, -1.0/4.0 ] + coef[1] = [ 1.0/4.0, 13.0/12.0, -5.0/12.0, 1.0/12.0 ] + coef[2] = [ -1.0/12.0, 7.0/12.0, 7.0/12.0, -1.0/12.0 ] + coef[3] = [ 1.0/12.0, -5.0/12.0, 13.0/12.0, 1.0/4.0 ] + coef[4] = [ -1.0/4.0, 13.0/12.0, -23.0/12.0, 25.0/12.0 ] + elif iorder == 5: + coef[0] = [ 137.0/60.0, -163.0/60.0, 137.0/60.0, -21.0/20.0, 1.0/5.0 ] + coef[1] = [ 1.0/5.0, 77.0/60.0, -43.0/60.0, 17.0/60.0, -1.0/20.0 ] + coef[2] = [ -1.0/20.0, 9.0/20.0, 47.0/60.0, -13.0/60.0, 1.0/30.0 ] + coef[3] = [ 1.0/30.0, -13.0/60.0, 47.0/60.0, 9.0/20.0, -1.0/20.0 ] + coef[4] = [ -1.0/20.0, 17.0/60.0, -43.0/60.0, 77.0/60.0, 1.0/5.0 ] + coef[5] = [ 1.0/5.0, -21.0/20.0, 137.0/60.0, -163.0/60.0, 137.0/60.0 ] + elif iorder == 6: + coef[0] = [ 49.0/20.0, -71.0/20.0, 79.0/20.0, -163.0/60.0, 31.0/30.0, -1.0/6.0 ] + coef[1] = [ 1.0/6.0, 29.0/20.0, -21.0/20.0, 37.0/60.0, -13.0/60.0, 1.0/30.0 ] + coef[2] = [ -1.0/30.0, 11.0/30.0, 19.0/20.0, -23.0/60.0, 7.0/60.0, -1.0/60.0 ] + coef[3] = [ 1.0/60.0, -2.0/15.0, 37.0/60.0, 37.0/60.0, -2.0/15.0, 1.0/60.0 ] + coef[4] = [ -1.0/60.0, 7.0/60.0, -23.0/60.0, 19.0/20.0, 11.0/30.0, -1.0/30.0 ] + coef[5] = [ 1.0/30.0, -13.0/60.0, 37.0/60.0, -21.0/20.0, 29.0/20.0, 1.0/6.0 ] + coef[6] = [ -1.0/6.0, 31.0/30.0, -163.0/60.0, 79.0/20.0, -71.0/20.0, 49.0/20.0 ] + elif iorder == 7: + coef[0] = [ 363.0/140.0, -617.0/140.0, 853.0/140.0, -2341.0/420.0, 667.0/210.0, -43.0/42.0, 1.0/7.0 ] + coef[1] = [ 1.0/7.0, 223.0/140.0, -197.0/140.0, 153.0/140.0, -241.0/420.0, 37.0/210.0, -1.0/42.0 ] + coef[2] = [ -1.0/42.0, 13.0/42.0, 153.0/140.0, -241.0/420.0, 109.0/420.0, -31.0/420.0, 1.0/105.0 ] + coef[3] = [ 1.0/105.0, -19.0/210.0, 107.0/210.0, 319.0/420.0, -101.0/420.0, 5.0/84.0, -1.0/140.0 ] + coef[4] = [ -1.0/140.0, 5.0/84.0, -101.0/420.0, 319.0/420.0, 107.0/210.0, -19.0/210.0, 1.0/105.0 ] + coef[5] = [ 1.0/105.0, -31.0/420.0, 109.0/420.0, -241.0/420.0, 153.0/140.0, 13.0/42.0, -1.0/42.0 ] + coef[6] = [ -1.0/42.0, 37.0/210.0, -241.0/420.0, 153.0/140.0, -197.0/140.0, 223.0/140.0, 1.0/7.0 ] + coef[7] = [ 1.0/7.0, -43.0/42.0, 667.0/210.0, -2341.0/420.0, 853.0/140.0, -617.0/140.0, 363.0/140.0 ] + +def init_field(eno): + for i in range(eno.ist, eno.ied + 1): + j = i - eno.ist + if 0.5 <= eno.mesh.xcc[j] <= 1.0: + eno.u[i] = 2.0 + else: + eno.u[i] = 1.0 + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def runge_kutta(eno): + rk = eno.solver.rk + if rk == 1: + runge_kutta_1(eno) + elif rk == 2: + runge_kutta_2(eno) + else: + runge_kutta_3(eno) + +def runge_kutta_1(eno): + dt = eno.solver.dt + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = eno.u[j] + dt * eno.res[i] + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def runge_kutta_2(eno): + dt = eno.solver.dt + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = eno.u[j] + dt * eno.res[i] + boundary(eno.u, eno) + + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = 0.5 * eno.un[j] + 0.5 * eno.u[j] + 0.5 * dt * eno.res[i] + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def runge_kutta_3(eno): + dt = eno.solver.dt + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = eno.u[j] + dt * eno.res[i] + boundary(eno.u, eno) + + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = 0.75 * eno.un[j] + 0.25 * eno.u[j] + 0.25 * dt * eno.res[i] + boundary(eno.u, eno) + + residual(eno.u, eno) + c1, c2, c3 = 1.0/3.0, 2.0/3.0, 2.0/3.0 + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = c1 * eno.un[j] + c2 * eno.u[j] + c3 * dt * eno.res[i] + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def get_ordinal_numbers(order): + if order == 1: + return 'st' + elif order == 2: + return 'nd' + elif order == 3: + return 'rd' + else: + return 'th' + +def visualize(eno): + with open('solution.plt', 'w') as f: + for i in range(eno.ist, eno.ied + 1): + j = i - eno.ist + f.write(f"{eno.xcc[j]:20.10e}{eno.u[i]:20.10e}\n") + + # 可视化 + u_numerical = np.copy(eno.u[eno.ist:eno.ied+1]) + print(f'u_numerical.size={u_numerical.size}') + print(f'eno.xcc.size={eno.xcc.size}') + #计算理论解 + u_analytical = analytical_solution(eno.mesh.xcc, eno.T, eno.c, eno.L) + print(f'u_analytical.size={u_analytical.size}') + plt.figure("OneFLOW-CFD Solver", figsize=(10, 6)) + plt.scatter(eno.xcc, u_numerical, facecolor="none", edgecolor="blue", s=20, linewidths=0.5, label=f'Numerical (Rusanov)') + plt.plot(eno.xcc, u_analytical, 'r--', label='Analytical') + plt.xlabel('x') + plt.ylabel('u') + ordinal1 = get_ordinal_numbers(eno.iorder) + ordinal2 = get_ordinal_numbers(eno.rk) + plt.title(f'1D Convection Equation at t = {eno.T:.3f} using {eno.iorder}{ordinal1}-order ENO and {eno.rk}{ordinal2}-order Runge-Kutta methods') + plt.legend() + plt.grid(True, color='gray', linestyle='--', linewidth=0.5, alpha=0.7) + plt.tight_layout() + plt.show() + +class Mesh: + def __init__(self): + self.nx = 40 + self.L = 2.0 + self.x = np.zeros(self.nx + 1) + self.xcc = np.zeros(self.nx) + self.init_mesh() + def init_mesh(self): + xstart = 0.0 + xend = self.L + self.dx = (xend - xstart) / self.nx + + for i in range(0, self.nx+1): + self.x[i] = xstart + i * self.dx + + for i in range(0, self.nx): + self.xcc[i] = 0.5 * (self.x[i] + self.x[i + 1]) + +class Solver: + def __init__(self): + self.iflux = 0 + self.rk = 1 + self.c = 1.0 + self.T = 0.625 + self.dt = .0025 + +class Eno: + def __init__(self, solver, mesh, iorder): + self.solver = solver + self.mesh = mesh + self.nx = mesh.nx + self.iorder = iorder + self.ighost = iorder + self.ishift = self.ighost + 1 + self.ist = 0 + self.ishift + self.ied = self.nx - 1 + self.ishift + self.ntcell = self.nx + 2 * self.ishift + self.isize = iorder * (iorder + 1) + + self.il = np.zeros(self.nx + 1, dtype=int) + self.ir = np.zeros(self.nx + 1, dtype=int) + self.coef = np.zeros((iorder + 1, iorder)) + self.dd = np.zeros((iorder, self.ntcell)) + self.up1_2m = np.zeros(self.nx + 1) + self.up1_2p = np.zeros(self.nx + 1) + self.flux = np.zeros(self.nx + 1) + self.res = np.zeros(self.nx) + + # Field module variables + self.u = np.zeros(self.ntcell) + self.un = np.zeros(self.ntcell) + + #self.dt = .0025 + +def plot_eno_OrderAnalysis(solver, xcc, u_list, u_analytical): + # 定义一个包含不同颜色、线形和标记的列表 + styles = [ + {'color': 'black', 'linestyle': '-', 'marker': 'o'}, + {'color': 'blue', 'linestyle': '--', 'marker': 's'}, + {'color': 'black', 'linestyle': '-', 'marker': '^'}, + {'color': 'blue', 'linestyle': '--', 'marker': 'v'}, + {'color': 'black', 'linestyle': '-', 'marker': '<'}, + {'color': 'blue', 'linestyle': '--', 'marker': '>'}, + {'color': 'black', 'linestyle': '-', 'marker': 'D'}, + ] + + n = len(u_list) + num_styles = len(styles) + ordinal = get_ordinal_numbers(solver.rk) + + plt.figure("OneFLOW-CFD Solver", figsize=(10, 6)) + plt.title(f'1D Convection Equation at t = {solver.T:.3f} using [1-7]th-order ENO and {solver.rk}{ordinal}-order Runge-Kutta methods') + for i in range(0, n): + lable = 'Numerical (Rusanov)ENO' + str(i+1) + style = styles[i % num_styles] + plt.plot(xcc, u_list[i], marker=style['marker'], markerfacecolor='none', linestyle=style['linestyle'], color=style['color'], \ + markersize=5, linewidth=0.5, alpha=1.0, label=f'{lable}') + plt.plot(xcc, u_analytical, 'r--', label='Analytical') + plt.xlabel('x') + plt.ylabel('u') + plt.legend() + plt.grid(True, color='gray', linestyle='--', linewidth=0.5, alpha=0.7) + plt.tight_layout() + plt.show() + +def plot_eno_TimestepAnalysis(solver, xcc, u_list, u_analytical, dt_list, iorder): + # 定义一个包含不同颜色、线形和标记的列表 + styles = [ + {'color': 'black', 'linestyle': '-', 'marker': 'o'}, + {'color': 'blue', 'linestyle': '--', 'marker': 's'}, + {'color': 'black', 'linestyle': '-', 'marker': '^'}, + {'color': 'blue', 'linestyle': '--', 'marker': 'v'}, + {'color': 'black', 'linestyle': '-', 'marker': '<'}, + {'color': 'blue', 'linestyle': '--', 'marker': '>'}, + {'color': 'black', 'linestyle': '-', 'marker': 'D'}, + {'color': 'blue', 'linestyle': '--', 'marker': 'o'}, + {'color': 'black', 'linestyle': '-', 'marker': 's'}, + {'color': 'blue', 'linestyle': '--', 'marker': '^'}, + {'color': 'black', 'linestyle': '-', 'marker': 'v'}, + {'color': 'blue', 'linestyle': '--', 'marker': '<'}, + {'color': 'black', 'linestyle': '-', 'marker': '>'}, + {'color': 'blue', 'linestyle': '--', 'marker': 'D'}, + ] + + n = len(u_list) + num_styles = len(styles) + + ordinalENO = get_ordinal_numbers(iorder) + ordinalRK = get_ordinal_numbers(solver.rk) + + plt.figure("OneFLOW-CFD Solver", figsize=(10, 6)) + plt.title(f'1D Convection Equation at t = {solver.T:.3f} using {iorder}{ordinalENO}-order ENO and {solver.rk}{ordinalRK}-order Runge-Kutta methods') + for i in range(0, n): + lable = 'Numerical (Rusanov)ENO' + str(iorder) + ' T='+str(dt_list[i]) + style = styles[i % num_styles] + plt.plot(xcc, u_list[i], marker=style['marker'], markerfacecolor='none', linestyle=style['linestyle'], color=style['color'], \ + markersize=5, linewidth=1.0, alpha=1.0, label=f'{lable}') + plt.plot(xcc, u_analytical, 'r--', label='Analytical') + plt.xlabel('x') + plt.ylabel('u') + plt.legend() + plt.grid(True, color='gray', linestyle='--', linewidth=0.5, alpha=0.7) + plt.tight_layout() + plt.show() + +def RunEno(solver, mesh, iorder): + eno = Eno(solver, mesh, iorder) + init_coef(eno.iorder, eno.coef) + init_field(eno) + + simu_time = solver.T + t = 0.0 + dt = solver.dt + while t < simu_time: + runge_kutta(eno) + if t + dt > simu_time: + dt = simu_time - t + t += dt + #print(f'T={t:.3f},runge_kutta{solver.rk},ENO{eno.iorder},{fluxnames[solver.iflux]} FLUX') + #visualize(eno) + return np.copy(eno.u[eno.ist:eno.ied+1]) + +def performEnoOrderAnalysis(): + iorder_max = 7 + mesh = Mesh() + solver = Solver() + #计算理论解 + u_analytical = analytical_solution(mesh.xcc, solver.T, solver.c, mesh.L) + + u_list = [] + for iorder in range(1, iorder_max+1): + u = RunEno(solver, mesh, iorder) + u_list.append(u) + + plot_eno_OrderAnalysis(solver, mesh.xcc, u_list, u_analytical) + +def performEnoTimestepAnalysis(): + mesh = Mesh() + solver = Solver() + #计算理论解 + u_analytical = analytical_solution(mesh.xcc, solver.T, solver.c, mesh.L) + + u_list = [] + dt_list = [] + solver.dt = 0.025/4 + #solver.dt = 0.025/16 + n = 12 + solver.rk = 2 + iorder = 5 + for i in range(0, n): + u = RunEno(solver, mesh, iorder) + u_list.append(u) + dt_list.append(solver.dt) + print(f'i={i+1},N={n},T={solver.T:.3f},dt={solver.dt},nt={int(solver.T/solver.dt)},runge_kutta{solver.rk},ENO{iorder},{fluxnames[solver.iflux]} FLUX') + solver.dt /= 2 + + plot_eno_TimestepAnalysis(solver, mesh.xcc, u_list, u_analytical, dt_list, iorder) + +def main(): + #performEnoOrderAnalysis() + performEnoTimestepAnalysis() + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/example/1d-linear-convection/eno/rusanov/timestep/rk2-eno/eno5/01/plot.py b/example/1d-linear-convection/eno/rusanov/timestep/rk2-eno/eno5/01/plot.py new file mode 100644 index 00000000..e389044c --- /dev/null +++ b/example/1d-linear-convection/eno/rusanov/timestep/rk2-eno/eno5/01/plot.py @@ -0,0 +1,53 @@ +import numpy as np +import matplotlib.pyplot as plt +import csv +import sys + +nvar = len(sys.argv) +print('nvar=',nvar) +print('sys.argv=',sys.argv) + +order = 1 +if nvar >= 2: + var = sys.argv[1] + print('var=',var) + order = int(var) + +print('order=',order) + +x_list = [] +u_list = [] + +with open('solution.plt', newline='') as csvfile: + #readCSV = csv.reader(csvfile, delimiter= ' ') + icount = 0 + for line in csvfile: + # 去除首尾空格,按连续空格分割 + row = line.strip().split() + #print("row=",row) + x_list.append(row[0]) + u_list.append(row[1]) + icount += 1 + +ni = icount +print("ni=",ni) + +#print("x_list=",x_list) + +x = np.zeros( ni ) +u = np.zeros( ni ) + +for i in range(0, ni): + x[i] = float(x_list[i]) + u[i] = float(u_list[i]) + +labelname = 'Eno' + str(order) + +plt.figure("OneFLOW-CFD Solver", figsize=(8, 6), dpi=100) +plt.plot(x, u, "b-", linewidth=1.0, marker = 's', markerfacecolor='None', label=labelname) +plt.xlabel("$x$") +plt.ylabel("$u$") +plt.title("burgers T=1") +plt.legend() +plt.tight_layout() +plt.show(); \ No newline at end of file diff --git a/example/1d-linear-convection/eno/rusanov/timestep/rk2-eno/eno6/01/eno.py b/example/1d-linear-convection/eno/rusanov/timestep/rk2-eno/eno6/01/eno.py new file mode 100644 index 00000000..a01fbf35 --- /dev/null +++ b/example/1d-linear-convection/eno/rusanov/timestep/rk2-eno/eno6/01/eno.py @@ -0,0 +1,426 @@ +import numpy as np +import matplotlib.pyplot as plt + +# 初始条件 +def initial_condition(x): + u0 = np.zeros_like(x) + for i in range(len(x)): + if 0.5 <= x[i] <= 1.0: + u0[i] = 2.0 + else: + u0[i] = 1.0 + return u0 + +# 理论解 +def analytical_solution(x, t, a, L): + # 初始条件沿 x - at 平移 + x_shifted = x - a * t + return initial_condition((x_shifted + L) % L) # 周期边界条件 + +def residual(q, eno): + reconstruction(q, eno) + inviscid_flux(eno.up1_2m, eno.up1_2p, eno.flux, eno) + for i in range(eno.nx): + eno.res[i] = -(eno.flux[i + 1] - eno.flux[i]) / eno.mesh.dx + +def reconstruction(q, eno): + # Choose the stencil by ENO method + eno.dd[0, 0:eno.ntcell-1] = q[0:eno.ntcell-1] + + for m in range(1, eno.iorder): + for j in range(0, eno.ntcell-1): + eno.dd[m, j] = eno.dd[m-1, j+1] - eno.dd[m-1, j] + + for i in range(eno.nx + 1): + eno.il[i] = i - 1 + for m in range(1, eno.iorder): + if abs(eno.dd[m, eno.il[i]-1+eno.ishift]) <= abs(eno.dd[m, eno.il[i]+eno.ishift]): + eno.il[i] -= 1 + + for i in range(eno.nx + 1): + eno.ir[i] = i + for m in range(1, eno.iorder): + if abs(eno.dd[m, eno.ir[i]-1+eno.ishift]) <= abs(eno.dd[m, eno.ir[i]+eno.ishift]): + eno.ir[i] -= 1 + + # Reconstruction u(j+1/2) + for i in range(eno.nx + 1): + k1 = eno.il[i] + k2 = eno.ir[i] + l1 = i - k1 + l2 = i - k2 + eno.up1_2m[i] = 0 + eno.up1_2p[i] = 0 + for m in range(eno.iorder): + eno.up1_2m[i] += q[k1 + eno.ishift + m] * eno.coef[l1, m] + eno.up1_2p[i] += q[k2 + eno.ishift + m] * eno.coef[l2, m] + +fluxnames = [ + 'Rusanov', + 'Engquist-Osher', +] + +def inviscid_flux(up1_2m, up1_2p, flux, eno): + if eno.solver.iflux == 0: + rusanov_flux(up1_2m, up1_2p, flux, eno) + else: + engquist_osher_flux(up1_2m, up1_2p, flux, eno) + +def engquist_osher_flux(up1_2m, up1_2p, flux, eno): + for i in range(eno.nx + 1): + u_L = up1_2m[i] + u_R = up1_2p[i] + + cp = 0.5 * ( eno.solver.c + abs(eno.solver.c) ) + cm = 0.5 * ( eno.solver.c - abs(eno.solver.c) ) + + flux[i] = cp * u_L + cm * u_R + +def rusanov_flux(up1_2m, up1_2p, flux, eno): + for i in range(eno.nx + 1): + u_L = up1_2m[i] + u_R = up1_2p[i] + F_L = eno.solver.c * u_L # 左状态通量 + F_R = eno.solver.c * u_R # 右状态通量 + alpha = abs(eno.solver.c) # 最大波速 + flux[i] = 0.5 * (F_L + F_R) - 0.5 * alpha * (u_R - u_L) + + +def boundary(u, eno): + for i in range(-eno.ighost, 1): + u[eno.ist - 1 + i] = u[eno.ied + i] + for i in range(1, eno.ighost + 2): + u[eno.ied + i] = u[eno.ist - 1 + i] + +def update_oldfield(qn, q): + qn[:] = q[:] + +def init_coef( iorder, coef ): + if iorder == 1: + coef[0] = [1.0] + coef[1] = [1.0] + elif iorder == 2: + coef[0] = [3.0/2.0, -1.0/2.0] + coef[1] = [1.0/2.0, 1.0/2.0] + coef[2] = [-1.0/2.0, 3.0/2.0] + elif iorder == 3: + coef[0] = [ 11.0/6.0, -7.0/6.0, 1.0/3.0 ] + coef[1] = [ 1.0/3.0, 5.0/6.0, -1.0/6.0 ] + coef[2] = [ -1.0/6.0, 5.0/6.0, 1.0/3.0 ] + coef[3] = [ 1.0/3.0, -7.0/6.0, 11.0/6.0 ] + elif iorder == 4: + coef[0] = [ 25.0/12.0, -23.0/12.0, 13.0/12.0, -1.0/4.0 ] + coef[1] = [ 1.0/4.0, 13.0/12.0, -5.0/12.0, 1.0/12.0 ] + coef[2] = [ -1.0/12.0, 7.0/12.0, 7.0/12.0, -1.0/12.0 ] + coef[3] = [ 1.0/12.0, -5.0/12.0, 13.0/12.0, 1.0/4.0 ] + coef[4] = [ -1.0/4.0, 13.0/12.0, -23.0/12.0, 25.0/12.0 ] + elif iorder == 5: + coef[0] = [ 137.0/60.0, -163.0/60.0, 137.0/60.0, -21.0/20.0, 1.0/5.0 ] + coef[1] = [ 1.0/5.0, 77.0/60.0, -43.0/60.0, 17.0/60.0, -1.0/20.0 ] + coef[2] = [ -1.0/20.0, 9.0/20.0, 47.0/60.0, -13.0/60.0, 1.0/30.0 ] + coef[3] = [ 1.0/30.0, -13.0/60.0, 47.0/60.0, 9.0/20.0, -1.0/20.0 ] + coef[4] = [ -1.0/20.0, 17.0/60.0, -43.0/60.0, 77.0/60.0, 1.0/5.0 ] + coef[5] = [ 1.0/5.0, -21.0/20.0, 137.0/60.0, -163.0/60.0, 137.0/60.0 ] + elif iorder == 6: + coef[0] = [ 49.0/20.0, -71.0/20.0, 79.0/20.0, -163.0/60.0, 31.0/30.0, -1.0/6.0 ] + coef[1] = [ 1.0/6.0, 29.0/20.0, -21.0/20.0, 37.0/60.0, -13.0/60.0, 1.0/30.0 ] + coef[2] = [ -1.0/30.0, 11.0/30.0, 19.0/20.0, -23.0/60.0, 7.0/60.0, -1.0/60.0 ] + coef[3] = [ 1.0/60.0, -2.0/15.0, 37.0/60.0, 37.0/60.0, -2.0/15.0, 1.0/60.0 ] + coef[4] = [ -1.0/60.0, 7.0/60.0, -23.0/60.0, 19.0/20.0, 11.0/30.0, -1.0/30.0 ] + coef[5] = [ 1.0/30.0, -13.0/60.0, 37.0/60.0, -21.0/20.0, 29.0/20.0, 1.0/6.0 ] + coef[6] = [ -1.0/6.0, 31.0/30.0, -163.0/60.0, 79.0/20.0, -71.0/20.0, 49.0/20.0 ] + elif iorder == 7: + coef[0] = [ 363.0/140.0, -617.0/140.0, 853.0/140.0, -2341.0/420.0, 667.0/210.0, -43.0/42.0, 1.0/7.0 ] + coef[1] = [ 1.0/7.0, 223.0/140.0, -197.0/140.0, 153.0/140.0, -241.0/420.0, 37.0/210.0, -1.0/42.0 ] + coef[2] = [ -1.0/42.0, 13.0/42.0, 153.0/140.0, -241.0/420.0, 109.0/420.0, -31.0/420.0, 1.0/105.0 ] + coef[3] = [ 1.0/105.0, -19.0/210.0, 107.0/210.0, 319.0/420.0, -101.0/420.0, 5.0/84.0, -1.0/140.0 ] + coef[4] = [ -1.0/140.0, 5.0/84.0, -101.0/420.0, 319.0/420.0, 107.0/210.0, -19.0/210.0, 1.0/105.0 ] + coef[5] = [ 1.0/105.0, -31.0/420.0, 109.0/420.0, -241.0/420.0, 153.0/140.0, 13.0/42.0, -1.0/42.0 ] + coef[6] = [ -1.0/42.0, 37.0/210.0, -241.0/420.0, 153.0/140.0, -197.0/140.0, 223.0/140.0, 1.0/7.0 ] + coef[7] = [ 1.0/7.0, -43.0/42.0, 667.0/210.0, -2341.0/420.0, 853.0/140.0, -617.0/140.0, 363.0/140.0 ] + +def init_field(eno): + for i in range(eno.ist, eno.ied + 1): + j = i - eno.ist + if 0.5 <= eno.mesh.xcc[j] <= 1.0: + eno.u[i] = 2.0 + else: + eno.u[i] = 1.0 + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def runge_kutta(eno): + rk = eno.solver.rk + if rk == 1: + runge_kutta_1(eno) + elif rk == 2: + runge_kutta_2(eno) + else: + runge_kutta_3(eno) + +def runge_kutta_1(eno): + dt = eno.solver.dt + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = eno.u[j] + dt * eno.res[i] + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def runge_kutta_2(eno): + dt = eno.solver.dt + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = eno.u[j] + dt * eno.res[i] + boundary(eno.u, eno) + + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = 0.5 * eno.un[j] + 0.5 * eno.u[j] + 0.5 * dt * eno.res[i] + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def runge_kutta_3(eno): + dt = eno.solver.dt + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = eno.u[j] + dt * eno.res[i] + boundary(eno.u, eno) + + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = 0.75 * eno.un[j] + 0.25 * eno.u[j] + 0.25 * dt * eno.res[i] + boundary(eno.u, eno) + + residual(eno.u, eno) + c1, c2, c3 = 1.0/3.0, 2.0/3.0, 2.0/3.0 + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = c1 * eno.un[j] + c2 * eno.u[j] + c3 * dt * eno.res[i] + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def get_ordinal_numbers(order): + if order == 1: + return 'st' + elif order == 2: + return 'nd' + elif order == 3: + return 'rd' + else: + return 'th' + +def visualize(eno): + with open('solution.plt', 'w') as f: + for i in range(eno.ist, eno.ied + 1): + j = i - eno.ist + f.write(f"{eno.xcc[j]:20.10e}{eno.u[i]:20.10e}\n") + + # 可视化 + u_numerical = np.copy(eno.u[eno.ist:eno.ied+1]) + print(f'u_numerical.size={u_numerical.size}') + print(f'eno.xcc.size={eno.xcc.size}') + #计算理论解 + u_analytical = analytical_solution(eno.mesh.xcc, eno.T, eno.c, eno.L) + print(f'u_analytical.size={u_analytical.size}') + plt.figure("OneFLOW-CFD Solver", figsize=(10, 6)) + plt.scatter(eno.xcc, u_numerical, facecolor="none", edgecolor="blue", s=20, linewidths=0.5, label=f'Numerical (Rusanov)') + plt.plot(eno.xcc, u_analytical, 'r--', label='Analytical') + plt.xlabel('x') + plt.ylabel('u') + ordinal1 = get_ordinal_numbers(eno.iorder) + ordinal2 = get_ordinal_numbers(eno.rk) + plt.title(f'1D Convection Equation at t = {eno.T:.3f} using {eno.iorder}{ordinal1}-order ENO and {eno.rk}{ordinal2}-order Runge-Kutta methods') + plt.legend() + plt.grid(True, color='gray', linestyle='--', linewidth=0.5, alpha=0.7) + plt.tight_layout() + plt.show() + +class Mesh: + def __init__(self): + self.nx = 40 + self.L = 2.0 + self.x = np.zeros(self.nx + 1) + self.xcc = np.zeros(self.nx) + self.init_mesh() + def init_mesh(self): + xstart = 0.0 + xend = self.L + self.dx = (xend - xstart) / self.nx + + for i in range(0, self.nx+1): + self.x[i] = xstart + i * self.dx + + for i in range(0, self.nx): + self.xcc[i] = 0.5 * (self.x[i] + self.x[i + 1]) + +class Solver: + def __init__(self): + self.iflux = 0 + self.rk = 1 + self.c = 1.0 + self.T = 0.625 + self.dt = .0025 + +class Eno: + def __init__(self, solver, mesh, iorder): + self.solver = solver + self.mesh = mesh + self.nx = mesh.nx + self.iorder = iorder + self.ighost = iorder + self.ishift = self.ighost + 1 + self.ist = 0 + self.ishift + self.ied = self.nx - 1 + self.ishift + self.ntcell = self.nx + 2 * self.ishift + self.isize = iorder * (iorder + 1) + + self.il = np.zeros(self.nx + 1, dtype=int) + self.ir = np.zeros(self.nx + 1, dtype=int) + self.coef = np.zeros((iorder + 1, iorder)) + self.dd = np.zeros((iorder, self.ntcell)) + self.up1_2m = np.zeros(self.nx + 1) + self.up1_2p = np.zeros(self.nx + 1) + self.flux = np.zeros(self.nx + 1) + self.res = np.zeros(self.nx) + + # Field module variables + self.u = np.zeros(self.ntcell) + self.un = np.zeros(self.ntcell) + + #self.dt = .0025 + +def plot_eno_OrderAnalysis(solver, xcc, u_list, u_analytical): + # 定义一个包含不同颜色、线形和标记的列表 + styles = [ + {'color': 'black', 'linestyle': '-', 'marker': 'o'}, + {'color': 'blue', 'linestyle': '--', 'marker': 's'}, + {'color': 'black', 'linestyle': '-', 'marker': '^'}, + {'color': 'blue', 'linestyle': '--', 'marker': 'v'}, + {'color': 'black', 'linestyle': '-', 'marker': '<'}, + {'color': 'blue', 'linestyle': '--', 'marker': '>'}, + {'color': 'black', 'linestyle': '-', 'marker': 'D'}, + ] + + n = len(u_list) + num_styles = len(styles) + ordinal = get_ordinal_numbers(solver.rk) + + plt.figure("OneFLOW-CFD Solver", figsize=(10, 6)) + plt.title(f'1D Convection Equation at t = {solver.T:.3f} using [1-7]th-order ENO and {solver.rk}{ordinal}-order Runge-Kutta methods') + for i in range(0, n): + lable = 'Numerical (Rusanov)ENO' + str(i+1) + style = styles[i % num_styles] + plt.plot(xcc, u_list[i], marker=style['marker'], markerfacecolor='none', linestyle=style['linestyle'], color=style['color'], \ + markersize=5, linewidth=0.5, alpha=1.0, label=f'{lable}') + plt.plot(xcc, u_analytical, 'r--', label='Analytical') + plt.xlabel('x') + plt.ylabel('u') + plt.legend() + plt.grid(True, color='gray', linestyle='--', linewidth=0.5, alpha=0.7) + plt.tight_layout() + plt.show() + +def plot_eno_TimestepAnalysis(solver, xcc, u_list, u_analytical, dt_list, iorder): + # 定义一个包含不同颜色、线形和标记的列表 + styles = [ + {'color': 'black', 'linestyle': '-', 'marker': 'o'}, + {'color': 'blue', 'linestyle': '--', 'marker': 's'}, + {'color': 'black', 'linestyle': '-', 'marker': '^'}, + {'color': 'blue', 'linestyle': '--', 'marker': 'v'}, + {'color': 'black', 'linestyle': '-', 'marker': '<'}, + {'color': 'blue', 'linestyle': '--', 'marker': '>'}, + {'color': 'black', 'linestyle': '-', 'marker': 'D'}, + {'color': 'blue', 'linestyle': '--', 'marker': 'o'}, + {'color': 'black', 'linestyle': '-', 'marker': 's'}, + {'color': 'blue', 'linestyle': '--', 'marker': '^'}, + {'color': 'black', 'linestyle': '-', 'marker': 'v'}, + {'color': 'blue', 'linestyle': '--', 'marker': '<'}, + {'color': 'black', 'linestyle': '-', 'marker': '>'}, + {'color': 'blue', 'linestyle': '--', 'marker': 'D'}, + ] + + n = len(u_list) + num_styles = len(styles) + + ordinalENO = get_ordinal_numbers(iorder) + ordinalRK = get_ordinal_numbers(solver.rk) + + plt.figure("OneFLOW-CFD Solver", figsize=(10, 6)) + plt.title(f'1D Convection Equation at t = {solver.T:.3f} using {iorder}{ordinalENO}-order ENO and {solver.rk}{ordinalRK}-order Runge-Kutta methods') + for i in range(0, n): + lable = 'Numerical (Rusanov)ENO' + str(iorder) + ' T='+str(dt_list[i]) + style = styles[i % num_styles] + plt.plot(xcc, u_list[i], marker=style['marker'], markerfacecolor='none', linestyle=style['linestyle'], color=style['color'], \ + markersize=5, linewidth=1.0, alpha=1.0, label=f'{lable}') + plt.plot(xcc, u_analytical, 'r--', label='Analytical') + plt.xlabel('x') + plt.ylabel('u') + plt.legend() + plt.grid(True, color='gray', linestyle='--', linewidth=0.5, alpha=0.7) + plt.tight_layout() + plt.show() + +def RunEno(solver, mesh, iorder): + eno = Eno(solver, mesh, iorder) + init_coef(eno.iorder, eno.coef) + init_field(eno) + + simu_time = solver.T + t = 0.0 + dt = solver.dt + while t < simu_time: + runge_kutta(eno) + if t + dt > simu_time: + dt = simu_time - t + t += dt + #print(f'T={t:.3f},runge_kutta{solver.rk},ENO{eno.iorder},{fluxnames[solver.iflux]} FLUX') + #visualize(eno) + return np.copy(eno.u[eno.ist:eno.ied+1]) + +def performEnoOrderAnalysis(): + iorder_max = 7 + mesh = Mesh() + solver = Solver() + #计算理论解 + u_analytical = analytical_solution(mesh.xcc, solver.T, solver.c, mesh.L) + + u_list = [] + for iorder in range(1, iorder_max+1): + u = RunEno(solver, mesh, iorder) + u_list.append(u) + + plot_eno_OrderAnalysis(solver, mesh.xcc, u_list, u_analytical) + +def performEnoTimestepAnalysis(): + mesh = Mesh() + solver = Solver() + #计算理论解 + u_analytical = analytical_solution(mesh.xcc, solver.T, solver.c, mesh.L) + + u_list = [] + dt_list = [] + solver.dt = 0.025/4 + #solver.dt = 0.025/16 + n = 12 + solver.rk = 2 + iorder = 6 + for i in range(0, n): + u = RunEno(solver, mesh, iorder) + u_list.append(u) + dt_list.append(solver.dt) + print(f'i={i+1},N={n},T={solver.T:.3f},dt={solver.dt},nt={int(solver.T/solver.dt)},runge_kutta{solver.rk},ENO{iorder},{fluxnames[solver.iflux]} FLUX') + solver.dt /= 2 + + plot_eno_TimestepAnalysis(solver, mesh.xcc, u_list, u_analytical, dt_list, iorder) + +def main(): + #performEnoOrderAnalysis() + performEnoTimestepAnalysis() + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/example/1d-linear-convection/eno/rusanov/timestep/rk2-eno/eno6/01/plot.py b/example/1d-linear-convection/eno/rusanov/timestep/rk2-eno/eno6/01/plot.py new file mode 100644 index 00000000..e389044c --- /dev/null +++ b/example/1d-linear-convection/eno/rusanov/timestep/rk2-eno/eno6/01/plot.py @@ -0,0 +1,53 @@ +import numpy as np +import matplotlib.pyplot as plt +import csv +import sys + +nvar = len(sys.argv) +print('nvar=',nvar) +print('sys.argv=',sys.argv) + +order = 1 +if nvar >= 2: + var = sys.argv[1] + print('var=',var) + order = int(var) + +print('order=',order) + +x_list = [] +u_list = [] + +with open('solution.plt', newline='') as csvfile: + #readCSV = csv.reader(csvfile, delimiter= ' ') + icount = 0 + for line in csvfile: + # 去除首尾空格,按连续空格分割 + row = line.strip().split() + #print("row=",row) + x_list.append(row[0]) + u_list.append(row[1]) + icount += 1 + +ni = icount +print("ni=",ni) + +#print("x_list=",x_list) + +x = np.zeros( ni ) +u = np.zeros( ni ) + +for i in range(0, ni): + x[i] = float(x_list[i]) + u[i] = float(u_list[i]) + +labelname = 'Eno' + str(order) + +plt.figure("OneFLOW-CFD Solver", figsize=(8, 6), dpi=100) +plt.plot(x, u, "b-", linewidth=1.0, marker = 's', markerfacecolor='None', label=labelname) +plt.xlabel("$x$") +plt.ylabel("$u$") +plt.title("burgers T=1") +plt.legend() +plt.tight_layout() +plt.show(); \ No newline at end of file diff --git a/example/1d-linear-convection/eno/rusanov/timestep/rk2-eno/eno7/01/eno.py b/example/1d-linear-convection/eno/rusanov/timestep/rk2-eno/eno7/01/eno.py new file mode 100644 index 00000000..a065fb78 --- /dev/null +++ b/example/1d-linear-convection/eno/rusanov/timestep/rk2-eno/eno7/01/eno.py @@ -0,0 +1,426 @@ +import numpy as np +import matplotlib.pyplot as plt + +# 初始条件 +def initial_condition(x): + u0 = np.zeros_like(x) + for i in range(len(x)): + if 0.5 <= x[i] <= 1.0: + u0[i] = 2.0 + else: + u0[i] = 1.0 + return u0 + +# 理论解 +def analytical_solution(x, t, a, L): + # 初始条件沿 x - at 平移 + x_shifted = x - a * t + return initial_condition((x_shifted + L) % L) # 周期边界条件 + +def residual(q, eno): + reconstruction(q, eno) + inviscid_flux(eno.up1_2m, eno.up1_2p, eno.flux, eno) + for i in range(eno.nx): + eno.res[i] = -(eno.flux[i + 1] - eno.flux[i]) / eno.mesh.dx + +def reconstruction(q, eno): + # Choose the stencil by ENO method + eno.dd[0, 0:eno.ntcell-1] = q[0:eno.ntcell-1] + + for m in range(1, eno.iorder): + for j in range(0, eno.ntcell-1): + eno.dd[m, j] = eno.dd[m-1, j+1] - eno.dd[m-1, j] + + for i in range(eno.nx + 1): + eno.il[i] = i - 1 + for m in range(1, eno.iorder): + if abs(eno.dd[m, eno.il[i]-1+eno.ishift]) <= abs(eno.dd[m, eno.il[i]+eno.ishift]): + eno.il[i] -= 1 + + for i in range(eno.nx + 1): + eno.ir[i] = i + for m in range(1, eno.iorder): + if abs(eno.dd[m, eno.ir[i]-1+eno.ishift]) <= abs(eno.dd[m, eno.ir[i]+eno.ishift]): + eno.ir[i] -= 1 + + # Reconstruction u(j+1/2) + for i in range(eno.nx + 1): + k1 = eno.il[i] + k2 = eno.ir[i] + l1 = i - k1 + l2 = i - k2 + eno.up1_2m[i] = 0 + eno.up1_2p[i] = 0 + for m in range(eno.iorder): + eno.up1_2m[i] += q[k1 + eno.ishift + m] * eno.coef[l1, m] + eno.up1_2p[i] += q[k2 + eno.ishift + m] * eno.coef[l2, m] + +fluxnames = [ + 'Rusanov', + 'Engquist-Osher', +] + +def inviscid_flux(up1_2m, up1_2p, flux, eno): + if eno.solver.iflux == 0: + rusanov_flux(up1_2m, up1_2p, flux, eno) + else: + engquist_osher_flux(up1_2m, up1_2p, flux, eno) + +def engquist_osher_flux(up1_2m, up1_2p, flux, eno): + for i in range(eno.nx + 1): + u_L = up1_2m[i] + u_R = up1_2p[i] + + cp = 0.5 * ( eno.solver.c + abs(eno.solver.c) ) + cm = 0.5 * ( eno.solver.c - abs(eno.solver.c) ) + + flux[i] = cp * u_L + cm * u_R + +def rusanov_flux(up1_2m, up1_2p, flux, eno): + for i in range(eno.nx + 1): + u_L = up1_2m[i] + u_R = up1_2p[i] + F_L = eno.solver.c * u_L # 左状态通量 + F_R = eno.solver.c * u_R # 右状态通量 + alpha = abs(eno.solver.c) # 最大波速 + flux[i] = 0.5 * (F_L + F_R) - 0.5 * alpha * (u_R - u_L) + + +def boundary(u, eno): + for i in range(-eno.ighost, 1): + u[eno.ist - 1 + i] = u[eno.ied + i] + for i in range(1, eno.ighost + 2): + u[eno.ied + i] = u[eno.ist - 1 + i] + +def update_oldfield(qn, q): + qn[:] = q[:] + +def init_coef( iorder, coef ): + if iorder == 1: + coef[0] = [1.0] + coef[1] = [1.0] + elif iorder == 2: + coef[0] = [3.0/2.0, -1.0/2.0] + coef[1] = [1.0/2.0, 1.0/2.0] + coef[2] = [-1.0/2.0, 3.0/2.0] + elif iorder == 3: + coef[0] = [ 11.0/6.0, -7.0/6.0, 1.0/3.0 ] + coef[1] = [ 1.0/3.0, 5.0/6.0, -1.0/6.0 ] + coef[2] = [ -1.0/6.0, 5.0/6.0, 1.0/3.0 ] + coef[3] = [ 1.0/3.0, -7.0/6.0, 11.0/6.0 ] + elif iorder == 4: + coef[0] = [ 25.0/12.0, -23.0/12.0, 13.0/12.0, -1.0/4.0 ] + coef[1] = [ 1.0/4.0, 13.0/12.0, -5.0/12.0, 1.0/12.0 ] + coef[2] = [ -1.0/12.0, 7.0/12.0, 7.0/12.0, -1.0/12.0 ] + coef[3] = [ 1.0/12.0, -5.0/12.0, 13.0/12.0, 1.0/4.0 ] + coef[4] = [ -1.0/4.0, 13.0/12.0, -23.0/12.0, 25.0/12.0 ] + elif iorder == 5: + coef[0] = [ 137.0/60.0, -163.0/60.0, 137.0/60.0, -21.0/20.0, 1.0/5.0 ] + coef[1] = [ 1.0/5.0, 77.0/60.0, -43.0/60.0, 17.0/60.0, -1.0/20.0 ] + coef[2] = [ -1.0/20.0, 9.0/20.0, 47.0/60.0, -13.0/60.0, 1.0/30.0 ] + coef[3] = [ 1.0/30.0, -13.0/60.0, 47.0/60.0, 9.0/20.0, -1.0/20.0 ] + coef[4] = [ -1.0/20.0, 17.0/60.0, -43.0/60.0, 77.0/60.0, 1.0/5.0 ] + coef[5] = [ 1.0/5.0, -21.0/20.0, 137.0/60.0, -163.0/60.0, 137.0/60.0 ] + elif iorder == 6: + coef[0] = [ 49.0/20.0, -71.0/20.0, 79.0/20.0, -163.0/60.0, 31.0/30.0, -1.0/6.0 ] + coef[1] = [ 1.0/6.0, 29.0/20.0, -21.0/20.0, 37.0/60.0, -13.0/60.0, 1.0/30.0 ] + coef[2] = [ -1.0/30.0, 11.0/30.0, 19.0/20.0, -23.0/60.0, 7.0/60.0, -1.0/60.0 ] + coef[3] = [ 1.0/60.0, -2.0/15.0, 37.0/60.0, 37.0/60.0, -2.0/15.0, 1.0/60.0 ] + coef[4] = [ -1.0/60.0, 7.0/60.0, -23.0/60.0, 19.0/20.0, 11.0/30.0, -1.0/30.0 ] + coef[5] = [ 1.0/30.0, -13.0/60.0, 37.0/60.0, -21.0/20.0, 29.0/20.0, 1.0/6.0 ] + coef[6] = [ -1.0/6.0, 31.0/30.0, -163.0/60.0, 79.0/20.0, -71.0/20.0, 49.0/20.0 ] + elif iorder == 7: + coef[0] = [ 363.0/140.0, -617.0/140.0, 853.0/140.0, -2341.0/420.0, 667.0/210.0, -43.0/42.0, 1.0/7.0 ] + coef[1] = [ 1.0/7.0, 223.0/140.0, -197.0/140.0, 153.0/140.0, -241.0/420.0, 37.0/210.0, -1.0/42.0 ] + coef[2] = [ -1.0/42.0, 13.0/42.0, 153.0/140.0, -241.0/420.0, 109.0/420.0, -31.0/420.0, 1.0/105.0 ] + coef[3] = [ 1.0/105.0, -19.0/210.0, 107.0/210.0, 319.0/420.0, -101.0/420.0, 5.0/84.0, -1.0/140.0 ] + coef[4] = [ -1.0/140.0, 5.0/84.0, -101.0/420.0, 319.0/420.0, 107.0/210.0, -19.0/210.0, 1.0/105.0 ] + coef[5] = [ 1.0/105.0, -31.0/420.0, 109.0/420.0, -241.0/420.0, 153.0/140.0, 13.0/42.0, -1.0/42.0 ] + coef[6] = [ -1.0/42.0, 37.0/210.0, -241.0/420.0, 153.0/140.0, -197.0/140.0, 223.0/140.0, 1.0/7.0 ] + coef[7] = [ 1.0/7.0, -43.0/42.0, 667.0/210.0, -2341.0/420.0, 853.0/140.0, -617.0/140.0, 363.0/140.0 ] + +def init_field(eno): + for i in range(eno.ist, eno.ied + 1): + j = i - eno.ist + if 0.5 <= eno.mesh.xcc[j] <= 1.0: + eno.u[i] = 2.0 + else: + eno.u[i] = 1.0 + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def runge_kutta(eno): + rk = eno.solver.rk + if rk == 1: + runge_kutta_1(eno) + elif rk == 2: + runge_kutta_2(eno) + else: + runge_kutta_3(eno) + +def runge_kutta_1(eno): + dt = eno.solver.dt + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = eno.u[j] + dt * eno.res[i] + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def runge_kutta_2(eno): + dt = eno.solver.dt + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = eno.u[j] + dt * eno.res[i] + boundary(eno.u, eno) + + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = 0.5 * eno.un[j] + 0.5 * eno.u[j] + 0.5 * dt * eno.res[i] + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def runge_kutta_3(eno): + dt = eno.solver.dt + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = eno.u[j] + dt * eno.res[i] + boundary(eno.u, eno) + + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = 0.75 * eno.un[j] + 0.25 * eno.u[j] + 0.25 * dt * eno.res[i] + boundary(eno.u, eno) + + residual(eno.u, eno) + c1, c2, c3 = 1.0/3.0, 2.0/3.0, 2.0/3.0 + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = c1 * eno.un[j] + c2 * eno.u[j] + c3 * dt * eno.res[i] + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def get_ordinal_numbers(order): + if order == 1: + return 'st' + elif order == 2: + return 'nd' + elif order == 3: + return 'rd' + else: + return 'th' + +def visualize(eno): + with open('solution.plt', 'w') as f: + for i in range(eno.ist, eno.ied + 1): + j = i - eno.ist + f.write(f"{eno.xcc[j]:20.10e}{eno.u[i]:20.10e}\n") + + # 可视化 + u_numerical = np.copy(eno.u[eno.ist:eno.ied+1]) + print(f'u_numerical.size={u_numerical.size}') + print(f'eno.xcc.size={eno.xcc.size}') + #计算理论解 + u_analytical = analytical_solution(eno.mesh.xcc, eno.T, eno.c, eno.L) + print(f'u_analytical.size={u_analytical.size}') + plt.figure("OneFLOW-CFD Solver", figsize=(10, 6)) + plt.scatter(eno.xcc, u_numerical, facecolor="none", edgecolor="blue", s=20, linewidths=0.5, label=f'Numerical (Rusanov)') + plt.plot(eno.xcc, u_analytical, 'r--', label='Analytical') + plt.xlabel('x') + plt.ylabel('u') + ordinal1 = get_ordinal_numbers(eno.iorder) + ordinal2 = get_ordinal_numbers(eno.rk) + plt.title(f'1D Convection Equation at t = {eno.T:.3f} using {eno.iorder}{ordinal1}-order ENO and {eno.rk}{ordinal2}-order Runge-Kutta methods') + plt.legend() + plt.grid(True, color='gray', linestyle='--', linewidth=0.5, alpha=0.7) + plt.tight_layout() + plt.show() + +class Mesh: + def __init__(self): + self.nx = 40 + self.L = 2.0 + self.x = np.zeros(self.nx + 1) + self.xcc = np.zeros(self.nx) + self.init_mesh() + def init_mesh(self): + xstart = 0.0 + xend = self.L + self.dx = (xend - xstart) / self.nx + + for i in range(0, self.nx+1): + self.x[i] = xstart + i * self.dx + + for i in range(0, self.nx): + self.xcc[i] = 0.5 * (self.x[i] + self.x[i + 1]) + +class Solver: + def __init__(self): + self.iflux = 0 + self.rk = 1 + self.c = 1.0 + self.T = 0.625 + self.dt = .0025 + +class Eno: + def __init__(self, solver, mesh, iorder): + self.solver = solver + self.mesh = mesh + self.nx = mesh.nx + self.iorder = iorder + self.ighost = iorder + self.ishift = self.ighost + 1 + self.ist = 0 + self.ishift + self.ied = self.nx - 1 + self.ishift + self.ntcell = self.nx + 2 * self.ishift + self.isize = iorder * (iorder + 1) + + self.il = np.zeros(self.nx + 1, dtype=int) + self.ir = np.zeros(self.nx + 1, dtype=int) + self.coef = np.zeros((iorder + 1, iorder)) + self.dd = np.zeros((iorder, self.ntcell)) + self.up1_2m = np.zeros(self.nx + 1) + self.up1_2p = np.zeros(self.nx + 1) + self.flux = np.zeros(self.nx + 1) + self.res = np.zeros(self.nx) + + # Field module variables + self.u = np.zeros(self.ntcell) + self.un = np.zeros(self.ntcell) + + #self.dt = .0025 + +def plot_eno_OrderAnalysis(solver, xcc, u_list, u_analytical): + # 定义一个包含不同颜色、线形和标记的列表 + styles = [ + {'color': 'black', 'linestyle': '-', 'marker': 'o'}, + {'color': 'blue', 'linestyle': '--', 'marker': 's'}, + {'color': 'black', 'linestyle': '-', 'marker': '^'}, + {'color': 'blue', 'linestyle': '--', 'marker': 'v'}, + {'color': 'black', 'linestyle': '-', 'marker': '<'}, + {'color': 'blue', 'linestyle': '--', 'marker': '>'}, + {'color': 'black', 'linestyle': '-', 'marker': 'D'}, + ] + + n = len(u_list) + num_styles = len(styles) + ordinal = get_ordinal_numbers(solver.rk) + + plt.figure("OneFLOW-CFD Solver", figsize=(10, 6)) + plt.title(f'1D Convection Equation at t = {solver.T:.3f} using [1-7]th-order ENO and {solver.rk}{ordinal}-order Runge-Kutta methods') + for i in range(0, n): + lable = 'Numerical (Rusanov)ENO' + str(i+1) + style = styles[i % num_styles] + plt.plot(xcc, u_list[i], marker=style['marker'], markerfacecolor='none', linestyle=style['linestyle'], color=style['color'], \ + markersize=5, linewidth=0.5, alpha=1.0, label=f'{lable}') + plt.plot(xcc, u_analytical, 'r--', label='Analytical') + plt.xlabel('x') + plt.ylabel('u') + plt.legend() + plt.grid(True, color='gray', linestyle='--', linewidth=0.5, alpha=0.7) + plt.tight_layout() + plt.show() + +def plot_eno_TimestepAnalysis(solver, xcc, u_list, u_analytical, dt_list, iorder): + # 定义一个包含不同颜色、线形和标记的列表 + styles = [ + {'color': 'black', 'linestyle': '-', 'marker': 'o'}, + {'color': 'blue', 'linestyle': '--', 'marker': 's'}, + {'color': 'black', 'linestyle': '-', 'marker': '^'}, + {'color': 'blue', 'linestyle': '--', 'marker': 'v'}, + {'color': 'black', 'linestyle': '-', 'marker': '<'}, + {'color': 'blue', 'linestyle': '--', 'marker': '>'}, + {'color': 'black', 'linestyle': '-', 'marker': 'D'}, + {'color': 'blue', 'linestyle': '--', 'marker': 'o'}, + {'color': 'black', 'linestyle': '-', 'marker': 's'}, + {'color': 'blue', 'linestyle': '--', 'marker': '^'}, + {'color': 'black', 'linestyle': '-', 'marker': 'v'}, + {'color': 'blue', 'linestyle': '--', 'marker': '<'}, + {'color': 'black', 'linestyle': '-', 'marker': '>'}, + {'color': 'blue', 'linestyle': '--', 'marker': 'D'}, + ] + + n = len(u_list) + num_styles = len(styles) + + ordinalENO = get_ordinal_numbers(iorder) + ordinalRK = get_ordinal_numbers(solver.rk) + + plt.figure("OneFLOW-CFD Solver", figsize=(10, 6)) + plt.title(f'1D Convection Equation at t = {solver.T:.3f} using {iorder}{ordinalENO}-order ENO and {solver.rk}{ordinalRK}-order Runge-Kutta methods') + for i in range(0, n): + lable = 'Numerical (Rusanov)ENO' + str(iorder) + ' T='+str(dt_list[i]) + style = styles[i % num_styles] + plt.plot(xcc, u_list[i], marker=style['marker'], markerfacecolor='none', linestyle=style['linestyle'], color=style['color'], \ + markersize=5, linewidth=1.0, alpha=1.0, label=f'{lable}') + plt.plot(xcc, u_analytical, 'r--', label='Analytical') + plt.xlabel('x') + plt.ylabel('u') + plt.legend() + plt.grid(True, color='gray', linestyle='--', linewidth=0.5, alpha=0.7) + plt.tight_layout() + plt.show() + +def RunEno(solver, mesh, iorder): + eno = Eno(solver, mesh, iorder) + init_coef(eno.iorder, eno.coef) + init_field(eno) + + simu_time = solver.T + t = 0.0 + dt = solver.dt + while t < simu_time: + runge_kutta(eno) + if t + dt > simu_time: + dt = simu_time - t + t += dt + #print(f'T={t:.3f},runge_kutta{solver.rk},ENO{eno.iorder},{fluxnames[solver.iflux]} FLUX') + #visualize(eno) + return np.copy(eno.u[eno.ist:eno.ied+1]) + +def performEnoOrderAnalysis(): + iorder_max = 7 + mesh = Mesh() + solver = Solver() + #计算理论解 + u_analytical = analytical_solution(mesh.xcc, solver.T, solver.c, mesh.L) + + u_list = [] + for iorder in range(1, iorder_max+1): + u = RunEno(solver, mesh, iorder) + u_list.append(u) + + plot_eno_OrderAnalysis(solver, mesh.xcc, u_list, u_analytical) + +def performEnoTimestepAnalysis(): + mesh = Mesh() + solver = Solver() + #计算理论解 + u_analytical = analytical_solution(mesh.xcc, solver.T, solver.c, mesh.L) + + u_list = [] + dt_list = [] + solver.dt = 0.025/4 + #solver.dt = 0.025/16 + n = 12 + solver.rk = 2 + iorder = 7 + for i in range(0, n): + u = RunEno(solver, mesh, iorder) + u_list.append(u) + dt_list.append(solver.dt) + print(f'i={i+1},N={n},T={solver.T:.3f},dt={solver.dt},nt={int(solver.T/solver.dt)},runge_kutta{solver.rk},ENO{iorder},{fluxnames[solver.iflux]} FLUX') + solver.dt /= 2 + + plot_eno_TimestepAnalysis(solver, mesh.xcc, u_list, u_analytical, dt_list, iorder) + +def main(): + #performEnoOrderAnalysis() + performEnoTimestepAnalysis() + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/example/1d-linear-convection/eno/rusanov/timestep/rk2-eno/eno7/01/plot.py b/example/1d-linear-convection/eno/rusanov/timestep/rk2-eno/eno7/01/plot.py new file mode 100644 index 00000000..e389044c --- /dev/null +++ b/example/1d-linear-convection/eno/rusanov/timestep/rk2-eno/eno7/01/plot.py @@ -0,0 +1,53 @@ +import numpy as np +import matplotlib.pyplot as plt +import csv +import sys + +nvar = len(sys.argv) +print('nvar=',nvar) +print('sys.argv=',sys.argv) + +order = 1 +if nvar >= 2: + var = sys.argv[1] + print('var=',var) + order = int(var) + +print('order=',order) + +x_list = [] +u_list = [] + +with open('solution.plt', newline='') as csvfile: + #readCSV = csv.reader(csvfile, delimiter= ' ') + icount = 0 + for line in csvfile: + # 去除首尾空格,按连续空格分割 + row = line.strip().split() + #print("row=",row) + x_list.append(row[0]) + u_list.append(row[1]) + icount += 1 + +ni = icount +print("ni=",ni) + +#print("x_list=",x_list) + +x = np.zeros( ni ) +u = np.zeros( ni ) + +for i in range(0, ni): + x[i] = float(x_list[i]) + u[i] = float(u_list[i]) + +labelname = 'Eno' + str(order) + +plt.figure("OneFLOW-CFD Solver", figsize=(8, 6), dpi=100) +plt.plot(x, u, "b-", linewidth=1.0, marker = 's', markerfacecolor='None', label=labelname) +plt.xlabel("$x$") +plt.ylabel("$u$") +plt.title("burgers T=1") +plt.legend() +plt.tight_layout() +plt.show(); \ No newline at end of file diff --git a/example/1d-linear-convection/eno/rusanov/timestep/rk2-eno1/01/eno.py b/example/1d-linear-convection/eno/rusanov/timestep/rk2-eno1/01/eno.py new file mode 100644 index 00000000..00a01f63 --- /dev/null +++ b/example/1d-linear-convection/eno/rusanov/timestep/rk2-eno1/01/eno.py @@ -0,0 +1,425 @@ +import numpy as np +import matplotlib.pyplot as plt + +# 初始条件 +def initial_condition(x): + u0 = np.zeros_like(x) + for i in range(len(x)): + if 0.5 <= x[i] <= 1.0: + u0[i] = 2.0 + else: + u0[i] = 1.0 + return u0 + +# 理论解 +def analytical_solution(x, t, a, L): + # 初始条件沿 x - at 平移 + x_shifted = x - a * t + return initial_condition((x_shifted + L) % L) # 周期边界条件 + +def residual(q, eno): + reconstruction(q, eno) + inviscid_flux(eno.up1_2m, eno.up1_2p, eno.flux, eno) + for i in range(eno.nx): + eno.res[i] = -(eno.flux[i + 1] - eno.flux[i]) / eno.mesh.dx + +def reconstruction(q, eno): + # Choose the stencil by ENO method + eno.dd[0, 0:eno.ntcell-1] = q[0:eno.ntcell-1] + + for m in range(1, eno.iorder): + for j in range(0, eno.ntcell-1): + eno.dd[m, j] = eno.dd[m-1, j+1] - eno.dd[m-1, j] + + for i in range(eno.nx + 1): + eno.il[i] = i - 1 + for m in range(1, eno.iorder): + if abs(eno.dd[m, eno.il[i]-1+eno.ishift]) <= abs(eno.dd[m, eno.il[i]+eno.ishift]): + eno.il[i] -= 1 + + for i in range(eno.nx + 1): + eno.ir[i] = i + for m in range(1, eno.iorder): + if abs(eno.dd[m, eno.ir[i]-1+eno.ishift]) <= abs(eno.dd[m, eno.ir[i]+eno.ishift]): + eno.ir[i] -= 1 + + # Reconstruction u(j+1/2) + for i in range(eno.nx + 1): + k1 = eno.il[i] + k2 = eno.ir[i] + l1 = i - k1 + l2 = i - k2 + eno.up1_2m[i] = 0 + eno.up1_2p[i] = 0 + for m in range(eno.iorder): + eno.up1_2m[i] += q[k1 + eno.ishift + m] * eno.coef[l1, m] + eno.up1_2p[i] += q[k2 + eno.ishift + m] * eno.coef[l2, m] + +fluxnames = [ + 'Rusanov', + 'Engquist-Osher', +] + +def inviscid_flux(up1_2m, up1_2p, flux, eno): + if eno.solver.iflux == 0: + rusanov_flux(up1_2m, up1_2p, flux, eno) + else: + engquist_osher_flux(up1_2m, up1_2p, flux, eno) + +def engquist_osher_flux(up1_2m, up1_2p, flux, eno): + for i in range(eno.nx + 1): + u_L = up1_2m[i] + u_R = up1_2p[i] + + cp = 0.5 * ( eno.solver.c + abs(eno.solver.c) ) + cm = 0.5 * ( eno.solver.c - abs(eno.solver.c) ) + + flux[i] = cp * u_L + cm * u_R + +def rusanov_flux(up1_2m, up1_2p, flux, eno): + for i in range(eno.nx + 1): + u_L = up1_2m[i] + u_R = up1_2p[i] + F_L = eno.solver.c * u_L # 左状态通量 + F_R = eno.solver.c * u_R # 右状态通量 + alpha = abs(eno.solver.c) # 最大波速 + flux[i] = 0.5 * (F_L + F_R) - 0.5 * alpha * (u_R - u_L) + + +def boundary(u, eno): + for i in range(-eno.ighost, 1): + u[eno.ist - 1 + i] = u[eno.ied + i] + for i in range(1, eno.ighost + 2): + u[eno.ied + i] = u[eno.ist - 1 + i] + +def update_oldfield(qn, q): + qn[:] = q[:] + +def init_coef( iorder, coef ): + if iorder == 1: + coef[0] = [1.0] + coef[1] = [1.0] + elif iorder == 2: + coef[0] = [3.0/2.0, -1.0/2.0] + coef[1] = [1.0/2.0, 1.0/2.0] + coef[2] = [-1.0/2.0, 3.0/2.0] + elif iorder == 3: + coef[0] = [ 11.0/6.0, -7.0/6.0, 1.0/3.0 ] + coef[1] = [ 1.0/3.0, 5.0/6.0, -1.0/6.0 ] + coef[2] = [ -1.0/6.0, 5.0/6.0, 1.0/3.0 ] + coef[3] = [ 1.0/3.0, -7.0/6.0, 11.0/6.0 ] + elif iorder == 4: + coef[0] = [ 25.0/12.0, -23.0/12.0, 13.0/12.0, -1.0/4.0 ] + coef[1] = [ 1.0/4.0, 13.0/12.0, -5.0/12.0, 1.0/12.0 ] + coef[2] = [ -1.0/12.0, 7.0/12.0, 7.0/12.0, -1.0/12.0 ] + coef[3] = [ 1.0/12.0, -5.0/12.0, 13.0/12.0, 1.0/4.0 ] + coef[4] = [ -1.0/4.0, 13.0/12.0, -23.0/12.0, 25.0/12.0 ] + elif iorder == 5: + coef[0] = [ 137.0/60.0, -163.0/60.0, 137.0/60.0, -21.0/20.0, 1.0/5.0 ] + coef[1] = [ 1.0/5.0, 77.0/60.0, -43.0/60.0, 17.0/60.0, -1.0/20.0 ] + coef[2] = [ -1.0/20.0, 9.0/20.0, 47.0/60.0, -13.0/60.0, 1.0/30.0 ] + coef[3] = [ 1.0/30.0, -13.0/60.0, 47.0/60.0, 9.0/20.0, -1.0/20.0 ] + coef[4] = [ -1.0/20.0, 17.0/60.0, -43.0/60.0, 77.0/60.0, 1.0/5.0 ] + coef[5] = [ 1.0/5.0, -21.0/20.0, 137.0/60.0, -163.0/60.0, 137.0/60.0 ] + elif iorder == 6: + coef[0] = [ 49.0/20.0, -71.0/20.0, 79.0/20.0, -163.0/60.0, 31.0/30.0, -1.0/6.0 ] + coef[1] = [ 1.0/6.0, 29.0/20.0, -21.0/20.0, 37.0/60.0, -13.0/60.0, 1.0/30.0 ] + coef[2] = [ -1.0/30.0, 11.0/30.0, 19.0/20.0, -23.0/60.0, 7.0/60.0, -1.0/60.0 ] + coef[3] = [ 1.0/60.0, -2.0/15.0, 37.0/60.0, 37.0/60.0, -2.0/15.0, 1.0/60.0 ] + coef[4] = [ -1.0/60.0, 7.0/60.0, -23.0/60.0, 19.0/20.0, 11.0/30.0, -1.0/30.0 ] + coef[5] = [ 1.0/30.0, -13.0/60.0, 37.0/60.0, -21.0/20.0, 29.0/20.0, 1.0/6.0 ] + coef[6] = [ -1.0/6.0, 31.0/30.0, -163.0/60.0, 79.0/20.0, -71.0/20.0, 49.0/20.0 ] + elif iorder == 7: + coef[0] = [ 363.0/140.0, -617.0/140.0, 853.0/140.0, -2341.0/420.0, 667.0/210.0, -43.0/42.0, 1.0/7.0 ] + coef[1] = [ 1.0/7.0, 223.0/140.0, -197.0/140.0, 153.0/140.0, -241.0/420.0, 37.0/210.0, -1.0/42.0 ] + coef[2] = [ -1.0/42.0, 13.0/42.0, 153.0/140.0, -241.0/420.0, 109.0/420.0, -31.0/420.0, 1.0/105.0 ] + coef[3] = [ 1.0/105.0, -19.0/210.0, 107.0/210.0, 319.0/420.0, -101.0/420.0, 5.0/84.0, -1.0/140.0 ] + coef[4] = [ -1.0/140.0, 5.0/84.0, -101.0/420.0, 319.0/420.0, 107.0/210.0, -19.0/210.0, 1.0/105.0 ] + coef[5] = [ 1.0/105.0, -31.0/420.0, 109.0/420.0, -241.0/420.0, 153.0/140.0, 13.0/42.0, -1.0/42.0 ] + coef[6] = [ -1.0/42.0, 37.0/210.0, -241.0/420.0, 153.0/140.0, -197.0/140.0, 223.0/140.0, 1.0/7.0 ] + coef[7] = [ 1.0/7.0, -43.0/42.0, 667.0/210.0, -2341.0/420.0, 853.0/140.0, -617.0/140.0, 363.0/140.0 ] + +def init_field(eno): + for i in range(eno.ist, eno.ied + 1): + j = i - eno.ist + if 0.5 <= eno.mesh.xcc[j] <= 1.0: + eno.u[i] = 2.0 + else: + eno.u[i] = 1.0 + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def runge_kutta(eno): + rk = eno.solver.rk + if rk == 1: + runge_kutta_1(eno) + elif rk == 2: + runge_kutta_2(eno) + else: + runge_kutta_3(eno) + +def runge_kutta_1(eno): + dt = eno.solver.dt + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = eno.u[j] + dt * eno.res[i] + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def runge_kutta_2(eno): + dt = eno.solver.dt + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = eno.u[j] + dt * eno.res[i] + boundary(eno.u, eno) + + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = 0.5 * eno.un[j] + 0.5 * eno.u[j] + 0.5 * dt * eno.res[i] + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def runge_kutta_3(eno): + dt = eno.solver.dt + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = eno.u[j] + dt * eno.res[i] + boundary(eno.u, eno) + + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = 0.75 * eno.un[j] + 0.25 * eno.u[j] + 0.25 * dt * eno.res[i] + boundary(eno.u, eno) + + residual(eno.u, eno) + c1, c2, c3 = 1.0/3.0, 2.0/3.0, 2.0/3.0 + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = c1 * eno.un[j] + c2 * eno.u[j] + c3 * dt * eno.res[i] + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def get_ordinal_numbers(order): + if order == 1: + return 'st' + elif order == 2: + return 'nd' + elif order == 3: + return 'rd' + else: + return 'th' + +def visualize(eno): + with open('solution.plt', 'w') as f: + for i in range(eno.ist, eno.ied + 1): + j = i - eno.ist + f.write(f"{eno.xcc[j]:20.10e}{eno.u[i]:20.10e}\n") + + # 可视化 + u_numerical = np.copy(eno.u[eno.ist:eno.ied+1]) + print(f'u_numerical.size={u_numerical.size}') + print(f'eno.xcc.size={eno.xcc.size}') + #计算理论解 + u_analytical = analytical_solution(eno.mesh.xcc, eno.T, eno.c, eno.L) + print(f'u_analytical.size={u_analytical.size}') + plt.figure("OneFLOW-CFD Solver", figsize=(10, 6)) + plt.scatter(eno.xcc, u_numerical, facecolor="none", edgecolor="blue", s=20, linewidths=0.5, label=f'Numerical (Rusanov)') + plt.plot(eno.xcc, u_analytical, 'r--', label='Analytical') + plt.xlabel('x') + plt.ylabel('u') + ordinal1 = get_ordinal_numbers(eno.iorder) + ordinal2 = get_ordinal_numbers(eno.rk) + plt.title(f'1D Convection Equation at t = {eno.T:.3f} using {eno.iorder}{ordinal1}-order ENO and {eno.rk}{ordinal2}-order Runge-Kutta methods') + plt.legend() + plt.grid(True, color='gray', linestyle='--', linewidth=0.5, alpha=0.7) + plt.tight_layout() + plt.show() + +class Mesh: + def __init__(self): + self.nx = 40 + self.L = 2.0 + self.x = np.zeros(self.nx + 1) + self.xcc = np.zeros(self.nx) + self.init_mesh() + def init_mesh(self): + xstart = 0.0 + xend = self.L + self.dx = (xend - xstart) / self.nx + + for i in range(0, self.nx+1): + self.x[i] = xstart + i * self.dx + + for i in range(0, self.nx): + self.xcc[i] = 0.5 * (self.x[i] + self.x[i + 1]) + +class Solver: + def __init__(self): + self.iflux = 0 + self.rk = 2 + self.c = 1.0 + self.T = 0.625 + self.dt = .0025 + +class Eno: + def __init__(self, solver, mesh, iorder): + self.solver = solver + self.mesh = mesh + self.nx = mesh.nx + self.iorder = iorder + self.ighost = iorder + self.ishift = self.ighost + 1 + self.ist = 0 + self.ishift + self.ied = self.nx - 1 + self.ishift + self.ntcell = self.nx + 2 * self.ishift + self.isize = iorder * (iorder + 1) + + self.il = np.zeros(self.nx + 1, dtype=int) + self.ir = np.zeros(self.nx + 1, dtype=int) + self.coef = np.zeros((iorder + 1, iorder)) + self.dd = np.zeros((iorder, self.ntcell)) + self.up1_2m = np.zeros(self.nx + 1) + self.up1_2p = np.zeros(self.nx + 1) + self.flux = np.zeros(self.nx + 1) + self.res = np.zeros(self.nx) + + # Field module variables + self.u = np.zeros(self.ntcell) + self.un = np.zeros(self.ntcell) + + #self.dt = .0025 + +def plot_eno_OrderAnalysis(solver, xcc, u_list, u_analytical): + # 定义一个包含不同颜色、线形和标记的列表 + styles = [ + {'color': 'black', 'linestyle': '-', 'marker': 'o'}, + {'color': 'blue', 'linestyle': '--', 'marker': 's'}, + {'color': 'black', 'linestyle': '-', 'marker': '^'}, + {'color': 'blue', 'linestyle': '--', 'marker': 'v'}, + {'color': 'black', 'linestyle': '-', 'marker': '<'}, + {'color': 'blue', 'linestyle': '--', 'marker': '>'}, + {'color': 'black', 'linestyle': '-', 'marker': 'D'}, + ] + + n = len(u_list) + num_styles = len(styles) + ordinal = get_ordinal_numbers(solver.rk) + + plt.figure("OneFLOW-CFD Solver", figsize=(10, 6)) + plt.title(f'1D Convection Equation at t = {solver.T:.3f} using [1-7]th-order ENO and {solver.rk}{ordinal}-order Runge-Kutta methods') + for i in range(0, n): + lable = 'Numerical (Rusanov)ENO' + str(i+1) + style = styles[i % num_styles] + plt.plot(xcc, u_list[i], marker=style['marker'], markerfacecolor='none', linestyle=style['linestyle'], color=style['color'], \ + markersize=5, linewidth=0.5, alpha=1.0, label=f'{lable}') + plt.plot(xcc, u_analytical, 'r--', label='Analytical') + plt.xlabel('x') + plt.ylabel('u') + plt.legend() + plt.grid(True, color='gray', linestyle='--', linewidth=0.5, alpha=0.7) + plt.tight_layout() + plt.show() + +def plot_eno_TimestepAnalysis(solver, xcc, u_list, u_analytical, dt_list, iorder): + # 定义一个包含不同颜色、线形和标记的列表 + styles = [ + {'color': 'black', 'linestyle': '-', 'marker': 'o'}, + {'color': 'blue', 'linestyle': '--', 'marker': 's'}, + {'color': 'black', 'linestyle': '-', 'marker': '^'}, + {'color': 'blue', 'linestyle': '--', 'marker': 'v'}, + {'color': 'black', 'linestyle': '-', 'marker': '<'}, + {'color': 'blue', 'linestyle': '--', 'marker': '>'}, + {'color': 'black', 'linestyle': '-', 'marker': 'D'}, + {'color': 'blue', 'linestyle': '--', 'marker': 'o'}, + {'color': 'black', 'linestyle': '-', 'marker': 's'}, + {'color': 'blue', 'linestyle': '--', 'marker': '^'}, + {'color': 'black', 'linestyle': '-', 'marker': 'v'}, + {'color': 'blue', 'linestyle': '--', 'marker': '<'}, + {'color': 'black', 'linestyle': '-', 'marker': '>'}, + {'color': 'blue', 'linestyle': '--', 'marker': 'D'}, + ] + + n = len(u_list) + num_styles = len(styles) + + ordinalENO = get_ordinal_numbers(iorder) + ordinalRK = get_ordinal_numbers(solver.rk) + + plt.figure("OneFLOW-CFD Solver", figsize=(10, 6)) + plt.title(f'1D Convection Equation at t = {solver.T:.3f} using {iorder}{ordinalENO}-order ENO and {solver.rk}{ordinalRK}-order Runge-Kutta methods') + for i in range(0, n): + lable = 'Numerical (Rusanov)ENO' + str(iorder) + ' T='+str(dt_list[i]) + style = styles[i % num_styles] + plt.plot(xcc, u_list[i], marker=style['marker'], markerfacecolor='none', linestyle=style['linestyle'], color=style['color'], \ + markersize=5, linewidth=1.0, alpha=1.0, label=f'{lable}') + plt.plot(xcc, u_analytical, 'r--', label='Analytical') + plt.xlabel('x') + plt.ylabel('u') + plt.legend() + plt.grid(True, color='gray', linestyle='--', linewidth=0.5, alpha=0.7) + plt.tight_layout() + plt.show() + +def RunEno(solver, mesh, iorder): + eno = Eno(solver, mesh, iorder) + init_coef(eno.iorder, eno.coef) + init_field(eno) + + simu_time = solver.T + t = 0.0 + dt = solver.dt + while t < simu_time: + runge_kutta(eno) + if t + dt > simu_time: + dt = simu_time - t + t += dt + #print(f'T={t:.3f},runge_kutta{solver.rk},ENO{eno.iorder},{fluxnames[solver.iflux]} FLUX') + #visualize(eno) + return np.copy(eno.u[eno.ist:eno.ied+1]) + +def performEnoOrderAnalysis(): + iorder_max = 7 + mesh = Mesh() + solver = Solver() + #计算理论解 + u_analytical = analytical_solution(mesh.xcc, solver.T, solver.c, mesh.L) + + u_list = [] + for iorder in range(1, iorder_max+1): + u = RunEno(solver, mesh, iorder) + u_list.append(u) + + plot_eno_OrderAnalysis(solver, mesh.xcc, u_list, u_analytical) + +def performEnoTimestepAnalysis(): + mesh = Mesh() + solver = Solver() + #计算理论解 + u_analytical = analytical_solution(mesh.xcc, solver.T, solver.c, mesh.L) + + u_list = [] + dt_list = [] + solver.dt = 0.025 + #solver.dt = 0.025/16 + n = 12 + iorder = 1 + for i in range(0, n): + u = RunEno(solver, mesh, iorder) + u_list.append(u) + dt_list.append(solver.dt) + print(f'i={i+1},N={n},T={solver.T:.3f},dt={solver.dt},nt={int(solver.T/solver.dt)},runge_kutta{solver.rk},ENO{iorder},{fluxnames[solver.iflux]} FLUX') + solver.dt /= 2 + + plot_eno_TimestepAnalysis(solver, mesh.xcc, u_list, u_analytical, dt_list, iorder) + +def main(): + #performEnoOrderAnalysis() + performEnoTimestepAnalysis() + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/example/1d-linear-convection/eno/rusanov/timestep/rk2-eno1/01/plot.py b/example/1d-linear-convection/eno/rusanov/timestep/rk2-eno1/01/plot.py new file mode 100644 index 00000000..e389044c --- /dev/null +++ b/example/1d-linear-convection/eno/rusanov/timestep/rk2-eno1/01/plot.py @@ -0,0 +1,53 @@ +import numpy as np +import matplotlib.pyplot as plt +import csv +import sys + +nvar = len(sys.argv) +print('nvar=',nvar) +print('sys.argv=',sys.argv) + +order = 1 +if nvar >= 2: + var = sys.argv[1] + print('var=',var) + order = int(var) + +print('order=',order) + +x_list = [] +u_list = [] + +with open('solution.plt', newline='') as csvfile: + #readCSV = csv.reader(csvfile, delimiter= ' ') + icount = 0 + for line in csvfile: + # 去除首尾空格,按连续空格分割 + row = line.strip().split() + #print("row=",row) + x_list.append(row[0]) + u_list.append(row[1]) + icount += 1 + +ni = icount +print("ni=",ni) + +#print("x_list=",x_list) + +x = np.zeros( ni ) +u = np.zeros( ni ) + +for i in range(0, ni): + x[i] = float(x_list[i]) + u[i] = float(u_list[i]) + +labelname = 'Eno' + str(order) + +plt.figure("OneFLOW-CFD Solver", figsize=(8, 6), dpi=100) +plt.plot(x, u, "b-", linewidth=1.0, marker = 's', markerfacecolor='None', label=labelname) +plt.xlabel("$x$") +plt.ylabel("$u$") +plt.title("burgers T=1") +plt.legend() +plt.tight_layout() +plt.show(); \ No newline at end of file diff --git a/example/1d-linear-convection/eno/rusanov/timestep/rk3-eno/eno1/01/eno.py b/example/1d-linear-convection/eno/rusanov/timestep/rk3-eno/eno1/01/eno.py new file mode 100644 index 00000000..c4ea37b1 --- /dev/null +++ b/example/1d-linear-convection/eno/rusanov/timestep/rk3-eno/eno1/01/eno.py @@ -0,0 +1,426 @@ +import numpy as np +import matplotlib.pyplot as plt + +# 初始条件 +def initial_condition(x): + u0 = np.zeros_like(x) + for i in range(len(x)): + if 0.5 <= x[i] <= 1.0: + u0[i] = 2.0 + else: + u0[i] = 1.0 + return u0 + +# 理论解 +def analytical_solution(x, t, a, L): + # 初始条件沿 x - at 平移 + x_shifted = x - a * t + return initial_condition((x_shifted + L) % L) # 周期边界条件 + +def residual(q, eno): + reconstruction(q, eno) + inviscid_flux(eno.up1_2m, eno.up1_2p, eno.flux, eno) + for i in range(eno.nx): + eno.res[i] = -(eno.flux[i + 1] - eno.flux[i]) / eno.mesh.dx + +def reconstruction(q, eno): + # Choose the stencil by ENO method + eno.dd[0, 0:eno.ntcell-1] = q[0:eno.ntcell-1] + + for m in range(1, eno.iorder): + for j in range(0, eno.ntcell-1): + eno.dd[m, j] = eno.dd[m-1, j+1] - eno.dd[m-1, j] + + for i in range(eno.nx + 1): + eno.il[i] = i - 1 + for m in range(1, eno.iorder): + if abs(eno.dd[m, eno.il[i]-1+eno.ishift]) <= abs(eno.dd[m, eno.il[i]+eno.ishift]): + eno.il[i] -= 1 + + for i in range(eno.nx + 1): + eno.ir[i] = i + for m in range(1, eno.iorder): + if abs(eno.dd[m, eno.ir[i]-1+eno.ishift]) <= abs(eno.dd[m, eno.ir[i]+eno.ishift]): + eno.ir[i] -= 1 + + # Reconstruction u(j+1/2) + for i in range(eno.nx + 1): + k1 = eno.il[i] + k2 = eno.ir[i] + l1 = i - k1 + l2 = i - k2 + eno.up1_2m[i] = 0 + eno.up1_2p[i] = 0 + for m in range(eno.iorder): + eno.up1_2m[i] += q[k1 + eno.ishift + m] * eno.coef[l1, m] + eno.up1_2p[i] += q[k2 + eno.ishift + m] * eno.coef[l2, m] + +fluxnames = [ + 'Rusanov', + 'Engquist-Osher', +] + +def inviscid_flux(up1_2m, up1_2p, flux, eno): + if eno.solver.iflux == 0: + rusanov_flux(up1_2m, up1_2p, flux, eno) + else: + engquist_osher_flux(up1_2m, up1_2p, flux, eno) + +def engquist_osher_flux(up1_2m, up1_2p, flux, eno): + for i in range(eno.nx + 1): + u_L = up1_2m[i] + u_R = up1_2p[i] + + cp = 0.5 * ( eno.solver.c + abs(eno.solver.c) ) + cm = 0.5 * ( eno.solver.c - abs(eno.solver.c) ) + + flux[i] = cp * u_L + cm * u_R + +def rusanov_flux(up1_2m, up1_2p, flux, eno): + for i in range(eno.nx + 1): + u_L = up1_2m[i] + u_R = up1_2p[i] + F_L = eno.solver.c * u_L # 左状态通量 + F_R = eno.solver.c * u_R # 右状态通量 + alpha = abs(eno.solver.c) # 最大波速 + flux[i] = 0.5 * (F_L + F_R) - 0.5 * alpha * (u_R - u_L) + + +def boundary(u, eno): + for i in range(-eno.ighost, 1): + u[eno.ist - 1 + i] = u[eno.ied + i] + for i in range(1, eno.ighost + 2): + u[eno.ied + i] = u[eno.ist - 1 + i] + +def update_oldfield(qn, q): + qn[:] = q[:] + +def init_coef( iorder, coef ): + if iorder == 1: + coef[0] = [1.0] + coef[1] = [1.0] + elif iorder == 2: + coef[0] = [3.0/2.0, -1.0/2.0] + coef[1] = [1.0/2.0, 1.0/2.0] + coef[2] = [-1.0/2.0, 3.0/2.0] + elif iorder == 3: + coef[0] = [ 11.0/6.0, -7.0/6.0, 1.0/3.0 ] + coef[1] = [ 1.0/3.0, 5.0/6.0, -1.0/6.0 ] + coef[2] = [ -1.0/6.0, 5.0/6.0, 1.0/3.0 ] + coef[3] = [ 1.0/3.0, -7.0/6.0, 11.0/6.0 ] + elif iorder == 4: + coef[0] = [ 25.0/12.0, -23.0/12.0, 13.0/12.0, -1.0/4.0 ] + coef[1] = [ 1.0/4.0, 13.0/12.0, -5.0/12.0, 1.0/12.0 ] + coef[2] = [ -1.0/12.0, 7.0/12.0, 7.0/12.0, -1.0/12.0 ] + coef[3] = [ 1.0/12.0, -5.0/12.0, 13.0/12.0, 1.0/4.0 ] + coef[4] = [ -1.0/4.0, 13.0/12.0, -23.0/12.0, 25.0/12.0 ] + elif iorder == 5: + coef[0] = [ 137.0/60.0, -163.0/60.0, 137.0/60.0, -21.0/20.0, 1.0/5.0 ] + coef[1] = [ 1.0/5.0, 77.0/60.0, -43.0/60.0, 17.0/60.0, -1.0/20.0 ] + coef[2] = [ -1.0/20.0, 9.0/20.0, 47.0/60.0, -13.0/60.0, 1.0/30.0 ] + coef[3] = [ 1.0/30.0, -13.0/60.0, 47.0/60.0, 9.0/20.0, -1.0/20.0 ] + coef[4] = [ -1.0/20.0, 17.0/60.0, -43.0/60.0, 77.0/60.0, 1.0/5.0 ] + coef[5] = [ 1.0/5.0, -21.0/20.0, 137.0/60.0, -163.0/60.0, 137.0/60.0 ] + elif iorder == 6: + coef[0] = [ 49.0/20.0, -71.0/20.0, 79.0/20.0, -163.0/60.0, 31.0/30.0, -1.0/6.0 ] + coef[1] = [ 1.0/6.0, 29.0/20.0, -21.0/20.0, 37.0/60.0, -13.0/60.0, 1.0/30.0 ] + coef[2] = [ -1.0/30.0, 11.0/30.0, 19.0/20.0, -23.0/60.0, 7.0/60.0, -1.0/60.0 ] + coef[3] = [ 1.0/60.0, -2.0/15.0, 37.0/60.0, 37.0/60.0, -2.0/15.0, 1.0/60.0 ] + coef[4] = [ -1.0/60.0, 7.0/60.0, -23.0/60.0, 19.0/20.0, 11.0/30.0, -1.0/30.0 ] + coef[5] = [ 1.0/30.0, -13.0/60.0, 37.0/60.0, -21.0/20.0, 29.0/20.0, 1.0/6.0 ] + coef[6] = [ -1.0/6.0, 31.0/30.0, -163.0/60.0, 79.0/20.0, -71.0/20.0, 49.0/20.0 ] + elif iorder == 7: + coef[0] = [ 363.0/140.0, -617.0/140.0, 853.0/140.0, -2341.0/420.0, 667.0/210.0, -43.0/42.0, 1.0/7.0 ] + coef[1] = [ 1.0/7.0, 223.0/140.0, -197.0/140.0, 153.0/140.0, -241.0/420.0, 37.0/210.0, -1.0/42.0 ] + coef[2] = [ -1.0/42.0, 13.0/42.0, 153.0/140.0, -241.0/420.0, 109.0/420.0, -31.0/420.0, 1.0/105.0 ] + coef[3] = [ 1.0/105.0, -19.0/210.0, 107.0/210.0, 319.0/420.0, -101.0/420.0, 5.0/84.0, -1.0/140.0 ] + coef[4] = [ -1.0/140.0, 5.0/84.0, -101.0/420.0, 319.0/420.0, 107.0/210.0, -19.0/210.0, 1.0/105.0 ] + coef[5] = [ 1.0/105.0, -31.0/420.0, 109.0/420.0, -241.0/420.0, 153.0/140.0, 13.0/42.0, -1.0/42.0 ] + coef[6] = [ -1.0/42.0, 37.0/210.0, -241.0/420.0, 153.0/140.0, -197.0/140.0, 223.0/140.0, 1.0/7.0 ] + coef[7] = [ 1.0/7.0, -43.0/42.0, 667.0/210.0, -2341.0/420.0, 853.0/140.0, -617.0/140.0, 363.0/140.0 ] + +def init_field(eno): + for i in range(eno.ist, eno.ied + 1): + j = i - eno.ist + if 0.5 <= eno.mesh.xcc[j] <= 1.0: + eno.u[i] = 2.0 + else: + eno.u[i] = 1.0 + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def runge_kutta(eno): + rk = eno.solver.rk + if rk == 1: + runge_kutta_1(eno) + elif rk == 2: + runge_kutta_2(eno) + else: + runge_kutta_3(eno) + +def runge_kutta_1(eno): + dt = eno.solver.dt + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = eno.u[j] + dt * eno.res[i] + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def runge_kutta_2(eno): + dt = eno.solver.dt + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = eno.u[j] + dt * eno.res[i] + boundary(eno.u, eno) + + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = 0.5 * eno.un[j] + 0.5 * eno.u[j] + 0.5 * dt * eno.res[i] + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def runge_kutta_3(eno): + dt = eno.solver.dt + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = eno.u[j] + dt * eno.res[i] + boundary(eno.u, eno) + + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = 0.75 * eno.un[j] + 0.25 * eno.u[j] + 0.25 * dt * eno.res[i] + boundary(eno.u, eno) + + residual(eno.u, eno) + c1, c2, c3 = 1.0/3.0, 2.0/3.0, 2.0/3.0 + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = c1 * eno.un[j] + c2 * eno.u[j] + c3 * dt * eno.res[i] + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def get_ordinal_numbers(order): + if order == 1: + return 'st' + elif order == 2: + return 'nd' + elif order == 3: + return 'rd' + else: + return 'th' + +def visualize(eno): + with open('solution.plt', 'w') as f: + for i in range(eno.ist, eno.ied + 1): + j = i - eno.ist + f.write(f"{eno.xcc[j]:20.10e}{eno.u[i]:20.10e}\n") + + # 可视化 + u_numerical = np.copy(eno.u[eno.ist:eno.ied+1]) + print(f'u_numerical.size={u_numerical.size}') + print(f'eno.xcc.size={eno.xcc.size}') + #计算理论解 + u_analytical = analytical_solution(eno.mesh.xcc, eno.T, eno.c, eno.L) + print(f'u_analytical.size={u_analytical.size}') + plt.figure("OneFLOW-CFD Solver", figsize=(10, 6)) + plt.scatter(eno.xcc, u_numerical, facecolor="none", edgecolor="blue", s=20, linewidths=0.5, label=f'Numerical (Rusanov)') + plt.plot(eno.xcc, u_analytical, 'r--', label='Analytical') + plt.xlabel('x') + plt.ylabel('u') + ordinal1 = get_ordinal_numbers(eno.iorder) + ordinal2 = get_ordinal_numbers(eno.rk) + plt.title(f'1D Convection Equation at t = {eno.T:.3f} using {eno.iorder}{ordinal1}-order ENO and {eno.rk}{ordinal2}-order Runge-Kutta methods') + plt.legend() + plt.grid(True, color='gray', linestyle='--', linewidth=0.5, alpha=0.7) + plt.tight_layout() + plt.show() + +class Mesh: + def __init__(self): + self.nx = 40 + self.L = 2.0 + self.x = np.zeros(self.nx + 1) + self.xcc = np.zeros(self.nx) + self.init_mesh() + def init_mesh(self): + xstart = 0.0 + xend = self.L + self.dx = (xend - xstart) / self.nx + + for i in range(0, self.nx+1): + self.x[i] = xstart + i * self.dx + + for i in range(0, self.nx): + self.xcc[i] = 0.5 * (self.x[i] + self.x[i + 1]) + +class Solver: + def __init__(self): + self.iflux = 0 + self.rk = 1 + self.c = 1.0 + self.T = 0.625 + self.dt = .0025 + +class Eno: + def __init__(self, solver, mesh, iorder): + self.solver = solver + self.mesh = mesh + self.nx = mesh.nx + self.iorder = iorder + self.ighost = iorder + self.ishift = self.ighost + 1 + self.ist = 0 + self.ishift + self.ied = self.nx - 1 + self.ishift + self.ntcell = self.nx + 2 * self.ishift + self.isize = iorder * (iorder + 1) + + self.il = np.zeros(self.nx + 1, dtype=int) + self.ir = np.zeros(self.nx + 1, dtype=int) + self.coef = np.zeros((iorder + 1, iorder)) + self.dd = np.zeros((iorder, self.ntcell)) + self.up1_2m = np.zeros(self.nx + 1) + self.up1_2p = np.zeros(self.nx + 1) + self.flux = np.zeros(self.nx + 1) + self.res = np.zeros(self.nx) + + # Field module variables + self.u = np.zeros(self.ntcell) + self.un = np.zeros(self.ntcell) + + #self.dt = .0025 + +def plot_eno_OrderAnalysis(solver, xcc, u_list, u_analytical): + # 定义一个包含不同颜色、线形和标记的列表 + styles = [ + {'color': 'black', 'linestyle': '-', 'marker': 'o'}, + {'color': 'blue', 'linestyle': '--', 'marker': 's'}, + {'color': 'black', 'linestyle': '-', 'marker': '^'}, + {'color': 'blue', 'linestyle': '--', 'marker': 'v'}, + {'color': 'black', 'linestyle': '-', 'marker': '<'}, + {'color': 'blue', 'linestyle': '--', 'marker': '>'}, + {'color': 'black', 'linestyle': '-', 'marker': 'D'}, + ] + + n = len(u_list) + num_styles = len(styles) + ordinal = get_ordinal_numbers(solver.rk) + + plt.figure("OneFLOW-CFD Solver", figsize=(10, 6)) + plt.title(f'1D Convection Equation at t = {solver.T:.3f} using [1-7]th-order ENO and {solver.rk}{ordinal}-order Runge-Kutta methods') + for i in range(0, n): + lable = 'Numerical (Rusanov)ENO' + str(i+1) + style = styles[i % num_styles] + plt.plot(xcc, u_list[i], marker=style['marker'], markerfacecolor='none', linestyle=style['linestyle'], color=style['color'], \ + markersize=5, linewidth=0.5, alpha=1.0, label=f'{lable}') + plt.plot(xcc, u_analytical, 'r--', label='Analytical') + plt.xlabel('x') + plt.ylabel('u') + plt.legend() + plt.grid(True, color='gray', linestyle='--', linewidth=0.5, alpha=0.7) + plt.tight_layout() + plt.show() + +def plot_eno_TimestepAnalysis(solver, xcc, u_list, u_analytical, dt_list, iorder): + # 定义一个包含不同颜色、线形和标记的列表 + styles = [ + {'color': 'black', 'linestyle': '-', 'marker': 'o'}, + {'color': 'blue', 'linestyle': '--', 'marker': 's'}, + {'color': 'black', 'linestyle': '-', 'marker': '^'}, + {'color': 'blue', 'linestyle': '--', 'marker': 'v'}, + {'color': 'black', 'linestyle': '-', 'marker': '<'}, + {'color': 'blue', 'linestyle': '--', 'marker': '>'}, + {'color': 'black', 'linestyle': '-', 'marker': 'D'}, + {'color': 'blue', 'linestyle': '--', 'marker': 'o'}, + {'color': 'black', 'linestyle': '-', 'marker': 's'}, + {'color': 'blue', 'linestyle': '--', 'marker': '^'}, + {'color': 'black', 'linestyle': '-', 'marker': 'v'}, + {'color': 'blue', 'linestyle': '--', 'marker': '<'}, + {'color': 'black', 'linestyle': '-', 'marker': '>'}, + {'color': 'blue', 'linestyle': '--', 'marker': 'D'}, + ] + + n = len(u_list) + num_styles = len(styles) + + ordinalENO = get_ordinal_numbers(iorder) + ordinalRK = get_ordinal_numbers(solver.rk) + + plt.figure("OneFLOW-CFD Solver", figsize=(10, 6)) + plt.title(f'1D Convection Equation at t = {solver.T:.3f} using {iorder}{ordinalENO}-order ENO and {solver.rk}{ordinalRK}-order Runge-Kutta methods') + for i in range(0, n): + lable = 'Numerical (Rusanov)ENO' + str(iorder) + ' T='+str(dt_list[i]) + style = styles[i % num_styles] + plt.plot(xcc, u_list[i], marker=style['marker'], markerfacecolor='none', linestyle=style['linestyle'], color=style['color'], \ + markersize=5, linewidth=1.0, alpha=1.0, label=f'{lable}') + plt.plot(xcc, u_analytical, 'r--', label='Analytical') + plt.xlabel('x') + plt.ylabel('u') + plt.legend() + plt.grid(True, color='gray', linestyle='--', linewidth=0.5, alpha=0.7) + plt.tight_layout() + plt.show() + +def RunEno(solver, mesh, iorder): + eno = Eno(solver, mesh, iorder) + init_coef(eno.iorder, eno.coef) + init_field(eno) + + simu_time = solver.T + t = 0.0 + dt = solver.dt + while t < simu_time: + runge_kutta(eno) + if t + dt > simu_time: + dt = simu_time - t + t += dt + #print(f'T={t:.3f},runge_kutta{solver.rk},ENO{eno.iorder},{fluxnames[solver.iflux]} FLUX') + #visualize(eno) + return np.copy(eno.u[eno.ist:eno.ied+1]) + +def performEnoOrderAnalysis(): + iorder_max = 7 + mesh = Mesh() + solver = Solver() + #计算理论解 + u_analytical = analytical_solution(mesh.xcc, solver.T, solver.c, mesh.L) + + u_list = [] + for iorder in range(1, iorder_max+1): + u = RunEno(solver, mesh, iorder) + u_list.append(u) + + plot_eno_OrderAnalysis(solver, mesh.xcc, u_list, u_analytical) + +def performEnoTimestepAnalysis(): + mesh = Mesh() + solver = Solver() + #计算理论解 + u_analytical = analytical_solution(mesh.xcc, solver.T, solver.c, mesh.L) + + u_list = [] + dt_list = [] + solver.dt = 0.025/4 + #solver.dt = 0.025/16 + n = 12 + solver.rk = 3 + iorder = 1 + for i in range(0, n): + u = RunEno(solver, mesh, iorder) + u_list.append(u) + dt_list.append(solver.dt) + print(f'i={i+1},N={n},T={solver.T:.3f},dt={solver.dt},nt={int(solver.T/solver.dt)},runge_kutta{solver.rk},ENO{iorder},{fluxnames[solver.iflux]} FLUX') + solver.dt /= 2 + + plot_eno_TimestepAnalysis(solver, mesh.xcc, u_list, u_analytical, dt_list, iorder) + +def main(): + #performEnoOrderAnalysis() + performEnoTimestepAnalysis() + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/example/1d-linear-convection/eno/rusanov/timestep/rk3-eno/eno1/01/plot.py b/example/1d-linear-convection/eno/rusanov/timestep/rk3-eno/eno1/01/plot.py new file mode 100644 index 00000000..e389044c --- /dev/null +++ b/example/1d-linear-convection/eno/rusanov/timestep/rk3-eno/eno1/01/plot.py @@ -0,0 +1,53 @@ +import numpy as np +import matplotlib.pyplot as plt +import csv +import sys + +nvar = len(sys.argv) +print('nvar=',nvar) +print('sys.argv=',sys.argv) + +order = 1 +if nvar >= 2: + var = sys.argv[1] + print('var=',var) + order = int(var) + +print('order=',order) + +x_list = [] +u_list = [] + +with open('solution.plt', newline='') as csvfile: + #readCSV = csv.reader(csvfile, delimiter= ' ') + icount = 0 + for line in csvfile: + # 去除首尾空格,按连续空格分割 + row = line.strip().split() + #print("row=",row) + x_list.append(row[0]) + u_list.append(row[1]) + icount += 1 + +ni = icount +print("ni=",ni) + +#print("x_list=",x_list) + +x = np.zeros( ni ) +u = np.zeros( ni ) + +for i in range(0, ni): + x[i] = float(x_list[i]) + u[i] = float(u_list[i]) + +labelname = 'Eno' + str(order) + +plt.figure("OneFLOW-CFD Solver", figsize=(8, 6), dpi=100) +plt.plot(x, u, "b-", linewidth=1.0, marker = 's', markerfacecolor='None', label=labelname) +plt.xlabel("$x$") +plt.ylabel("$u$") +plt.title("burgers T=1") +plt.legend() +plt.tight_layout() +plt.show(); \ No newline at end of file diff --git a/example/1d-linear-convection/eno/rusanov/timestep/rk3-eno/eno2/01/eno.py b/example/1d-linear-convection/eno/rusanov/timestep/rk3-eno/eno2/01/eno.py new file mode 100644 index 00000000..d8b332f4 --- /dev/null +++ b/example/1d-linear-convection/eno/rusanov/timestep/rk3-eno/eno2/01/eno.py @@ -0,0 +1,426 @@ +import numpy as np +import matplotlib.pyplot as plt + +# 初始条件 +def initial_condition(x): + u0 = np.zeros_like(x) + for i in range(len(x)): + if 0.5 <= x[i] <= 1.0: + u0[i] = 2.0 + else: + u0[i] = 1.0 + return u0 + +# 理论解 +def analytical_solution(x, t, a, L): + # 初始条件沿 x - at 平移 + x_shifted = x - a * t + return initial_condition((x_shifted + L) % L) # 周期边界条件 + +def residual(q, eno): + reconstruction(q, eno) + inviscid_flux(eno.up1_2m, eno.up1_2p, eno.flux, eno) + for i in range(eno.nx): + eno.res[i] = -(eno.flux[i + 1] - eno.flux[i]) / eno.mesh.dx + +def reconstruction(q, eno): + # Choose the stencil by ENO method + eno.dd[0, 0:eno.ntcell-1] = q[0:eno.ntcell-1] + + for m in range(1, eno.iorder): + for j in range(0, eno.ntcell-1): + eno.dd[m, j] = eno.dd[m-1, j+1] - eno.dd[m-1, j] + + for i in range(eno.nx + 1): + eno.il[i] = i - 1 + for m in range(1, eno.iorder): + if abs(eno.dd[m, eno.il[i]-1+eno.ishift]) <= abs(eno.dd[m, eno.il[i]+eno.ishift]): + eno.il[i] -= 1 + + for i in range(eno.nx + 1): + eno.ir[i] = i + for m in range(1, eno.iorder): + if abs(eno.dd[m, eno.ir[i]-1+eno.ishift]) <= abs(eno.dd[m, eno.ir[i]+eno.ishift]): + eno.ir[i] -= 1 + + # Reconstruction u(j+1/2) + for i in range(eno.nx + 1): + k1 = eno.il[i] + k2 = eno.ir[i] + l1 = i - k1 + l2 = i - k2 + eno.up1_2m[i] = 0 + eno.up1_2p[i] = 0 + for m in range(eno.iorder): + eno.up1_2m[i] += q[k1 + eno.ishift + m] * eno.coef[l1, m] + eno.up1_2p[i] += q[k2 + eno.ishift + m] * eno.coef[l2, m] + +fluxnames = [ + 'Rusanov', + 'Engquist-Osher', +] + +def inviscid_flux(up1_2m, up1_2p, flux, eno): + if eno.solver.iflux == 0: + rusanov_flux(up1_2m, up1_2p, flux, eno) + else: + engquist_osher_flux(up1_2m, up1_2p, flux, eno) + +def engquist_osher_flux(up1_2m, up1_2p, flux, eno): + for i in range(eno.nx + 1): + u_L = up1_2m[i] + u_R = up1_2p[i] + + cp = 0.5 * ( eno.solver.c + abs(eno.solver.c) ) + cm = 0.5 * ( eno.solver.c - abs(eno.solver.c) ) + + flux[i] = cp * u_L + cm * u_R + +def rusanov_flux(up1_2m, up1_2p, flux, eno): + for i in range(eno.nx + 1): + u_L = up1_2m[i] + u_R = up1_2p[i] + F_L = eno.solver.c * u_L # 左状态通量 + F_R = eno.solver.c * u_R # 右状态通量 + alpha = abs(eno.solver.c) # 最大波速 + flux[i] = 0.5 * (F_L + F_R) - 0.5 * alpha * (u_R - u_L) + + +def boundary(u, eno): + for i in range(-eno.ighost, 1): + u[eno.ist - 1 + i] = u[eno.ied + i] + for i in range(1, eno.ighost + 2): + u[eno.ied + i] = u[eno.ist - 1 + i] + +def update_oldfield(qn, q): + qn[:] = q[:] + +def init_coef( iorder, coef ): + if iorder == 1: + coef[0] = [1.0] + coef[1] = [1.0] + elif iorder == 2: + coef[0] = [3.0/2.0, -1.0/2.0] + coef[1] = [1.0/2.0, 1.0/2.0] + coef[2] = [-1.0/2.0, 3.0/2.0] + elif iorder == 3: + coef[0] = [ 11.0/6.0, -7.0/6.0, 1.0/3.0 ] + coef[1] = [ 1.0/3.0, 5.0/6.0, -1.0/6.0 ] + coef[2] = [ -1.0/6.0, 5.0/6.0, 1.0/3.0 ] + coef[3] = [ 1.0/3.0, -7.0/6.0, 11.0/6.0 ] + elif iorder == 4: + coef[0] = [ 25.0/12.0, -23.0/12.0, 13.0/12.0, -1.0/4.0 ] + coef[1] = [ 1.0/4.0, 13.0/12.0, -5.0/12.0, 1.0/12.0 ] + coef[2] = [ -1.0/12.0, 7.0/12.0, 7.0/12.0, -1.0/12.0 ] + coef[3] = [ 1.0/12.0, -5.0/12.0, 13.0/12.0, 1.0/4.0 ] + coef[4] = [ -1.0/4.0, 13.0/12.0, -23.0/12.0, 25.0/12.0 ] + elif iorder == 5: + coef[0] = [ 137.0/60.0, -163.0/60.0, 137.0/60.0, -21.0/20.0, 1.0/5.0 ] + coef[1] = [ 1.0/5.0, 77.0/60.0, -43.0/60.0, 17.0/60.0, -1.0/20.0 ] + coef[2] = [ -1.0/20.0, 9.0/20.0, 47.0/60.0, -13.0/60.0, 1.0/30.0 ] + coef[3] = [ 1.0/30.0, -13.0/60.0, 47.0/60.0, 9.0/20.0, -1.0/20.0 ] + coef[4] = [ -1.0/20.0, 17.0/60.0, -43.0/60.0, 77.0/60.0, 1.0/5.0 ] + coef[5] = [ 1.0/5.0, -21.0/20.0, 137.0/60.0, -163.0/60.0, 137.0/60.0 ] + elif iorder == 6: + coef[0] = [ 49.0/20.0, -71.0/20.0, 79.0/20.0, -163.0/60.0, 31.0/30.0, -1.0/6.0 ] + coef[1] = [ 1.0/6.0, 29.0/20.0, -21.0/20.0, 37.0/60.0, -13.0/60.0, 1.0/30.0 ] + coef[2] = [ -1.0/30.0, 11.0/30.0, 19.0/20.0, -23.0/60.0, 7.0/60.0, -1.0/60.0 ] + coef[3] = [ 1.0/60.0, -2.0/15.0, 37.0/60.0, 37.0/60.0, -2.0/15.0, 1.0/60.0 ] + coef[4] = [ -1.0/60.0, 7.0/60.0, -23.0/60.0, 19.0/20.0, 11.0/30.0, -1.0/30.0 ] + coef[5] = [ 1.0/30.0, -13.0/60.0, 37.0/60.0, -21.0/20.0, 29.0/20.0, 1.0/6.0 ] + coef[6] = [ -1.0/6.0, 31.0/30.0, -163.0/60.0, 79.0/20.0, -71.0/20.0, 49.0/20.0 ] + elif iorder == 7: + coef[0] = [ 363.0/140.0, -617.0/140.0, 853.0/140.0, -2341.0/420.0, 667.0/210.0, -43.0/42.0, 1.0/7.0 ] + coef[1] = [ 1.0/7.0, 223.0/140.0, -197.0/140.0, 153.0/140.0, -241.0/420.0, 37.0/210.0, -1.0/42.0 ] + coef[2] = [ -1.0/42.0, 13.0/42.0, 153.0/140.0, -241.0/420.0, 109.0/420.0, -31.0/420.0, 1.0/105.0 ] + coef[3] = [ 1.0/105.0, -19.0/210.0, 107.0/210.0, 319.0/420.0, -101.0/420.0, 5.0/84.0, -1.0/140.0 ] + coef[4] = [ -1.0/140.0, 5.0/84.0, -101.0/420.0, 319.0/420.0, 107.0/210.0, -19.0/210.0, 1.0/105.0 ] + coef[5] = [ 1.0/105.0, -31.0/420.0, 109.0/420.0, -241.0/420.0, 153.0/140.0, 13.0/42.0, -1.0/42.0 ] + coef[6] = [ -1.0/42.0, 37.0/210.0, -241.0/420.0, 153.0/140.0, -197.0/140.0, 223.0/140.0, 1.0/7.0 ] + coef[7] = [ 1.0/7.0, -43.0/42.0, 667.0/210.0, -2341.0/420.0, 853.0/140.0, -617.0/140.0, 363.0/140.0 ] + +def init_field(eno): + for i in range(eno.ist, eno.ied + 1): + j = i - eno.ist + if 0.5 <= eno.mesh.xcc[j] <= 1.0: + eno.u[i] = 2.0 + else: + eno.u[i] = 1.0 + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def runge_kutta(eno): + rk = eno.solver.rk + if rk == 1: + runge_kutta_1(eno) + elif rk == 2: + runge_kutta_2(eno) + else: + runge_kutta_3(eno) + +def runge_kutta_1(eno): + dt = eno.solver.dt + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = eno.u[j] + dt * eno.res[i] + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def runge_kutta_2(eno): + dt = eno.solver.dt + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = eno.u[j] + dt * eno.res[i] + boundary(eno.u, eno) + + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = 0.5 * eno.un[j] + 0.5 * eno.u[j] + 0.5 * dt * eno.res[i] + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def runge_kutta_3(eno): + dt = eno.solver.dt + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = eno.u[j] + dt * eno.res[i] + boundary(eno.u, eno) + + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = 0.75 * eno.un[j] + 0.25 * eno.u[j] + 0.25 * dt * eno.res[i] + boundary(eno.u, eno) + + residual(eno.u, eno) + c1, c2, c3 = 1.0/3.0, 2.0/3.0, 2.0/3.0 + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = c1 * eno.un[j] + c2 * eno.u[j] + c3 * dt * eno.res[i] + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def get_ordinal_numbers(order): + if order == 1: + return 'st' + elif order == 2: + return 'nd' + elif order == 3: + return 'rd' + else: + return 'th' + +def visualize(eno): + with open('solution.plt', 'w') as f: + for i in range(eno.ist, eno.ied + 1): + j = i - eno.ist + f.write(f"{eno.xcc[j]:20.10e}{eno.u[i]:20.10e}\n") + + # 可视化 + u_numerical = np.copy(eno.u[eno.ist:eno.ied+1]) + print(f'u_numerical.size={u_numerical.size}') + print(f'eno.xcc.size={eno.xcc.size}') + #计算理论解 + u_analytical = analytical_solution(eno.mesh.xcc, eno.T, eno.c, eno.L) + print(f'u_analytical.size={u_analytical.size}') + plt.figure("OneFLOW-CFD Solver", figsize=(10, 6)) + plt.scatter(eno.xcc, u_numerical, facecolor="none", edgecolor="blue", s=20, linewidths=0.5, label=f'Numerical (Rusanov)') + plt.plot(eno.xcc, u_analytical, 'r--', label='Analytical') + plt.xlabel('x') + plt.ylabel('u') + ordinal1 = get_ordinal_numbers(eno.iorder) + ordinal2 = get_ordinal_numbers(eno.rk) + plt.title(f'1D Convection Equation at t = {eno.T:.3f} using {eno.iorder}{ordinal1}-order ENO and {eno.rk}{ordinal2}-order Runge-Kutta methods') + plt.legend() + plt.grid(True, color='gray', linestyle='--', linewidth=0.5, alpha=0.7) + plt.tight_layout() + plt.show() + +class Mesh: + def __init__(self): + self.nx = 40 + self.L = 2.0 + self.x = np.zeros(self.nx + 1) + self.xcc = np.zeros(self.nx) + self.init_mesh() + def init_mesh(self): + xstart = 0.0 + xend = self.L + self.dx = (xend - xstart) / self.nx + + for i in range(0, self.nx+1): + self.x[i] = xstart + i * self.dx + + for i in range(0, self.nx): + self.xcc[i] = 0.5 * (self.x[i] + self.x[i + 1]) + +class Solver: + def __init__(self): + self.iflux = 0 + self.rk = 1 + self.c = 1.0 + self.T = 0.625 + self.dt = .0025 + +class Eno: + def __init__(self, solver, mesh, iorder): + self.solver = solver + self.mesh = mesh + self.nx = mesh.nx + self.iorder = iorder + self.ighost = iorder + self.ishift = self.ighost + 1 + self.ist = 0 + self.ishift + self.ied = self.nx - 1 + self.ishift + self.ntcell = self.nx + 2 * self.ishift + self.isize = iorder * (iorder + 1) + + self.il = np.zeros(self.nx + 1, dtype=int) + self.ir = np.zeros(self.nx + 1, dtype=int) + self.coef = np.zeros((iorder + 1, iorder)) + self.dd = np.zeros((iorder, self.ntcell)) + self.up1_2m = np.zeros(self.nx + 1) + self.up1_2p = np.zeros(self.nx + 1) + self.flux = np.zeros(self.nx + 1) + self.res = np.zeros(self.nx) + + # Field module variables + self.u = np.zeros(self.ntcell) + self.un = np.zeros(self.ntcell) + + #self.dt = .0025 + +def plot_eno_OrderAnalysis(solver, xcc, u_list, u_analytical): + # 定义一个包含不同颜色、线形和标记的列表 + styles = [ + {'color': 'black', 'linestyle': '-', 'marker': 'o'}, + {'color': 'blue', 'linestyle': '--', 'marker': 's'}, + {'color': 'black', 'linestyle': '-', 'marker': '^'}, + {'color': 'blue', 'linestyle': '--', 'marker': 'v'}, + {'color': 'black', 'linestyle': '-', 'marker': '<'}, + {'color': 'blue', 'linestyle': '--', 'marker': '>'}, + {'color': 'black', 'linestyle': '-', 'marker': 'D'}, + ] + + n = len(u_list) + num_styles = len(styles) + ordinal = get_ordinal_numbers(solver.rk) + + plt.figure("OneFLOW-CFD Solver", figsize=(10, 6)) + plt.title(f'1D Convection Equation at t = {solver.T:.3f} using [1-7]th-order ENO and {solver.rk}{ordinal}-order Runge-Kutta methods') + for i in range(0, n): + lable = 'Numerical (Rusanov)ENO' + str(i+1) + style = styles[i % num_styles] + plt.plot(xcc, u_list[i], marker=style['marker'], markerfacecolor='none', linestyle=style['linestyle'], color=style['color'], \ + markersize=5, linewidth=0.5, alpha=1.0, label=f'{lable}') + plt.plot(xcc, u_analytical, 'r--', label='Analytical') + plt.xlabel('x') + plt.ylabel('u') + plt.legend() + plt.grid(True, color='gray', linestyle='--', linewidth=0.5, alpha=0.7) + plt.tight_layout() + plt.show() + +def plot_eno_TimestepAnalysis(solver, xcc, u_list, u_analytical, dt_list, iorder): + # 定义一个包含不同颜色、线形和标记的列表 + styles = [ + {'color': 'black', 'linestyle': '-', 'marker': 'o'}, + {'color': 'blue', 'linestyle': '--', 'marker': 's'}, + {'color': 'black', 'linestyle': '-', 'marker': '^'}, + {'color': 'blue', 'linestyle': '--', 'marker': 'v'}, + {'color': 'black', 'linestyle': '-', 'marker': '<'}, + {'color': 'blue', 'linestyle': '--', 'marker': '>'}, + {'color': 'black', 'linestyle': '-', 'marker': 'D'}, + {'color': 'blue', 'linestyle': '--', 'marker': 'o'}, + {'color': 'black', 'linestyle': '-', 'marker': 's'}, + {'color': 'blue', 'linestyle': '--', 'marker': '^'}, + {'color': 'black', 'linestyle': '-', 'marker': 'v'}, + {'color': 'blue', 'linestyle': '--', 'marker': '<'}, + {'color': 'black', 'linestyle': '-', 'marker': '>'}, + {'color': 'blue', 'linestyle': '--', 'marker': 'D'}, + ] + + n = len(u_list) + num_styles = len(styles) + + ordinalENO = get_ordinal_numbers(iorder) + ordinalRK = get_ordinal_numbers(solver.rk) + + plt.figure("OneFLOW-CFD Solver", figsize=(10, 6)) + plt.title(f'1D Convection Equation at t = {solver.T:.3f} using {iorder}{ordinalENO}-order ENO and {solver.rk}{ordinalRK}-order Runge-Kutta methods') + for i in range(0, n): + lable = 'Numerical (Rusanov)ENO' + str(iorder) + ' T='+str(dt_list[i]) + style = styles[i % num_styles] + plt.plot(xcc, u_list[i], marker=style['marker'], markerfacecolor='none', linestyle=style['linestyle'], color=style['color'], \ + markersize=5, linewidth=1.0, alpha=1.0, label=f'{lable}') + plt.plot(xcc, u_analytical, 'r--', label='Analytical') + plt.xlabel('x') + plt.ylabel('u') + plt.legend() + plt.grid(True, color='gray', linestyle='--', linewidth=0.5, alpha=0.7) + plt.tight_layout() + plt.show() + +def RunEno(solver, mesh, iorder): + eno = Eno(solver, mesh, iorder) + init_coef(eno.iorder, eno.coef) + init_field(eno) + + simu_time = solver.T + t = 0.0 + dt = solver.dt + while t < simu_time: + runge_kutta(eno) + if t + dt > simu_time: + dt = simu_time - t + t += dt + #print(f'T={t:.3f},runge_kutta{solver.rk},ENO{eno.iorder},{fluxnames[solver.iflux]} FLUX') + #visualize(eno) + return np.copy(eno.u[eno.ist:eno.ied+1]) + +def performEnoOrderAnalysis(): + iorder_max = 7 + mesh = Mesh() + solver = Solver() + #计算理论解 + u_analytical = analytical_solution(mesh.xcc, solver.T, solver.c, mesh.L) + + u_list = [] + for iorder in range(1, iorder_max+1): + u = RunEno(solver, mesh, iorder) + u_list.append(u) + + plot_eno_OrderAnalysis(solver, mesh.xcc, u_list, u_analytical) + +def performEnoTimestepAnalysis(): + mesh = Mesh() + solver = Solver() + #计算理论解 + u_analytical = analytical_solution(mesh.xcc, solver.T, solver.c, mesh.L) + + u_list = [] + dt_list = [] + solver.dt = 0.025/4 + #solver.dt = 0.025/16 + n = 12 + solver.rk = 3 + iorder = 2 + for i in range(0, n): + u = RunEno(solver, mesh, iorder) + u_list.append(u) + dt_list.append(solver.dt) + print(f'i={i+1},N={n},T={solver.T:.3f},dt={solver.dt},nt={int(solver.T/solver.dt)},runge_kutta{solver.rk},ENO{iorder},{fluxnames[solver.iflux]} FLUX') + solver.dt /= 2 + + plot_eno_TimestepAnalysis(solver, mesh.xcc, u_list, u_analytical, dt_list, iorder) + +def main(): + #performEnoOrderAnalysis() + performEnoTimestepAnalysis() + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/example/1d-linear-convection/eno/rusanov/timestep/rk3-eno/eno2/01/plot.py b/example/1d-linear-convection/eno/rusanov/timestep/rk3-eno/eno2/01/plot.py new file mode 100644 index 00000000..e389044c --- /dev/null +++ b/example/1d-linear-convection/eno/rusanov/timestep/rk3-eno/eno2/01/plot.py @@ -0,0 +1,53 @@ +import numpy as np +import matplotlib.pyplot as plt +import csv +import sys + +nvar = len(sys.argv) +print('nvar=',nvar) +print('sys.argv=',sys.argv) + +order = 1 +if nvar >= 2: + var = sys.argv[1] + print('var=',var) + order = int(var) + +print('order=',order) + +x_list = [] +u_list = [] + +with open('solution.plt', newline='') as csvfile: + #readCSV = csv.reader(csvfile, delimiter= ' ') + icount = 0 + for line in csvfile: + # 去除首尾空格,按连续空格分割 + row = line.strip().split() + #print("row=",row) + x_list.append(row[0]) + u_list.append(row[1]) + icount += 1 + +ni = icount +print("ni=",ni) + +#print("x_list=",x_list) + +x = np.zeros( ni ) +u = np.zeros( ni ) + +for i in range(0, ni): + x[i] = float(x_list[i]) + u[i] = float(u_list[i]) + +labelname = 'Eno' + str(order) + +plt.figure("OneFLOW-CFD Solver", figsize=(8, 6), dpi=100) +plt.plot(x, u, "b-", linewidth=1.0, marker = 's', markerfacecolor='None', label=labelname) +plt.xlabel("$x$") +plt.ylabel("$u$") +plt.title("burgers T=1") +plt.legend() +plt.tight_layout() +plt.show(); \ No newline at end of file diff --git a/example/1d-linear-convection/eno/rusanov/timestep/rk3-eno/eno3/01/eno.py b/example/1d-linear-convection/eno/rusanov/timestep/rk3-eno/eno3/01/eno.py new file mode 100644 index 00000000..35978a85 --- /dev/null +++ b/example/1d-linear-convection/eno/rusanov/timestep/rk3-eno/eno3/01/eno.py @@ -0,0 +1,426 @@ +import numpy as np +import matplotlib.pyplot as plt + +# 初始条件 +def initial_condition(x): + u0 = np.zeros_like(x) + for i in range(len(x)): + if 0.5 <= x[i] <= 1.0: + u0[i] = 2.0 + else: + u0[i] = 1.0 + return u0 + +# 理论解 +def analytical_solution(x, t, a, L): + # 初始条件沿 x - at 平移 + x_shifted = x - a * t + return initial_condition((x_shifted + L) % L) # 周期边界条件 + +def residual(q, eno): + reconstruction(q, eno) + inviscid_flux(eno.up1_2m, eno.up1_2p, eno.flux, eno) + for i in range(eno.nx): + eno.res[i] = -(eno.flux[i + 1] - eno.flux[i]) / eno.mesh.dx + +def reconstruction(q, eno): + # Choose the stencil by ENO method + eno.dd[0, 0:eno.ntcell-1] = q[0:eno.ntcell-1] + + for m in range(1, eno.iorder): + for j in range(0, eno.ntcell-1): + eno.dd[m, j] = eno.dd[m-1, j+1] - eno.dd[m-1, j] + + for i in range(eno.nx + 1): + eno.il[i] = i - 1 + for m in range(1, eno.iorder): + if abs(eno.dd[m, eno.il[i]-1+eno.ishift]) <= abs(eno.dd[m, eno.il[i]+eno.ishift]): + eno.il[i] -= 1 + + for i in range(eno.nx + 1): + eno.ir[i] = i + for m in range(1, eno.iorder): + if abs(eno.dd[m, eno.ir[i]-1+eno.ishift]) <= abs(eno.dd[m, eno.ir[i]+eno.ishift]): + eno.ir[i] -= 1 + + # Reconstruction u(j+1/2) + for i in range(eno.nx + 1): + k1 = eno.il[i] + k2 = eno.ir[i] + l1 = i - k1 + l2 = i - k2 + eno.up1_2m[i] = 0 + eno.up1_2p[i] = 0 + for m in range(eno.iorder): + eno.up1_2m[i] += q[k1 + eno.ishift + m] * eno.coef[l1, m] + eno.up1_2p[i] += q[k2 + eno.ishift + m] * eno.coef[l2, m] + +fluxnames = [ + 'Rusanov', + 'Engquist-Osher', +] + +def inviscid_flux(up1_2m, up1_2p, flux, eno): + if eno.solver.iflux == 0: + rusanov_flux(up1_2m, up1_2p, flux, eno) + else: + engquist_osher_flux(up1_2m, up1_2p, flux, eno) + +def engquist_osher_flux(up1_2m, up1_2p, flux, eno): + for i in range(eno.nx + 1): + u_L = up1_2m[i] + u_R = up1_2p[i] + + cp = 0.5 * ( eno.solver.c + abs(eno.solver.c) ) + cm = 0.5 * ( eno.solver.c - abs(eno.solver.c) ) + + flux[i] = cp * u_L + cm * u_R + +def rusanov_flux(up1_2m, up1_2p, flux, eno): + for i in range(eno.nx + 1): + u_L = up1_2m[i] + u_R = up1_2p[i] + F_L = eno.solver.c * u_L # 左状态通量 + F_R = eno.solver.c * u_R # 右状态通量 + alpha = abs(eno.solver.c) # 最大波速 + flux[i] = 0.5 * (F_L + F_R) - 0.5 * alpha * (u_R - u_L) + + +def boundary(u, eno): + for i in range(-eno.ighost, 1): + u[eno.ist - 1 + i] = u[eno.ied + i] + for i in range(1, eno.ighost + 2): + u[eno.ied + i] = u[eno.ist - 1 + i] + +def update_oldfield(qn, q): + qn[:] = q[:] + +def init_coef( iorder, coef ): + if iorder == 1: + coef[0] = [1.0] + coef[1] = [1.0] + elif iorder == 2: + coef[0] = [3.0/2.0, -1.0/2.0] + coef[1] = [1.0/2.0, 1.0/2.0] + coef[2] = [-1.0/2.0, 3.0/2.0] + elif iorder == 3: + coef[0] = [ 11.0/6.0, -7.0/6.0, 1.0/3.0 ] + coef[1] = [ 1.0/3.0, 5.0/6.0, -1.0/6.0 ] + coef[2] = [ -1.0/6.0, 5.0/6.0, 1.0/3.0 ] + coef[3] = [ 1.0/3.0, -7.0/6.0, 11.0/6.0 ] + elif iorder == 4: + coef[0] = [ 25.0/12.0, -23.0/12.0, 13.0/12.0, -1.0/4.0 ] + coef[1] = [ 1.0/4.0, 13.0/12.0, -5.0/12.0, 1.0/12.0 ] + coef[2] = [ -1.0/12.0, 7.0/12.0, 7.0/12.0, -1.0/12.0 ] + coef[3] = [ 1.0/12.0, -5.0/12.0, 13.0/12.0, 1.0/4.0 ] + coef[4] = [ -1.0/4.0, 13.0/12.0, -23.0/12.0, 25.0/12.0 ] + elif iorder == 5: + coef[0] = [ 137.0/60.0, -163.0/60.0, 137.0/60.0, -21.0/20.0, 1.0/5.0 ] + coef[1] = [ 1.0/5.0, 77.0/60.0, -43.0/60.0, 17.0/60.0, -1.0/20.0 ] + coef[2] = [ -1.0/20.0, 9.0/20.0, 47.0/60.0, -13.0/60.0, 1.0/30.0 ] + coef[3] = [ 1.0/30.0, -13.0/60.0, 47.0/60.0, 9.0/20.0, -1.0/20.0 ] + coef[4] = [ -1.0/20.0, 17.0/60.0, -43.0/60.0, 77.0/60.0, 1.0/5.0 ] + coef[5] = [ 1.0/5.0, -21.0/20.0, 137.0/60.0, -163.0/60.0, 137.0/60.0 ] + elif iorder == 6: + coef[0] = [ 49.0/20.0, -71.0/20.0, 79.0/20.0, -163.0/60.0, 31.0/30.0, -1.0/6.0 ] + coef[1] = [ 1.0/6.0, 29.0/20.0, -21.0/20.0, 37.0/60.0, -13.0/60.0, 1.0/30.0 ] + coef[2] = [ -1.0/30.0, 11.0/30.0, 19.0/20.0, -23.0/60.0, 7.0/60.0, -1.0/60.0 ] + coef[3] = [ 1.0/60.0, -2.0/15.0, 37.0/60.0, 37.0/60.0, -2.0/15.0, 1.0/60.0 ] + coef[4] = [ -1.0/60.0, 7.0/60.0, -23.0/60.0, 19.0/20.0, 11.0/30.0, -1.0/30.0 ] + coef[5] = [ 1.0/30.0, -13.0/60.0, 37.0/60.0, -21.0/20.0, 29.0/20.0, 1.0/6.0 ] + coef[6] = [ -1.0/6.0, 31.0/30.0, -163.0/60.0, 79.0/20.0, -71.0/20.0, 49.0/20.0 ] + elif iorder == 7: + coef[0] = [ 363.0/140.0, -617.0/140.0, 853.0/140.0, -2341.0/420.0, 667.0/210.0, -43.0/42.0, 1.0/7.0 ] + coef[1] = [ 1.0/7.0, 223.0/140.0, -197.0/140.0, 153.0/140.0, -241.0/420.0, 37.0/210.0, -1.0/42.0 ] + coef[2] = [ -1.0/42.0, 13.0/42.0, 153.0/140.0, -241.0/420.0, 109.0/420.0, -31.0/420.0, 1.0/105.0 ] + coef[3] = [ 1.0/105.0, -19.0/210.0, 107.0/210.0, 319.0/420.0, -101.0/420.0, 5.0/84.0, -1.0/140.0 ] + coef[4] = [ -1.0/140.0, 5.0/84.0, -101.0/420.0, 319.0/420.0, 107.0/210.0, -19.0/210.0, 1.0/105.0 ] + coef[5] = [ 1.0/105.0, -31.0/420.0, 109.0/420.0, -241.0/420.0, 153.0/140.0, 13.0/42.0, -1.0/42.0 ] + coef[6] = [ -1.0/42.0, 37.0/210.0, -241.0/420.0, 153.0/140.0, -197.0/140.0, 223.0/140.0, 1.0/7.0 ] + coef[7] = [ 1.0/7.0, -43.0/42.0, 667.0/210.0, -2341.0/420.0, 853.0/140.0, -617.0/140.0, 363.0/140.0 ] + +def init_field(eno): + for i in range(eno.ist, eno.ied + 1): + j = i - eno.ist + if 0.5 <= eno.mesh.xcc[j] <= 1.0: + eno.u[i] = 2.0 + else: + eno.u[i] = 1.0 + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def runge_kutta(eno): + rk = eno.solver.rk + if rk == 1: + runge_kutta_1(eno) + elif rk == 2: + runge_kutta_2(eno) + else: + runge_kutta_3(eno) + +def runge_kutta_1(eno): + dt = eno.solver.dt + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = eno.u[j] + dt * eno.res[i] + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def runge_kutta_2(eno): + dt = eno.solver.dt + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = eno.u[j] + dt * eno.res[i] + boundary(eno.u, eno) + + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = 0.5 * eno.un[j] + 0.5 * eno.u[j] + 0.5 * dt * eno.res[i] + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def runge_kutta_3(eno): + dt = eno.solver.dt + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = eno.u[j] + dt * eno.res[i] + boundary(eno.u, eno) + + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = 0.75 * eno.un[j] + 0.25 * eno.u[j] + 0.25 * dt * eno.res[i] + boundary(eno.u, eno) + + residual(eno.u, eno) + c1, c2, c3 = 1.0/3.0, 2.0/3.0, 2.0/3.0 + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = c1 * eno.un[j] + c2 * eno.u[j] + c3 * dt * eno.res[i] + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def get_ordinal_numbers(order): + if order == 1: + return 'st' + elif order == 2: + return 'nd' + elif order == 3: + return 'rd' + else: + return 'th' + +def visualize(eno): + with open('solution.plt', 'w') as f: + for i in range(eno.ist, eno.ied + 1): + j = i - eno.ist + f.write(f"{eno.xcc[j]:20.10e}{eno.u[i]:20.10e}\n") + + # 可视化 + u_numerical = np.copy(eno.u[eno.ist:eno.ied+1]) + print(f'u_numerical.size={u_numerical.size}') + print(f'eno.xcc.size={eno.xcc.size}') + #计算理论解 + u_analytical = analytical_solution(eno.mesh.xcc, eno.T, eno.c, eno.L) + print(f'u_analytical.size={u_analytical.size}') + plt.figure("OneFLOW-CFD Solver", figsize=(10, 6)) + plt.scatter(eno.xcc, u_numerical, facecolor="none", edgecolor="blue", s=20, linewidths=0.5, label=f'Numerical (Rusanov)') + plt.plot(eno.xcc, u_analytical, 'r--', label='Analytical') + plt.xlabel('x') + plt.ylabel('u') + ordinal1 = get_ordinal_numbers(eno.iorder) + ordinal2 = get_ordinal_numbers(eno.rk) + plt.title(f'1D Convection Equation at t = {eno.T:.3f} using {eno.iorder}{ordinal1}-order ENO and {eno.rk}{ordinal2}-order Runge-Kutta methods') + plt.legend() + plt.grid(True, color='gray', linestyle='--', linewidth=0.5, alpha=0.7) + plt.tight_layout() + plt.show() + +class Mesh: + def __init__(self): + self.nx = 40 + self.L = 2.0 + self.x = np.zeros(self.nx + 1) + self.xcc = np.zeros(self.nx) + self.init_mesh() + def init_mesh(self): + xstart = 0.0 + xend = self.L + self.dx = (xend - xstart) / self.nx + + for i in range(0, self.nx+1): + self.x[i] = xstart + i * self.dx + + for i in range(0, self.nx): + self.xcc[i] = 0.5 * (self.x[i] + self.x[i + 1]) + +class Solver: + def __init__(self): + self.iflux = 0 + self.rk = 1 + self.c = 1.0 + self.T = 0.625 + self.dt = .0025 + +class Eno: + def __init__(self, solver, mesh, iorder): + self.solver = solver + self.mesh = mesh + self.nx = mesh.nx + self.iorder = iorder + self.ighost = iorder + self.ishift = self.ighost + 1 + self.ist = 0 + self.ishift + self.ied = self.nx - 1 + self.ishift + self.ntcell = self.nx + 2 * self.ishift + self.isize = iorder * (iorder + 1) + + self.il = np.zeros(self.nx + 1, dtype=int) + self.ir = np.zeros(self.nx + 1, dtype=int) + self.coef = np.zeros((iorder + 1, iorder)) + self.dd = np.zeros((iorder, self.ntcell)) + self.up1_2m = np.zeros(self.nx + 1) + self.up1_2p = np.zeros(self.nx + 1) + self.flux = np.zeros(self.nx + 1) + self.res = np.zeros(self.nx) + + # Field module variables + self.u = np.zeros(self.ntcell) + self.un = np.zeros(self.ntcell) + + #self.dt = .0025 + +def plot_eno_OrderAnalysis(solver, xcc, u_list, u_analytical): + # 定义一个包含不同颜色、线形和标记的列表 + styles = [ + {'color': 'black', 'linestyle': '-', 'marker': 'o'}, + {'color': 'blue', 'linestyle': '--', 'marker': 's'}, + {'color': 'black', 'linestyle': '-', 'marker': '^'}, + {'color': 'blue', 'linestyle': '--', 'marker': 'v'}, + {'color': 'black', 'linestyle': '-', 'marker': '<'}, + {'color': 'blue', 'linestyle': '--', 'marker': '>'}, + {'color': 'black', 'linestyle': '-', 'marker': 'D'}, + ] + + n = len(u_list) + num_styles = len(styles) + ordinal = get_ordinal_numbers(solver.rk) + + plt.figure("OneFLOW-CFD Solver", figsize=(10, 6)) + plt.title(f'1D Convection Equation at t = {solver.T:.3f} using [1-7]th-order ENO and {solver.rk}{ordinal}-order Runge-Kutta methods') + for i in range(0, n): + lable = 'Numerical (Rusanov)ENO' + str(i+1) + style = styles[i % num_styles] + plt.plot(xcc, u_list[i], marker=style['marker'], markerfacecolor='none', linestyle=style['linestyle'], color=style['color'], \ + markersize=5, linewidth=0.5, alpha=1.0, label=f'{lable}') + plt.plot(xcc, u_analytical, 'r--', label='Analytical') + plt.xlabel('x') + plt.ylabel('u') + plt.legend() + plt.grid(True, color='gray', linestyle='--', linewidth=0.5, alpha=0.7) + plt.tight_layout() + plt.show() + +def plot_eno_TimestepAnalysis(solver, xcc, u_list, u_analytical, dt_list, iorder): + # 定义一个包含不同颜色、线形和标记的列表 + styles = [ + {'color': 'black', 'linestyle': '-', 'marker': 'o'}, + {'color': 'blue', 'linestyle': '--', 'marker': 's'}, + {'color': 'black', 'linestyle': '-', 'marker': '^'}, + {'color': 'blue', 'linestyle': '--', 'marker': 'v'}, + {'color': 'black', 'linestyle': '-', 'marker': '<'}, + {'color': 'blue', 'linestyle': '--', 'marker': '>'}, + {'color': 'black', 'linestyle': '-', 'marker': 'D'}, + {'color': 'blue', 'linestyle': '--', 'marker': 'o'}, + {'color': 'black', 'linestyle': '-', 'marker': 's'}, + {'color': 'blue', 'linestyle': '--', 'marker': '^'}, + {'color': 'black', 'linestyle': '-', 'marker': 'v'}, + {'color': 'blue', 'linestyle': '--', 'marker': '<'}, + {'color': 'black', 'linestyle': '-', 'marker': '>'}, + {'color': 'blue', 'linestyle': '--', 'marker': 'D'}, + ] + + n = len(u_list) + num_styles = len(styles) + + ordinalENO = get_ordinal_numbers(iorder) + ordinalRK = get_ordinal_numbers(solver.rk) + + plt.figure("OneFLOW-CFD Solver", figsize=(10, 6)) + plt.title(f'1D Convection Equation at t = {solver.T:.3f} using {iorder}{ordinalENO}-order ENO and {solver.rk}{ordinalRK}-order Runge-Kutta methods') + for i in range(0, n): + lable = 'Numerical (Rusanov)ENO' + str(iorder) + ' T='+str(dt_list[i]) + style = styles[i % num_styles] + plt.plot(xcc, u_list[i], marker=style['marker'], markerfacecolor='none', linestyle=style['linestyle'], color=style['color'], \ + markersize=5, linewidth=1.0, alpha=1.0, label=f'{lable}') + plt.plot(xcc, u_analytical, 'r--', label='Analytical') + plt.xlabel('x') + plt.ylabel('u') + plt.legend() + plt.grid(True, color='gray', linestyle='--', linewidth=0.5, alpha=0.7) + plt.tight_layout() + plt.show() + +def RunEno(solver, mesh, iorder): + eno = Eno(solver, mesh, iorder) + init_coef(eno.iorder, eno.coef) + init_field(eno) + + simu_time = solver.T + t = 0.0 + dt = solver.dt + while t < simu_time: + runge_kutta(eno) + if t + dt > simu_time: + dt = simu_time - t + t += dt + #print(f'T={t:.3f},runge_kutta{solver.rk},ENO{eno.iorder},{fluxnames[solver.iflux]} FLUX') + #visualize(eno) + return np.copy(eno.u[eno.ist:eno.ied+1]) + +def performEnoOrderAnalysis(): + iorder_max = 7 + mesh = Mesh() + solver = Solver() + #计算理论解 + u_analytical = analytical_solution(mesh.xcc, solver.T, solver.c, mesh.L) + + u_list = [] + for iorder in range(1, iorder_max+1): + u = RunEno(solver, mesh, iorder) + u_list.append(u) + + plot_eno_OrderAnalysis(solver, mesh.xcc, u_list, u_analytical) + +def performEnoTimestepAnalysis(): + mesh = Mesh() + solver = Solver() + #计算理论解 + u_analytical = analytical_solution(mesh.xcc, solver.T, solver.c, mesh.L) + + u_list = [] + dt_list = [] + solver.dt = 0.025/4 + #solver.dt = 0.025/16 + n = 12 + solver.rk = 3 + iorder = 3 + for i in range(0, n): + u = RunEno(solver, mesh, iorder) + u_list.append(u) + dt_list.append(solver.dt) + print(f'i={i+1},N={n},T={solver.T:.3f},dt={solver.dt},nt={int(solver.T/solver.dt)},runge_kutta{solver.rk},ENO{iorder},{fluxnames[solver.iflux]} FLUX') + solver.dt /= 2 + + plot_eno_TimestepAnalysis(solver, mesh.xcc, u_list, u_analytical, dt_list, iorder) + +def main(): + #performEnoOrderAnalysis() + performEnoTimestepAnalysis() + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/example/1d-linear-convection/eno/rusanov/timestep/rk3-eno/eno3/01/plot.py b/example/1d-linear-convection/eno/rusanov/timestep/rk3-eno/eno3/01/plot.py new file mode 100644 index 00000000..e389044c --- /dev/null +++ b/example/1d-linear-convection/eno/rusanov/timestep/rk3-eno/eno3/01/plot.py @@ -0,0 +1,53 @@ +import numpy as np +import matplotlib.pyplot as plt +import csv +import sys + +nvar = len(sys.argv) +print('nvar=',nvar) +print('sys.argv=',sys.argv) + +order = 1 +if nvar >= 2: + var = sys.argv[1] + print('var=',var) + order = int(var) + +print('order=',order) + +x_list = [] +u_list = [] + +with open('solution.plt', newline='') as csvfile: + #readCSV = csv.reader(csvfile, delimiter= ' ') + icount = 0 + for line in csvfile: + # 去除首尾空格,按连续空格分割 + row = line.strip().split() + #print("row=",row) + x_list.append(row[0]) + u_list.append(row[1]) + icount += 1 + +ni = icount +print("ni=",ni) + +#print("x_list=",x_list) + +x = np.zeros( ni ) +u = np.zeros( ni ) + +for i in range(0, ni): + x[i] = float(x_list[i]) + u[i] = float(u_list[i]) + +labelname = 'Eno' + str(order) + +plt.figure("OneFLOW-CFD Solver", figsize=(8, 6), dpi=100) +plt.plot(x, u, "b-", linewidth=1.0, marker = 's', markerfacecolor='None', label=labelname) +plt.xlabel("$x$") +plt.ylabel("$u$") +plt.title("burgers T=1") +plt.legend() +plt.tight_layout() +plt.show(); \ No newline at end of file diff --git a/example/1d-linear-convection/eno/rusanov/timestep/rk3-eno/eno4/01/eno.py b/example/1d-linear-convection/eno/rusanov/timestep/rk3-eno/eno4/01/eno.py new file mode 100644 index 00000000..e5c28ebd --- /dev/null +++ b/example/1d-linear-convection/eno/rusanov/timestep/rk3-eno/eno4/01/eno.py @@ -0,0 +1,426 @@ +import numpy as np +import matplotlib.pyplot as plt + +# 初始条件 +def initial_condition(x): + u0 = np.zeros_like(x) + for i in range(len(x)): + if 0.5 <= x[i] <= 1.0: + u0[i] = 2.0 + else: + u0[i] = 1.0 + return u0 + +# 理论解 +def analytical_solution(x, t, a, L): + # 初始条件沿 x - at 平移 + x_shifted = x - a * t + return initial_condition((x_shifted + L) % L) # 周期边界条件 + +def residual(q, eno): + reconstruction(q, eno) + inviscid_flux(eno.up1_2m, eno.up1_2p, eno.flux, eno) + for i in range(eno.nx): + eno.res[i] = -(eno.flux[i + 1] - eno.flux[i]) / eno.mesh.dx + +def reconstruction(q, eno): + # Choose the stencil by ENO method + eno.dd[0, 0:eno.ntcell-1] = q[0:eno.ntcell-1] + + for m in range(1, eno.iorder): + for j in range(0, eno.ntcell-1): + eno.dd[m, j] = eno.dd[m-1, j+1] - eno.dd[m-1, j] + + for i in range(eno.nx + 1): + eno.il[i] = i - 1 + for m in range(1, eno.iorder): + if abs(eno.dd[m, eno.il[i]-1+eno.ishift]) <= abs(eno.dd[m, eno.il[i]+eno.ishift]): + eno.il[i] -= 1 + + for i in range(eno.nx + 1): + eno.ir[i] = i + for m in range(1, eno.iorder): + if abs(eno.dd[m, eno.ir[i]-1+eno.ishift]) <= abs(eno.dd[m, eno.ir[i]+eno.ishift]): + eno.ir[i] -= 1 + + # Reconstruction u(j+1/2) + for i in range(eno.nx + 1): + k1 = eno.il[i] + k2 = eno.ir[i] + l1 = i - k1 + l2 = i - k2 + eno.up1_2m[i] = 0 + eno.up1_2p[i] = 0 + for m in range(eno.iorder): + eno.up1_2m[i] += q[k1 + eno.ishift + m] * eno.coef[l1, m] + eno.up1_2p[i] += q[k2 + eno.ishift + m] * eno.coef[l2, m] + +fluxnames = [ + 'Rusanov', + 'Engquist-Osher', +] + +def inviscid_flux(up1_2m, up1_2p, flux, eno): + if eno.solver.iflux == 0: + rusanov_flux(up1_2m, up1_2p, flux, eno) + else: + engquist_osher_flux(up1_2m, up1_2p, flux, eno) + +def engquist_osher_flux(up1_2m, up1_2p, flux, eno): + for i in range(eno.nx + 1): + u_L = up1_2m[i] + u_R = up1_2p[i] + + cp = 0.5 * ( eno.solver.c + abs(eno.solver.c) ) + cm = 0.5 * ( eno.solver.c - abs(eno.solver.c) ) + + flux[i] = cp * u_L + cm * u_R + +def rusanov_flux(up1_2m, up1_2p, flux, eno): + for i in range(eno.nx + 1): + u_L = up1_2m[i] + u_R = up1_2p[i] + F_L = eno.solver.c * u_L # 左状态通量 + F_R = eno.solver.c * u_R # 右状态通量 + alpha = abs(eno.solver.c) # 最大波速 + flux[i] = 0.5 * (F_L + F_R) - 0.5 * alpha * (u_R - u_L) + + +def boundary(u, eno): + for i in range(-eno.ighost, 1): + u[eno.ist - 1 + i] = u[eno.ied + i] + for i in range(1, eno.ighost + 2): + u[eno.ied + i] = u[eno.ist - 1 + i] + +def update_oldfield(qn, q): + qn[:] = q[:] + +def init_coef( iorder, coef ): + if iorder == 1: + coef[0] = [1.0] + coef[1] = [1.0] + elif iorder == 2: + coef[0] = [3.0/2.0, -1.0/2.0] + coef[1] = [1.0/2.0, 1.0/2.0] + coef[2] = [-1.0/2.0, 3.0/2.0] + elif iorder == 3: + coef[0] = [ 11.0/6.0, -7.0/6.0, 1.0/3.0 ] + coef[1] = [ 1.0/3.0, 5.0/6.0, -1.0/6.0 ] + coef[2] = [ -1.0/6.0, 5.0/6.0, 1.0/3.0 ] + coef[3] = [ 1.0/3.0, -7.0/6.0, 11.0/6.0 ] + elif iorder == 4: + coef[0] = [ 25.0/12.0, -23.0/12.0, 13.0/12.0, -1.0/4.0 ] + coef[1] = [ 1.0/4.0, 13.0/12.0, -5.0/12.0, 1.0/12.0 ] + coef[2] = [ -1.0/12.0, 7.0/12.0, 7.0/12.0, -1.0/12.0 ] + coef[3] = [ 1.0/12.0, -5.0/12.0, 13.0/12.0, 1.0/4.0 ] + coef[4] = [ -1.0/4.0, 13.0/12.0, -23.0/12.0, 25.0/12.0 ] + elif iorder == 5: + coef[0] = [ 137.0/60.0, -163.0/60.0, 137.0/60.0, -21.0/20.0, 1.0/5.0 ] + coef[1] = [ 1.0/5.0, 77.0/60.0, -43.0/60.0, 17.0/60.0, -1.0/20.0 ] + coef[2] = [ -1.0/20.0, 9.0/20.0, 47.0/60.0, -13.0/60.0, 1.0/30.0 ] + coef[3] = [ 1.0/30.0, -13.0/60.0, 47.0/60.0, 9.0/20.0, -1.0/20.0 ] + coef[4] = [ -1.0/20.0, 17.0/60.0, -43.0/60.0, 77.0/60.0, 1.0/5.0 ] + coef[5] = [ 1.0/5.0, -21.0/20.0, 137.0/60.0, -163.0/60.0, 137.0/60.0 ] + elif iorder == 6: + coef[0] = [ 49.0/20.0, -71.0/20.0, 79.0/20.0, -163.0/60.0, 31.0/30.0, -1.0/6.0 ] + coef[1] = [ 1.0/6.0, 29.0/20.0, -21.0/20.0, 37.0/60.0, -13.0/60.0, 1.0/30.0 ] + coef[2] = [ -1.0/30.0, 11.0/30.0, 19.0/20.0, -23.0/60.0, 7.0/60.0, -1.0/60.0 ] + coef[3] = [ 1.0/60.0, -2.0/15.0, 37.0/60.0, 37.0/60.0, -2.0/15.0, 1.0/60.0 ] + coef[4] = [ -1.0/60.0, 7.0/60.0, -23.0/60.0, 19.0/20.0, 11.0/30.0, -1.0/30.0 ] + coef[5] = [ 1.0/30.0, -13.0/60.0, 37.0/60.0, -21.0/20.0, 29.0/20.0, 1.0/6.0 ] + coef[6] = [ -1.0/6.0, 31.0/30.0, -163.0/60.0, 79.0/20.0, -71.0/20.0, 49.0/20.0 ] + elif iorder == 7: + coef[0] = [ 363.0/140.0, -617.0/140.0, 853.0/140.0, -2341.0/420.0, 667.0/210.0, -43.0/42.0, 1.0/7.0 ] + coef[1] = [ 1.0/7.0, 223.0/140.0, -197.0/140.0, 153.0/140.0, -241.0/420.0, 37.0/210.0, -1.0/42.0 ] + coef[2] = [ -1.0/42.0, 13.0/42.0, 153.0/140.0, -241.0/420.0, 109.0/420.0, -31.0/420.0, 1.0/105.0 ] + coef[3] = [ 1.0/105.0, -19.0/210.0, 107.0/210.0, 319.0/420.0, -101.0/420.0, 5.0/84.0, -1.0/140.0 ] + coef[4] = [ -1.0/140.0, 5.0/84.0, -101.0/420.0, 319.0/420.0, 107.0/210.0, -19.0/210.0, 1.0/105.0 ] + coef[5] = [ 1.0/105.0, -31.0/420.0, 109.0/420.0, -241.0/420.0, 153.0/140.0, 13.0/42.0, -1.0/42.0 ] + coef[6] = [ -1.0/42.0, 37.0/210.0, -241.0/420.0, 153.0/140.0, -197.0/140.0, 223.0/140.0, 1.0/7.0 ] + coef[7] = [ 1.0/7.0, -43.0/42.0, 667.0/210.0, -2341.0/420.0, 853.0/140.0, -617.0/140.0, 363.0/140.0 ] + +def init_field(eno): + for i in range(eno.ist, eno.ied + 1): + j = i - eno.ist + if 0.5 <= eno.mesh.xcc[j] <= 1.0: + eno.u[i] = 2.0 + else: + eno.u[i] = 1.0 + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def runge_kutta(eno): + rk = eno.solver.rk + if rk == 1: + runge_kutta_1(eno) + elif rk == 2: + runge_kutta_2(eno) + else: + runge_kutta_3(eno) + +def runge_kutta_1(eno): + dt = eno.solver.dt + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = eno.u[j] + dt * eno.res[i] + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def runge_kutta_2(eno): + dt = eno.solver.dt + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = eno.u[j] + dt * eno.res[i] + boundary(eno.u, eno) + + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = 0.5 * eno.un[j] + 0.5 * eno.u[j] + 0.5 * dt * eno.res[i] + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def runge_kutta_3(eno): + dt = eno.solver.dt + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = eno.u[j] + dt * eno.res[i] + boundary(eno.u, eno) + + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = 0.75 * eno.un[j] + 0.25 * eno.u[j] + 0.25 * dt * eno.res[i] + boundary(eno.u, eno) + + residual(eno.u, eno) + c1, c2, c3 = 1.0/3.0, 2.0/3.0, 2.0/3.0 + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = c1 * eno.un[j] + c2 * eno.u[j] + c3 * dt * eno.res[i] + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def get_ordinal_numbers(order): + if order == 1: + return 'st' + elif order == 2: + return 'nd' + elif order == 3: + return 'rd' + else: + return 'th' + +def visualize(eno): + with open('solution.plt', 'w') as f: + for i in range(eno.ist, eno.ied + 1): + j = i - eno.ist + f.write(f"{eno.xcc[j]:20.10e}{eno.u[i]:20.10e}\n") + + # 可视化 + u_numerical = np.copy(eno.u[eno.ist:eno.ied+1]) + print(f'u_numerical.size={u_numerical.size}') + print(f'eno.xcc.size={eno.xcc.size}') + #计算理论解 + u_analytical = analytical_solution(eno.mesh.xcc, eno.T, eno.c, eno.L) + print(f'u_analytical.size={u_analytical.size}') + plt.figure("OneFLOW-CFD Solver", figsize=(10, 6)) + plt.scatter(eno.xcc, u_numerical, facecolor="none", edgecolor="blue", s=20, linewidths=0.5, label=f'Numerical (Rusanov)') + plt.plot(eno.xcc, u_analytical, 'r--', label='Analytical') + plt.xlabel('x') + plt.ylabel('u') + ordinal1 = get_ordinal_numbers(eno.iorder) + ordinal2 = get_ordinal_numbers(eno.rk) + plt.title(f'1D Convection Equation at t = {eno.T:.3f} using {eno.iorder}{ordinal1}-order ENO and {eno.rk}{ordinal2}-order Runge-Kutta methods') + plt.legend() + plt.grid(True, color='gray', linestyle='--', linewidth=0.5, alpha=0.7) + plt.tight_layout() + plt.show() + +class Mesh: + def __init__(self): + self.nx = 40 + self.L = 2.0 + self.x = np.zeros(self.nx + 1) + self.xcc = np.zeros(self.nx) + self.init_mesh() + def init_mesh(self): + xstart = 0.0 + xend = self.L + self.dx = (xend - xstart) / self.nx + + for i in range(0, self.nx+1): + self.x[i] = xstart + i * self.dx + + for i in range(0, self.nx): + self.xcc[i] = 0.5 * (self.x[i] + self.x[i + 1]) + +class Solver: + def __init__(self): + self.iflux = 0 + self.rk = 1 + self.c = 1.0 + self.T = 0.625 + self.dt = .0025 + +class Eno: + def __init__(self, solver, mesh, iorder): + self.solver = solver + self.mesh = mesh + self.nx = mesh.nx + self.iorder = iorder + self.ighost = iorder + self.ishift = self.ighost + 1 + self.ist = 0 + self.ishift + self.ied = self.nx - 1 + self.ishift + self.ntcell = self.nx + 2 * self.ishift + self.isize = iorder * (iorder + 1) + + self.il = np.zeros(self.nx + 1, dtype=int) + self.ir = np.zeros(self.nx + 1, dtype=int) + self.coef = np.zeros((iorder + 1, iorder)) + self.dd = np.zeros((iorder, self.ntcell)) + self.up1_2m = np.zeros(self.nx + 1) + self.up1_2p = np.zeros(self.nx + 1) + self.flux = np.zeros(self.nx + 1) + self.res = np.zeros(self.nx) + + # Field module variables + self.u = np.zeros(self.ntcell) + self.un = np.zeros(self.ntcell) + + #self.dt = .0025 + +def plot_eno_OrderAnalysis(solver, xcc, u_list, u_analytical): + # 定义一个包含不同颜色、线形和标记的列表 + styles = [ + {'color': 'black', 'linestyle': '-', 'marker': 'o'}, + {'color': 'blue', 'linestyle': '--', 'marker': 's'}, + {'color': 'black', 'linestyle': '-', 'marker': '^'}, + {'color': 'blue', 'linestyle': '--', 'marker': 'v'}, + {'color': 'black', 'linestyle': '-', 'marker': '<'}, + {'color': 'blue', 'linestyle': '--', 'marker': '>'}, + {'color': 'black', 'linestyle': '-', 'marker': 'D'}, + ] + + n = len(u_list) + num_styles = len(styles) + ordinal = get_ordinal_numbers(solver.rk) + + plt.figure("OneFLOW-CFD Solver", figsize=(10, 6)) + plt.title(f'1D Convection Equation at t = {solver.T:.3f} using [1-7]th-order ENO and {solver.rk}{ordinal}-order Runge-Kutta methods') + for i in range(0, n): + lable = 'Numerical (Rusanov)ENO' + str(i+1) + style = styles[i % num_styles] + plt.plot(xcc, u_list[i], marker=style['marker'], markerfacecolor='none', linestyle=style['linestyle'], color=style['color'], \ + markersize=5, linewidth=0.5, alpha=1.0, label=f'{lable}') + plt.plot(xcc, u_analytical, 'r--', label='Analytical') + plt.xlabel('x') + plt.ylabel('u') + plt.legend() + plt.grid(True, color='gray', linestyle='--', linewidth=0.5, alpha=0.7) + plt.tight_layout() + plt.show() + +def plot_eno_TimestepAnalysis(solver, xcc, u_list, u_analytical, dt_list, iorder): + # 定义一个包含不同颜色、线形和标记的列表 + styles = [ + {'color': 'black', 'linestyle': '-', 'marker': 'o'}, + {'color': 'blue', 'linestyle': '--', 'marker': 's'}, + {'color': 'black', 'linestyle': '-', 'marker': '^'}, + {'color': 'blue', 'linestyle': '--', 'marker': 'v'}, + {'color': 'black', 'linestyle': '-', 'marker': '<'}, + {'color': 'blue', 'linestyle': '--', 'marker': '>'}, + {'color': 'black', 'linestyle': '-', 'marker': 'D'}, + {'color': 'blue', 'linestyle': '--', 'marker': 'o'}, + {'color': 'black', 'linestyle': '-', 'marker': 's'}, + {'color': 'blue', 'linestyle': '--', 'marker': '^'}, + {'color': 'black', 'linestyle': '-', 'marker': 'v'}, + {'color': 'blue', 'linestyle': '--', 'marker': '<'}, + {'color': 'black', 'linestyle': '-', 'marker': '>'}, + {'color': 'blue', 'linestyle': '--', 'marker': 'D'}, + ] + + n = len(u_list) + num_styles = len(styles) + + ordinalENO = get_ordinal_numbers(iorder) + ordinalRK = get_ordinal_numbers(solver.rk) + + plt.figure("OneFLOW-CFD Solver", figsize=(10, 6)) + plt.title(f'1D Convection Equation at t = {solver.T:.3f} using {iorder}{ordinalENO}-order ENO and {solver.rk}{ordinalRK}-order Runge-Kutta methods') + for i in range(0, n): + lable = 'Numerical (Rusanov)ENO' + str(iorder) + ' T='+str(dt_list[i]) + style = styles[i % num_styles] + plt.plot(xcc, u_list[i], marker=style['marker'], markerfacecolor='none', linestyle=style['linestyle'], color=style['color'], \ + markersize=5, linewidth=1.0, alpha=1.0, label=f'{lable}') + plt.plot(xcc, u_analytical, 'r--', label='Analytical') + plt.xlabel('x') + plt.ylabel('u') + plt.legend() + plt.grid(True, color='gray', linestyle='--', linewidth=0.5, alpha=0.7) + plt.tight_layout() + plt.show() + +def RunEno(solver, mesh, iorder): + eno = Eno(solver, mesh, iorder) + init_coef(eno.iorder, eno.coef) + init_field(eno) + + simu_time = solver.T + t = 0.0 + dt = solver.dt + while t < simu_time: + runge_kutta(eno) + if t + dt > simu_time: + dt = simu_time - t + t += dt + #print(f'T={t:.3f},runge_kutta{solver.rk},ENO{eno.iorder},{fluxnames[solver.iflux]} FLUX') + #visualize(eno) + return np.copy(eno.u[eno.ist:eno.ied+1]) + +def performEnoOrderAnalysis(): + iorder_max = 7 + mesh = Mesh() + solver = Solver() + #计算理论解 + u_analytical = analytical_solution(mesh.xcc, solver.T, solver.c, mesh.L) + + u_list = [] + for iorder in range(1, iorder_max+1): + u = RunEno(solver, mesh, iorder) + u_list.append(u) + + plot_eno_OrderAnalysis(solver, mesh.xcc, u_list, u_analytical) + +def performEnoTimestepAnalysis(): + mesh = Mesh() + solver = Solver() + #计算理论解 + u_analytical = analytical_solution(mesh.xcc, solver.T, solver.c, mesh.L) + + u_list = [] + dt_list = [] + solver.dt = 0.025/4 + #solver.dt = 0.025/16 + n = 12 + solver.rk = 3 + iorder = 4 + for i in range(0, n): + u = RunEno(solver, mesh, iorder) + u_list.append(u) + dt_list.append(solver.dt) + print(f'i={i+1},N={n},T={solver.T:.3f},dt={solver.dt},nt={int(solver.T/solver.dt)},runge_kutta{solver.rk},ENO{iorder},{fluxnames[solver.iflux]} FLUX') + solver.dt /= 2 + + plot_eno_TimestepAnalysis(solver, mesh.xcc, u_list, u_analytical, dt_list, iorder) + +def main(): + #performEnoOrderAnalysis() + performEnoTimestepAnalysis() + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/example/1d-linear-convection/eno/rusanov/timestep/rk3-eno/eno4/01/plot.py b/example/1d-linear-convection/eno/rusanov/timestep/rk3-eno/eno4/01/plot.py new file mode 100644 index 00000000..e389044c --- /dev/null +++ b/example/1d-linear-convection/eno/rusanov/timestep/rk3-eno/eno4/01/plot.py @@ -0,0 +1,53 @@ +import numpy as np +import matplotlib.pyplot as plt +import csv +import sys + +nvar = len(sys.argv) +print('nvar=',nvar) +print('sys.argv=',sys.argv) + +order = 1 +if nvar >= 2: + var = sys.argv[1] + print('var=',var) + order = int(var) + +print('order=',order) + +x_list = [] +u_list = [] + +with open('solution.plt', newline='') as csvfile: + #readCSV = csv.reader(csvfile, delimiter= ' ') + icount = 0 + for line in csvfile: + # 去除首尾空格,按连续空格分割 + row = line.strip().split() + #print("row=",row) + x_list.append(row[0]) + u_list.append(row[1]) + icount += 1 + +ni = icount +print("ni=",ni) + +#print("x_list=",x_list) + +x = np.zeros( ni ) +u = np.zeros( ni ) + +for i in range(0, ni): + x[i] = float(x_list[i]) + u[i] = float(u_list[i]) + +labelname = 'Eno' + str(order) + +plt.figure("OneFLOW-CFD Solver", figsize=(8, 6), dpi=100) +plt.plot(x, u, "b-", linewidth=1.0, marker = 's', markerfacecolor='None', label=labelname) +plt.xlabel("$x$") +plt.ylabel("$u$") +plt.title("burgers T=1") +plt.legend() +plt.tight_layout() +plt.show(); \ No newline at end of file diff --git a/example/1d-linear-convection/eno/rusanov/timestep/rk3-eno/eno5/01/eno.py b/example/1d-linear-convection/eno/rusanov/timestep/rk3-eno/eno5/01/eno.py new file mode 100644 index 00000000..f6c2d3eb --- /dev/null +++ b/example/1d-linear-convection/eno/rusanov/timestep/rk3-eno/eno5/01/eno.py @@ -0,0 +1,426 @@ +import numpy as np +import matplotlib.pyplot as plt + +# 初始条件 +def initial_condition(x): + u0 = np.zeros_like(x) + for i in range(len(x)): + if 0.5 <= x[i] <= 1.0: + u0[i] = 2.0 + else: + u0[i] = 1.0 + return u0 + +# 理论解 +def analytical_solution(x, t, a, L): + # 初始条件沿 x - at 平移 + x_shifted = x - a * t + return initial_condition((x_shifted + L) % L) # 周期边界条件 + +def residual(q, eno): + reconstruction(q, eno) + inviscid_flux(eno.up1_2m, eno.up1_2p, eno.flux, eno) + for i in range(eno.nx): + eno.res[i] = -(eno.flux[i + 1] - eno.flux[i]) / eno.mesh.dx + +def reconstruction(q, eno): + # Choose the stencil by ENO method + eno.dd[0, 0:eno.ntcell-1] = q[0:eno.ntcell-1] + + for m in range(1, eno.iorder): + for j in range(0, eno.ntcell-1): + eno.dd[m, j] = eno.dd[m-1, j+1] - eno.dd[m-1, j] + + for i in range(eno.nx + 1): + eno.il[i] = i - 1 + for m in range(1, eno.iorder): + if abs(eno.dd[m, eno.il[i]-1+eno.ishift]) <= abs(eno.dd[m, eno.il[i]+eno.ishift]): + eno.il[i] -= 1 + + for i in range(eno.nx + 1): + eno.ir[i] = i + for m in range(1, eno.iorder): + if abs(eno.dd[m, eno.ir[i]-1+eno.ishift]) <= abs(eno.dd[m, eno.ir[i]+eno.ishift]): + eno.ir[i] -= 1 + + # Reconstruction u(j+1/2) + for i in range(eno.nx + 1): + k1 = eno.il[i] + k2 = eno.ir[i] + l1 = i - k1 + l2 = i - k2 + eno.up1_2m[i] = 0 + eno.up1_2p[i] = 0 + for m in range(eno.iorder): + eno.up1_2m[i] += q[k1 + eno.ishift + m] * eno.coef[l1, m] + eno.up1_2p[i] += q[k2 + eno.ishift + m] * eno.coef[l2, m] + +fluxnames = [ + 'Rusanov', + 'Engquist-Osher', +] + +def inviscid_flux(up1_2m, up1_2p, flux, eno): + if eno.solver.iflux == 0: + rusanov_flux(up1_2m, up1_2p, flux, eno) + else: + engquist_osher_flux(up1_2m, up1_2p, flux, eno) + +def engquist_osher_flux(up1_2m, up1_2p, flux, eno): + for i in range(eno.nx + 1): + u_L = up1_2m[i] + u_R = up1_2p[i] + + cp = 0.5 * ( eno.solver.c + abs(eno.solver.c) ) + cm = 0.5 * ( eno.solver.c - abs(eno.solver.c) ) + + flux[i] = cp * u_L + cm * u_R + +def rusanov_flux(up1_2m, up1_2p, flux, eno): + for i in range(eno.nx + 1): + u_L = up1_2m[i] + u_R = up1_2p[i] + F_L = eno.solver.c * u_L # 左状态通量 + F_R = eno.solver.c * u_R # 右状态通量 + alpha = abs(eno.solver.c) # 最大波速 + flux[i] = 0.5 * (F_L + F_R) - 0.5 * alpha * (u_R - u_L) + + +def boundary(u, eno): + for i in range(-eno.ighost, 1): + u[eno.ist - 1 + i] = u[eno.ied + i] + for i in range(1, eno.ighost + 2): + u[eno.ied + i] = u[eno.ist - 1 + i] + +def update_oldfield(qn, q): + qn[:] = q[:] + +def init_coef( iorder, coef ): + if iorder == 1: + coef[0] = [1.0] + coef[1] = [1.0] + elif iorder == 2: + coef[0] = [3.0/2.0, -1.0/2.0] + coef[1] = [1.0/2.0, 1.0/2.0] + coef[2] = [-1.0/2.0, 3.0/2.0] + elif iorder == 3: + coef[0] = [ 11.0/6.0, -7.0/6.0, 1.0/3.0 ] + coef[1] = [ 1.0/3.0, 5.0/6.0, -1.0/6.0 ] + coef[2] = [ -1.0/6.0, 5.0/6.0, 1.0/3.0 ] + coef[3] = [ 1.0/3.0, -7.0/6.0, 11.0/6.0 ] + elif iorder == 4: + coef[0] = [ 25.0/12.0, -23.0/12.0, 13.0/12.0, -1.0/4.0 ] + coef[1] = [ 1.0/4.0, 13.0/12.0, -5.0/12.0, 1.0/12.0 ] + coef[2] = [ -1.0/12.0, 7.0/12.0, 7.0/12.0, -1.0/12.0 ] + coef[3] = [ 1.0/12.0, -5.0/12.0, 13.0/12.0, 1.0/4.0 ] + coef[4] = [ -1.0/4.0, 13.0/12.0, -23.0/12.0, 25.0/12.0 ] + elif iorder == 5: + coef[0] = [ 137.0/60.0, -163.0/60.0, 137.0/60.0, -21.0/20.0, 1.0/5.0 ] + coef[1] = [ 1.0/5.0, 77.0/60.0, -43.0/60.0, 17.0/60.0, -1.0/20.0 ] + coef[2] = [ -1.0/20.0, 9.0/20.0, 47.0/60.0, -13.0/60.0, 1.0/30.0 ] + coef[3] = [ 1.0/30.0, -13.0/60.0, 47.0/60.0, 9.0/20.0, -1.0/20.0 ] + coef[4] = [ -1.0/20.0, 17.0/60.0, -43.0/60.0, 77.0/60.0, 1.0/5.0 ] + coef[5] = [ 1.0/5.0, -21.0/20.0, 137.0/60.0, -163.0/60.0, 137.0/60.0 ] + elif iorder == 6: + coef[0] = [ 49.0/20.0, -71.0/20.0, 79.0/20.0, -163.0/60.0, 31.0/30.0, -1.0/6.0 ] + coef[1] = [ 1.0/6.0, 29.0/20.0, -21.0/20.0, 37.0/60.0, -13.0/60.0, 1.0/30.0 ] + coef[2] = [ -1.0/30.0, 11.0/30.0, 19.0/20.0, -23.0/60.0, 7.0/60.0, -1.0/60.0 ] + coef[3] = [ 1.0/60.0, -2.0/15.0, 37.0/60.0, 37.0/60.0, -2.0/15.0, 1.0/60.0 ] + coef[4] = [ -1.0/60.0, 7.0/60.0, -23.0/60.0, 19.0/20.0, 11.0/30.0, -1.0/30.0 ] + coef[5] = [ 1.0/30.0, -13.0/60.0, 37.0/60.0, -21.0/20.0, 29.0/20.0, 1.0/6.0 ] + coef[6] = [ -1.0/6.0, 31.0/30.0, -163.0/60.0, 79.0/20.0, -71.0/20.0, 49.0/20.0 ] + elif iorder == 7: + coef[0] = [ 363.0/140.0, -617.0/140.0, 853.0/140.0, -2341.0/420.0, 667.0/210.0, -43.0/42.0, 1.0/7.0 ] + coef[1] = [ 1.0/7.0, 223.0/140.0, -197.0/140.0, 153.0/140.0, -241.0/420.0, 37.0/210.0, -1.0/42.0 ] + coef[2] = [ -1.0/42.0, 13.0/42.0, 153.0/140.0, -241.0/420.0, 109.0/420.0, -31.0/420.0, 1.0/105.0 ] + coef[3] = [ 1.0/105.0, -19.0/210.0, 107.0/210.0, 319.0/420.0, -101.0/420.0, 5.0/84.0, -1.0/140.0 ] + coef[4] = [ -1.0/140.0, 5.0/84.0, -101.0/420.0, 319.0/420.0, 107.0/210.0, -19.0/210.0, 1.0/105.0 ] + coef[5] = [ 1.0/105.0, -31.0/420.0, 109.0/420.0, -241.0/420.0, 153.0/140.0, 13.0/42.0, -1.0/42.0 ] + coef[6] = [ -1.0/42.0, 37.0/210.0, -241.0/420.0, 153.0/140.0, -197.0/140.0, 223.0/140.0, 1.0/7.0 ] + coef[7] = [ 1.0/7.0, -43.0/42.0, 667.0/210.0, -2341.0/420.0, 853.0/140.0, -617.0/140.0, 363.0/140.0 ] + +def init_field(eno): + for i in range(eno.ist, eno.ied + 1): + j = i - eno.ist + if 0.5 <= eno.mesh.xcc[j] <= 1.0: + eno.u[i] = 2.0 + else: + eno.u[i] = 1.0 + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def runge_kutta(eno): + rk = eno.solver.rk + if rk == 1: + runge_kutta_1(eno) + elif rk == 2: + runge_kutta_2(eno) + else: + runge_kutta_3(eno) + +def runge_kutta_1(eno): + dt = eno.solver.dt + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = eno.u[j] + dt * eno.res[i] + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def runge_kutta_2(eno): + dt = eno.solver.dt + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = eno.u[j] + dt * eno.res[i] + boundary(eno.u, eno) + + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = 0.5 * eno.un[j] + 0.5 * eno.u[j] + 0.5 * dt * eno.res[i] + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def runge_kutta_3(eno): + dt = eno.solver.dt + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = eno.u[j] + dt * eno.res[i] + boundary(eno.u, eno) + + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = 0.75 * eno.un[j] + 0.25 * eno.u[j] + 0.25 * dt * eno.res[i] + boundary(eno.u, eno) + + residual(eno.u, eno) + c1, c2, c3 = 1.0/3.0, 2.0/3.0, 2.0/3.0 + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = c1 * eno.un[j] + c2 * eno.u[j] + c3 * dt * eno.res[i] + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def get_ordinal_numbers(order): + if order == 1: + return 'st' + elif order == 2: + return 'nd' + elif order == 3: + return 'rd' + else: + return 'th' + +def visualize(eno): + with open('solution.plt', 'w') as f: + for i in range(eno.ist, eno.ied + 1): + j = i - eno.ist + f.write(f"{eno.xcc[j]:20.10e}{eno.u[i]:20.10e}\n") + + # 可视化 + u_numerical = np.copy(eno.u[eno.ist:eno.ied+1]) + print(f'u_numerical.size={u_numerical.size}') + print(f'eno.xcc.size={eno.xcc.size}') + #计算理论解 + u_analytical = analytical_solution(eno.mesh.xcc, eno.T, eno.c, eno.L) + print(f'u_analytical.size={u_analytical.size}') + plt.figure("OneFLOW-CFD Solver", figsize=(10, 6)) + plt.scatter(eno.xcc, u_numerical, facecolor="none", edgecolor="blue", s=20, linewidths=0.5, label=f'Numerical (Rusanov)') + plt.plot(eno.xcc, u_analytical, 'r--', label='Analytical') + plt.xlabel('x') + plt.ylabel('u') + ordinal1 = get_ordinal_numbers(eno.iorder) + ordinal2 = get_ordinal_numbers(eno.rk) + plt.title(f'1D Convection Equation at t = {eno.T:.3f} using {eno.iorder}{ordinal1}-order ENO and {eno.rk}{ordinal2}-order Runge-Kutta methods') + plt.legend() + plt.grid(True, color='gray', linestyle='--', linewidth=0.5, alpha=0.7) + plt.tight_layout() + plt.show() + +class Mesh: + def __init__(self): + self.nx = 40 + self.L = 2.0 + self.x = np.zeros(self.nx + 1) + self.xcc = np.zeros(self.nx) + self.init_mesh() + def init_mesh(self): + xstart = 0.0 + xend = self.L + self.dx = (xend - xstart) / self.nx + + for i in range(0, self.nx+1): + self.x[i] = xstart + i * self.dx + + for i in range(0, self.nx): + self.xcc[i] = 0.5 * (self.x[i] + self.x[i + 1]) + +class Solver: + def __init__(self): + self.iflux = 0 + self.rk = 1 + self.c = 1.0 + self.T = 0.625 + self.dt = .0025 + +class Eno: + def __init__(self, solver, mesh, iorder): + self.solver = solver + self.mesh = mesh + self.nx = mesh.nx + self.iorder = iorder + self.ighost = iorder + self.ishift = self.ighost + 1 + self.ist = 0 + self.ishift + self.ied = self.nx - 1 + self.ishift + self.ntcell = self.nx + 2 * self.ishift + self.isize = iorder * (iorder + 1) + + self.il = np.zeros(self.nx + 1, dtype=int) + self.ir = np.zeros(self.nx + 1, dtype=int) + self.coef = np.zeros((iorder + 1, iorder)) + self.dd = np.zeros((iorder, self.ntcell)) + self.up1_2m = np.zeros(self.nx + 1) + self.up1_2p = np.zeros(self.nx + 1) + self.flux = np.zeros(self.nx + 1) + self.res = np.zeros(self.nx) + + # Field module variables + self.u = np.zeros(self.ntcell) + self.un = np.zeros(self.ntcell) + + #self.dt = .0025 + +def plot_eno_OrderAnalysis(solver, xcc, u_list, u_analytical): + # 定义一个包含不同颜色、线形和标记的列表 + styles = [ + {'color': 'black', 'linestyle': '-', 'marker': 'o'}, + {'color': 'blue', 'linestyle': '--', 'marker': 's'}, + {'color': 'black', 'linestyle': '-', 'marker': '^'}, + {'color': 'blue', 'linestyle': '--', 'marker': 'v'}, + {'color': 'black', 'linestyle': '-', 'marker': '<'}, + {'color': 'blue', 'linestyle': '--', 'marker': '>'}, + {'color': 'black', 'linestyle': '-', 'marker': 'D'}, + ] + + n = len(u_list) + num_styles = len(styles) + ordinal = get_ordinal_numbers(solver.rk) + + plt.figure("OneFLOW-CFD Solver", figsize=(10, 6)) + plt.title(f'1D Convection Equation at t = {solver.T:.3f} using [1-7]th-order ENO and {solver.rk}{ordinal}-order Runge-Kutta methods') + for i in range(0, n): + lable = 'Numerical (Rusanov)ENO' + str(i+1) + style = styles[i % num_styles] + plt.plot(xcc, u_list[i], marker=style['marker'], markerfacecolor='none', linestyle=style['linestyle'], color=style['color'], \ + markersize=5, linewidth=0.5, alpha=1.0, label=f'{lable}') + plt.plot(xcc, u_analytical, 'r--', label='Analytical') + plt.xlabel('x') + plt.ylabel('u') + plt.legend() + plt.grid(True, color='gray', linestyle='--', linewidth=0.5, alpha=0.7) + plt.tight_layout() + plt.show() + +def plot_eno_TimestepAnalysis(solver, xcc, u_list, u_analytical, dt_list, iorder): + # 定义一个包含不同颜色、线形和标记的列表 + styles = [ + {'color': 'black', 'linestyle': '-', 'marker': 'o'}, + {'color': 'blue', 'linestyle': '--', 'marker': 's'}, + {'color': 'black', 'linestyle': '-', 'marker': '^'}, + {'color': 'blue', 'linestyle': '--', 'marker': 'v'}, + {'color': 'black', 'linestyle': '-', 'marker': '<'}, + {'color': 'blue', 'linestyle': '--', 'marker': '>'}, + {'color': 'black', 'linestyle': '-', 'marker': 'D'}, + {'color': 'blue', 'linestyle': '--', 'marker': 'o'}, + {'color': 'black', 'linestyle': '-', 'marker': 's'}, + {'color': 'blue', 'linestyle': '--', 'marker': '^'}, + {'color': 'black', 'linestyle': '-', 'marker': 'v'}, + {'color': 'blue', 'linestyle': '--', 'marker': '<'}, + {'color': 'black', 'linestyle': '-', 'marker': '>'}, + {'color': 'blue', 'linestyle': '--', 'marker': 'D'}, + ] + + n = len(u_list) + num_styles = len(styles) + + ordinalENO = get_ordinal_numbers(iorder) + ordinalRK = get_ordinal_numbers(solver.rk) + + plt.figure("OneFLOW-CFD Solver", figsize=(10, 6)) + plt.title(f'1D Convection Equation at t = {solver.T:.3f} using {iorder}{ordinalENO}-order ENO and {solver.rk}{ordinalRK}-order Runge-Kutta methods') + for i in range(0, n): + lable = 'Numerical (Rusanov)ENO' + str(iorder) + ' T='+str(dt_list[i]) + style = styles[i % num_styles] + plt.plot(xcc, u_list[i], marker=style['marker'], markerfacecolor='none', linestyle=style['linestyle'], color=style['color'], \ + markersize=5, linewidth=1.0, alpha=1.0, label=f'{lable}') + plt.plot(xcc, u_analytical, 'r--', label='Analytical') + plt.xlabel('x') + plt.ylabel('u') + plt.legend() + plt.grid(True, color='gray', linestyle='--', linewidth=0.5, alpha=0.7) + plt.tight_layout() + plt.show() + +def RunEno(solver, mesh, iorder): + eno = Eno(solver, mesh, iorder) + init_coef(eno.iorder, eno.coef) + init_field(eno) + + simu_time = solver.T + t = 0.0 + dt = solver.dt + while t < simu_time: + runge_kutta(eno) + if t + dt > simu_time: + dt = simu_time - t + t += dt + #print(f'T={t:.3f},runge_kutta{solver.rk},ENO{eno.iorder},{fluxnames[solver.iflux]} FLUX') + #visualize(eno) + return np.copy(eno.u[eno.ist:eno.ied+1]) + +def performEnoOrderAnalysis(): + iorder_max = 7 + mesh = Mesh() + solver = Solver() + #计算理论解 + u_analytical = analytical_solution(mesh.xcc, solver.T, solver.c, mesh.L) + + u_list = [] + for iorder in range(1, iorder_max+1): + u = RunEno(solver, mesh, iorder) + u_list.append(u) + + plot_eno_OrderAnalysis(solver, mesh.xcc, u_list, u_analytical) + +def performEnoTimestepAnalysis(): + mesh = Mesh() + solver = Solver() + #计算理论解 + u_analytical = analytical_solution(mesh.xcc, solver.T, solver.c, mesh.L) + + u_list = [] + dt_list = [] + solver.dt = 0.025/4 + #solver.dt = 0.025/16 + n = 12 + solver.rk = 3 + iorder = 5 + for i in range(0, n): + u = RunEno(solver, mesh, iorder) + u_list.append(u) + dt_list.append(solver.dt) + print(f'i={i+1},N={n},T={solver.T:.3f},dt={solver.dt},nt={int(solver.T/solver.dt)},runge_kutta{solver.rk},ENO{iorder},{fluxnames[solver.iflux]} FLUX') + solver.dt /= 2 + + plot_eno_TimestepAnalysis(solver, mesh.xcc, u_list, u_analytical, dt_list, iorder) + +def main(): + #performEnoOrderAnalysis() + performEnoTimestepAnalysis() + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/example/1d-linear-convection/eno/rusanov/timestep/rk3-eno/eno5/01/plot.py b/example/1d-linear-convection/eno/rusanov/timestep/rk3-eno/eno5/01/plot.py new file mode 100644 index 00000000..e389044c --- /dev/null +++ b/example/1d-linear-convection/eno/rusanov/timestep/rk3-eno/eno5/01/plot.py @@ -0,0 +1,53 @@ +import numpy as np +import matplotlib.pyplot as plt +import csv +import sys + +nvar = len(sys.argv) +print('nvar=',nvar) +print('sys.argv=',sys.argv) + +order = 1 +if nvar >= 2: + var = sys.argv[1] + print('var=',var) + order = int(var) + +print('order=',order) + +x_list = [] +u_list = [] + +with open('solution.plt', newline='') as csvfile: + #readCSV = csv.reader(csvfile, delimiter= ' ') + icount = 0 + for line in csvfile: + # 去除首尾空格,按连续空格分割 + row = line.strip().split() + #print("row=",row) + x_list.append(row[0]) + u_list.append(row[1]) + icount += 1 + +ni = icount +print("ni=",ni) + +#print("x_list=",x_list) + +x = np.zeros( ni ) +u = np.zeros( ni ) + +for i in range(0, ni): + x[i] = float(x_list[i]) + u[i] = float(u_list[i]) + +labelname = 'Eno' + str(order) + +plt.figure("OneFLOW-CFD Solver", figsize=(8, 6), dpi=100) +plt.plot(x, u, "b-", linewidth=1.0, marker = 's', markerfacecolor='None', label=labelname) +plt.xlabel("$x$") +plt.ylabel("$u$") +plt.title("burgers T=1") +plt.legend() +plt.tight_layout() +plt.show(); \ No newline at end of file diff --git a/example/1d-linear-convection/eno/rusanov/timestep/rk3-eno/eno6/01/eno.py b/example/1d-linear-convection/eno/rusanov/timestep/rk3-eno/eno6/01/eno.py new file mode 100644 index 00000000..939256fb --- /dev/null +++ b/example/1d-linear-convection/eno/rusanov/timestep/rk3-eno/eno6/01/eno.py @@ -0,0 +1,426 @@ +import numpy as np +import matplotlib.pyplot as plt + +# 初始条件 +def initial_condition(x): + u0 = np.zeros_like(x) + for i in range(len(x)): + if 0.5 <= x[i] <= 1.0: + u0[i] = 2.0 + else: + u0[i] = 1.0 + return u0 + +# 理论解 +def analytical_solution(x, t, a, L): + # 初始条件沿 x - at 平移 + x_shifted = x - a * t + return initial_condition((x_shifted + L) % L) # 周期边界条件 + +def residual(q, eno): + reconstruction(q, eno) + inviscid_flux(eno.up1_2m, eno.up1_2p, eno.flux, eno) + for i in range(eno.nx): + eno.res[i] = -(eno.flux[i + 1] - eno.flux[i]) / eno.mesh.dx + +def reconstruction(q, eno): + # Choose the stencil by ENO method + eno.dd[0, 0:eno.ntcell-1] = q[0:eno.ntcell-1] + + for m in range(1, eno.iorder): + for j in range(0, eno.ntcell-1): + eno.dd[m, j] = eno.dd[m-1, j+1] - eno.dd[m-1, j] + + for i in range(eno.nx + 1): + eno.il[i] = i - 1 + for m in range(1, eno.iorder): + if abs(eno.dd[m, eno.il[i]-1+eno.ishift]) <= abs(eno.dd[m, eno.il[i]+eno.ishift]): + eno.il[i] -= 1 + + for i in range(eno.nx + 1): + eno.ir[i] = i + for m in range(1, eno.iorder): + if abs(eno.dd[m, eno.ir[i]-1+eno.ishift]) <= abs(eno.dd[m, eno.ir[i]+eno.ishift]): + eno.ir[i] -= 1 + + # Reconstruction u(j+1/2) + for i in range(eno.nx + 1): + k1 = eno.il[i] + k2 = eno.ir[i] + l1 = i - k1 + l2 = i - k2 + eno.up1_2m[i] = 0 + eno.up1_2p[i] = 0 + for m in range(eno.iorder): + eno.up1_2m[i] += q[k1 + eno.ishift + m] * eno.coef[l1, m] + eno.up1_2p[i] += q[k2 + eno.ishift + m] * eno.coef[l2, m] + +fluxnames = [ + 'Rusanov', + 'Engquist-Osher', +] + +def inviscid_flux(up1_2m, up1_2p, flux, eno): + if eno.solver.iflux == 0: + rusanov_flux(up1_2m, up1_2p, flux, eno) + else: + engquist_osher_flux(up1_2m, up1_2p, flux, eno) + +def engquist_osher_flux(up1_2m, up1_2p, flux, eno): + for i in range(eno.nx + 1): + u_L = up1_2m[i] + u_R = up1_2p[i] + + cp = 0.5 * ( eno.solver.c + abs(eno.solver.c) ) + cm = 0.5 * ( eno.solver.c - abs(eno.solver.c) ) + + flux[i] = cp * u_L + cm * u_R + +def rusanov_flux(up1_2m, up1_2p, flux, eno): + for i in range(eno.nx + 1): + u_L = up1_2m[i] + u_R = up1_2p[i] + F_L = eno.solver.c * u_L # 左状态通量 + F_R = eno.solver.c * u_R # 右状态通量 + alpha = abs(eno.solver.c) # 最大波速 + flux[i] = 0.5 * (F_L + F_R) - 0.5 * alpha * (u_R - u_L) + + +def boundary(u, eno): + for i in range(-eno.ighost, 1): + u[eno.ist - 1 + i] = u[eno.ied + i] + for i in range(1, eno.ighost + 2): + u[eno.ied + i] = u[eno.ist - 1 + i] + +def update_oldfield(qn, q): + qn[:] = q[:] + +def init_coef( iorder, coef ): + if iorder == 1: + coef[0] = [1.0] + coef[1] = [1.0] + elif iorder == 2: + coef[0] = [3.0/2.0, -1.0/2.0] + coef[1] = [1.0/2.0, 1.0/2.0] + coef[2] = [-1.0/2.0, 3.0/2.0] + elif iorder == 3: + coef[0] = [ 11.0/6.0, -7.0/6.0, 1.0/3.0 ] + coef[1] = [ 1.0/3.0, 5.0/6.0, -1.0/6.0 ] + coef[2] = [ -1.0/6.0, 5.0/6.0, 1.0/3.0 ] + coef[3] = [ 1.0/3.0, -7.0/6.0, 11.0/6.0 ] + elif iorder == 4: + coef[0] = [ 25.0/12.0, -23.0/12.0, 13.0/12.0, -1.0/4.0 ] + coef[1] = [ 1.0/4.0, 13.0/12.0, -5.0/12.0, 1.0/12.0 ] + coef[2] = [ -1.0/12.0, 7.0/12.0, 7.0/12.0, -1.0/12.0 ] + coef[3] = [ 1.0/12.0, -5.0/12.0, 13.0/12.0, 1.0/4.0 ] + coef[4] = [ -1.0/4.0, 13.0/12.0, -23.0/12.0, 25.0/12.0 ] + elif iorder == 5: + coef[0] = [ 137.0/60.0, -163.0/60.0, 137.0/60.0, -21.0/20.0, 1.0/5.0 ] + coef[1] = [ 1.0/5.0, 77.0/60.0, -43.0/60.0, 17.0/60.0, -1.0/20.0 ] + coef[2] = [ -1.0/20.0, 9.0/20.0, 47.0/60.0, -13.0/60.0, 1.0/30.0 ] + coef[3] = [ 1.0/30.0, -13.0/60.0, 47.0/60.0, 9.0/20.0, -1.0/20.0 ] + coef[4] = [ -1.0/20.0, 17.0/60.0, -43.0/60.0, 77.0/60.0, 1.0/5.0 ] + coef[5] = [ 1.0/5.0, -21.0/20.0, 137.0/60.0, -163.0/60.0, 137.0/60.0 ] + elif iorder == 6: + coef[0] = [ 49.0/20.0, -71.0/20.0, 79.0/20.0, -163.0/60.0, 31.0/30.0, -1.0/6.0 ] + coef[1] = [ 1.0/6.0, 29.0/20.0, -21.0/20.0, 37.0/60.0, -13.0/60.0, 1.0/30.0 ] + coef[2] = [ -1.0/30.0, 11.0/30.0, 19.0/20.0, -23.0/60.0, 7.0/60.0, -1.0/60.0 ] + coef[3] = [ 1.0/60.0, -2.0/15.0, 37.0/60.0, 37.0/60.0, -2.0/15.0, 1.0/60.0 ] + coef[4] = [ -1.0/60.0, 7.0/60.0, -23.0/60.0, 19.0/20.0, 11.0/30.0, -1.0/30.0 ] + coef[5] = [ 1.0/30.0, -13.0/60.0, 37.0/60.0, -21.0/20.0, 29.0/20.0, 1.0/6.0 ] + coef[6] = [ -1.0/6.0, 31.0/30.0, -163.0/60.0, 79.0/20.0, -71.0/20.0, 49.0/20.0 ] + elif iorder == 7: + coef[0] = [ 363.0/140.0, -617.0/140.0, 853.0/140.0, -2341.0/420.0, 667.0/210.0, -43.0/42.0, 1.0/7.0 ] + coef[1] = [ 1.0/7.0, 223.0/140.0, -197.0/140.0, 153.0/140.0, -241.0/420.0, 37.0/210.0, -1.0/42.0 ] + coef[2] = [ -1.0/42.0, 13.0/42.0, 153.0/140.0, -241.0/420.0, 109.0/420.0, -31.0/420.0, 1.0/105.0 ] + coef[3] = [ 1.0/105.0, -19.0/210.0, 107.0/210.0, 319.0/420.0, -101.0/420.0, 5.0/84.0, -1.0/140.0 ] + coef[4] = [ -1.0/140.0, 5.0/84.0, -101.0/420.0, 319.0/420.0, 107.0/210.0, -19.0/210.0, 1.0/105.0 ] + coef[5] = [ 1.0/105.0, -31.0/420.0, 109.0/420.0, -241.0/420.0, 153.0/140.0, 13.0/42.0, -1.0/42.0 ] + coef[6] = [ -1.0/42.0, 37.0/210.0, -241.0/420.0, 153.0/140.0, -197.0/140.0, 223.0/140.0, 1.0/7.0 ] + coef[7] = [ 1.0/7.0, -43.0/42.0, 667.0/210.0, -2341.0/420.0, 853.0/140.0, -617.0/140.0, 363.0/140.0 ] + +def init_field(eno): + for i in range(eno.ist, eno.ied + 1): + j = i - eno.ist + if 0.5 <= eno.mesh.xcc[j] <= 1.0: + eno.u[i] = 2.0 + else: + eno.u[i] = 1.0 + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def runge_kutta(eno): + rk = eno.solver.rk + if rk == 1: + runge_kutta_1(eno) + elif rk == 2: + runge_kutta_2(eno) + else: + runge_kutta_3(eno) + +def runge_kutta_1(eno): + dt = eno.solver.dt + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = eno.u[j] + dt * eno.res[i] + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def runge_kutta_2(eno): + dt = eno.solver.dt + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = eno.u[j] + dt * eno.res[i] + boundary(eno.u, eno) + + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = 0.5 * eno.un[j] + 0.5 * eno.u[j] + 0.5 * dt * eno.res[i] + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def runge_kutta_3(eno): + dt = eno.solver.dt + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = eno.u[j] + dt * eno.res[i] + boundary(eno.u, eno) + + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = 0.75 * eno.un[j] + 0.25 * eno.u[j] + 0.25 * dt * eno.res[i] + boundary(eno.u, eno) + + residual(eno.u, eno) + c1, c2, c3 = 1.0/3.0, 2.0/3.0, 2.0/3.0 + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = c1 * eno.un[j] + c2 * eno.u[j] + c3 * dt * eno.res[i] + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def get_ordinal_numbers(order): + if order == 1: + return 'st' + elif order == 2: + return 'nd' + elif order == 3: + return 'rd' + else: + return 'th' + +def visualize(eno): + with open('solution.plt', 'w') as f: + for i in range(eno.ist, eno.ied + 1): + j = i - eno.ist + f.write(f"{eno.xcc[j]:20.10e}{eno.u[i]:20.10e}\n") + + # 可视化 + u_numerical = np.copy(eno.u[eno.ist:eno.ied+1]) + print(f'u_numerical.size={u_numerical.size}') + print(f'eno.xcc.size={eno.xcc.size}') + #计算理论解 + u_analytical = analytical_solution(eno.mesh.xcc, eno.T, eno.c, eno.L) + print(f'u_analytical.size={u_analytical.size}') + plt.figure("OneFLOW-CFD Solver", figsize=(10, 6)) + plt.scatter(eno.xcc, u_numerical, facecolor="none", edgecolor="blue", s=20, linewidths=0.5, label=f'Numerical (Rusanov)') + plt.plot(eno.xcc, u_analytical, 'r--', label='Analytical') + plt.xlabel('x') + plt.ylabel('u') + ordinal1 = get_ordinal_numbers(eno.iorder) + ordinal2 = get_ordinal_numbers(eno.rk) + plt.title(f'1D Convection Equation at t = {eno.T:.3f} using {eno.iorder}{ordinal1}-order ENO and {eno.rk}{ordinal2}-order Runge-Kutta methods') + plt.legend() + plt.grid(True, color='gray', linestyle='--', linewidth=0.5, alpha=0.7) + plt.tight_layout() + plt.show() + +class Mesh: + def __init__(self): + self.nx = 40 + self.L = 2.0 + self.x = np.zeros(self.nx + 1) + self.xcc = np.zeros(self.nx) + self.init_mesh() + def init_mesh(self): + xstart = 0.0 + xend = self.L + self.dx = (xend - xstart) / self.nx + + for i in range(0, self.nx+1): + self.x[i] = xstart + i * self.dx + + for i in range(0, self.nx): + self.xcc[i] = 0.5 * (self.x[i] + self.x[i + 1]) + +class Solver: + def __init__(self): + self.iflux = 0 + self.rk = 1 + self.c = 1.0 + self.T = 0.625 + self.dt = .0025 + +class Eno: + def __init__(self, solver, mesh, iorder): + self.solver = solver + self.mesh = mesh + self.nx = mesh.nx + self.iorder = iorder + self.ighost = iorder + self.ishift = self.ighost + 1 + self.ist = 0 + self.ishift + self.ied = self.nx - 1 + self.ishift + self.ntcell = self.nx + 2 * self.ishift + self.isize = iorder * (iorder + 1) + + self.il = np.zeros(self.nx + 1, dtype=int) + self.ir = np.zeros(self.nx + 1, dtype=int) + self.coef = np.zeros((iorder + 1, iorder)) + self.dd = np.zeros((iorder, self.ntcell)) + self.up1_2m = np.zeros(self.nx + 1) + self.up1_2p = np.zeros(self.nx + 1) + self.flux = np.zeros(self.nx + 1) + self.res = np.zeros(self.nx) + + # Field module variables + self.u = np.zeros(self.ntcell) + self.un = np.zeros(self.ntcell) + + #self.dt = .0025 + +def plot_eno_OrderAnalysis(solver, xcc, u_list, u_analytical): + # 定义一个包含不同颜色、线形和标记的列表 + styles = [ + {'color': 'black', 'linestyle': '-', 'marker': 'o'}, + {'color': 'blue', 'linestyle': '--', 'marker': 's'}, + {'color': 'black', 'linestyle': '-', 'marker': '^'}, + {'color': 'blue', 'linestyle': '--', 'marker': 'v'}, + {'color': 'black', 'linestyle': '-', 'marker': '<'}, + {'color': 'blue', 'linestyle': '--', 'marker': '>'}, + {'color': 'black', 'linestyle': '-', 'marker': 'D'}, + ] + + n = len(u_list) + num_styles = len(styles) + ordinal = get_ordinal_numbers(solver.rk) + + plt.figure("OneFLOW-CFD Solver", figsize=(10, 6)) + plt.title(f'1D Convection Equation at t = {solver.T:.3f} using [1-7]th-order ENO and {solver.rk}{ordinal}-order Runge-Kutta methods') + for i in range(0, n): + lable = 'Numerical (Rusanov)ENO' + str(i+1) + style = styles[i % num_styles] + plt.plot(xcc, u_list[i], marker=style['marker'], markerfacecolor='none', linestyle=style['linestyle'], color=style['color'], \ + markersize=5, linewidth=0.5, alpha=1.0, label=f'{lable}') + plt.plot(xcc, u_analytical, 'r--', label='Analytical') + plt.xlabel('x') + plt.ylabel('u') + plt.legend() + plt.grid(True, color='gray', linestyle='--', linewidth=0.5, alpha=0.7) + plt.tight_layout() + plt.show() + +def plot_eno_TimestepAnalysis(solver, xcc, u_list, u_analytical, dt_list, iorder): + # 定义一个包含不同颜色、线形和标记的列表 + styles = [ + {'color': 'black', 'linestyle': '-', 'marker': 'o'}, + {'color': 'blue', 'linestyle': '--', 'marker': 's'}, + {'color': 'black', 'linestyle': '-', 'marker': '^'}, + {'color': 'blue', 'linestyle': '--', 'marker': 'v'}, + {'color': 'black', 'linestyle': '-', 'marker': '<'}, + {'color': 'blue', 'linestyle': '--', 'marker': '>'}, + {'color': 'black', 'linestyle': '-', 'marker': 'D'}, + {'color': 'blue', 'linestyle': '--', 'marker': 'o'}, + {'color': 'black', 'linestyle': '-', 'marker': 's'}, + {'color': 'blue', 'linestyle': '--', 'marker': '^'}, + {'color': 'black', 'linestyle': '-', 'marker': 'v'}, + {'color': 'blue', 'linestyle': '--', 'marker': '<'}, + {'color': 'black', 'linestyle': '-', 'marker': '>'}, + {'color': 'blue', 'linestyle': '--', 'marker': 'D'}, + ] + + n = len(u_list) + num_styles = len(styles) + + ordinalENO = get_ordinal_numbers(iorder) + ordinalRK = get_ordinal_numbers(solver.rk) + + plt.figure("OneFLOW-CFD Solver", figsize=(10, 6)) + plt.title(f'1D Convection Equation at t = {solver.T:.3f} using {iorder}{ordinalENO}-order ENO and {solver.rk}{ordinalRK}-order Runge-Kutta methods') + for i in range(0, n): + lable = 'Numerical (Rusanov)ENO' + str(iorder) + ' T='+str(dt_list[i]) + style = styles[i % num_styles] + plt.plot(xcc, u_list[i], marker=style['marker'], markerfacecolor='none', linestyle=style['linestyle'], color=style['color'], \ + markersize=5, linewidth=1.0, alpha=1.0, label=f'{lable}') + plt.plot(xcc, u_analytical, 'r--', label='Analytical') + plt.xlabel('x') + plt.ylabel('u') + plt.legend() + plt.grid(True, color='gray', linestyle='--', linewidth=0.5, alpha=0.7) + plt.tight_layout() + plt.show() + +def RunEno(solver, mesh, iorder): + eno = Eno(solver, mesh, iorder) + init_coef(eno.iorder, eno.coef) + init_field(eno) + + simu_time = solver.T + t = 0.0 + dt = solver.dt + while t < simu_time: + runge_kutta(eno) + if t + dt > simu_time: + dt = simu_time - t + t += dt + #print(f'T={t:.3f},runge_kutta{solver.rk},ENO{eno.iorder},{fluxnames[solver.iflux]} FLUX') + #visualize(eno) + return np.copy(eno.u[eno.ist:eno.ied+1]) + +def performEnoOrderAnalysis(): + iorder_max = 7 + mesh = Mesh() + solver = Solver() + #计算理论解 + u_analytical = analytical_solution(mesh.xcc, solver.T, solver.c, mesh.L) + + u_list = [] + for iorder in range(1, iorder_max+1): + u = RunEno(solver, mesh, iorder) + u_list.append(u) + + plot_eno_OrderAnalysis(solver, mesh.xcc, u_list, u_analytical) + +def performEnoTimestepAnalysis(): + mesh = Mesh() + solver = Solver() + #计算理论解 + u_analytical = analytical_solution(mesh.xcc, solver.T, solver.c, mesh.L) + + u_list = [] + dt_list = [] + solver.dt = 0.025/4 + #solver.dt = 0.025/16 + n = 12 + solver.rk = 3 + iorder = 6 + for i in range(0, n): + u = RunEno(solver, mesh, iorder) + u_list.append(u) + dt_list.append(solver.dt) + print(f'i={i+1},N={n},T={solver.T:.3f},dt={solver.dt},nt={int(solver.T/solver.dt)},runge_kutta{solver.rk},ENO{iorder},{fluxnames[solver.iflux]} FLUX') + solver.dt /= 2 + + plot_eno_TimestepAnalysis(solver, mesh.xcc, u_list, u_analytical, dt_list, iorder) + +def main(): + #performEnoOrderAnalysis() + performEnoTimestepAnalysis() + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/example/1d-linear-convection/eno/rusanov/timestep/rk3-eno/eno6/01/plot.py b/example/1d-linear-convection/eno/rusanov/timestep/rk3-eno/eno6/01/plot.py new file mode 100644 index 00000000..e389044c --- /dev/null +++ b/example/1d-linear-convection/eno/rusanov/timestep/rk3-eno/eno6/01/plot.py @@ -0,0 +1,53 @@ +import numpy as np +import matplotlib.pyplot as plt +import csv +import sys + +nvar = len(sys.argv) +print('nvar=',nvar) +print('sys.argv=',sys.argv) + +order = 1 +if nvar >= 2: + var = sys.argv[1] + print('var=',var) + order = int(var) + +print('order=',order) + +x_list = [] +u_list = [] + +with open('solution.plt', newline='') as csvfile: + #readCSV = csv.reader(csvfile, delimiter= ' ') + icount = 0 + for line in csvfile: + # 去除首尾空格,按连续空格分割 + row = line.strip().split() + #print("row=",row) + x_list.append(row[0]) + u_list.append(row[1]) + icount += 1 + +ni = icount +print("ni=",ni) + +#print("x_list=",x_list) + +x = np.zeros( ni ) +u = np.zeros( ni ) + +for i in range(0, ni): + x[i] = float(x_list[i]) + u[i] = float(u_list[i]) + +labelname = 'Eno' + str(order) + +plt.figure("OneFLOW-CFD Solver", figsize=(8, 6), dpi=100) +plt.plot(x, u, "b-", linewidth=1.0, marker = 's', markerfacecolor='None', label=labelname) +plt.xlabel("$x$") +plt.ylabel("$u$") +plt.title("burgers T=1") +plt.legend() +plt.tight_layout() +plt.show(); \ No newline at end of file diff --git a/example/1d-linear-convection/eno/rusanov/timestep/rk3-eno/eno7/01/eno.py b/example/1d-linear-convection/eno/rusanov/timestep/rk3-eno/eno7/01/eno.py new file mode 100644 index 00000000..5e1bae50 --- /dev/null +++ b/example/1d-linear-convection/eno/rusanov/timestep/rk3-eno/eno7/01/eno.py @@ -0,0 +1,426 @@ +import numpy as np +import matplotlib.pyplot as plt + +# 初始条件 +def initial_condition(x): + u0 = np.zeros_like(x) + for i in range(len(x)): + if 0.5 <= x[i] <= 1.0: + u0[i] = 2.0 + else: + u0[i] = 1.0 + return u0 + +# 理论解 +def analytical_solution(x, t, a, L): + # 初始条件沿 x - at 平移 + x_shifted = x - a * t + return initial_condition((x_shifted + L) % L) # 周期边界条件 + +def residual(q, eno): + reconstruction(q, eno) + inviscid_flux(eno.up1_2m, eno.up1_2p, eno.flux, eno) + for i in range(eno.nx): + eno.res[i] = -(eno.flux[i + 1] - eno.flux[i]) / eno.mesh.dx + +def reconstruction(q, eno): + # Choose the stencil by ENO method + eno.dd[0, 0:eno.ntcell-1] = q[0:eno.ntcell-1] + + for m in range(1, eno.iorder): + for j in range(0, eno.ntcell-1): + eno.dd[m, j] = eno.dd[m-1, j+1] - eno.dd[m-1, j] + + for i in range(eno.nx + 1): + eno.il[i] = i - 1 + for m in range(1, eno.iorder): + if abs(eno.dd[m, eno.il[i]-1+eno.ishift]) <= abs(eno.dd[m, eno.il[i]+eno.ishift]): + eno.il[i] -= 1 + + for i in range(eno.nx + 1): + eno.ir[i] = i + for m in range(1, eno.iorder): + if abs(eno.dd[m, eno.ir[i]-1+eno.ishift]) <= abs(eno.dd[m, eno.ir[i]+eno.ishift]): + eno.ir[i] -= 1 + + # Reconstruction u(j+1/2) + for i in range(eno.nx + 1): + k1 = eno.il[i] + k2 = eno.ir[i] + l1 = i - k1 + l2 = i - k2 + eno.up1_2m[i] = 0 + eno.up1_2p[i] = 0 + for m in range(eno.iorder): + eno.up1_2m[i] += q[k1 + eno.ishift + m] * eno.coef[l1, m] + eno.up1_2p[i] += q[k2 + eno.ishift + m] * eno.coef[l2, m] + +fluxnames = [ + 'Rusanov', + 'Engquist-Osher', +] + +def inviscid_flux(up1_2m, up1_2p, flux, eno): + if eno.solver.iflux == 0: + rusanov_flux(up1_2m, up1_2p, flux, eno) + else: + engquist_osher_flux(up1_2m, up1_2p, flux, eno) + +def engquist_osher_flux(up1_2m, up1_2p, flux, eno): + for i in range(eno.nx + 1): + u_L = up1_2m[i] + u_R = up1_2p[i] + + cp = 0.5 * ( eno.solver.c + abs(eno.solver.c) ) + cm = 0.5 * ( eno.solver.c - abs(eno.solver.c) ) + + flux[i] = cp * u_L + cm * u_R + +def rusanov_flux(up1_2m, up1_2p, flux, eno): + for i in range(eno.nx + 1): + u_L = up1_2m[i] + u_R = up1_2p[i] + F_L = eno.solver.c * u_L # 左状态通量 + F_R = eno.solver.c * u_R # 右状态通量 + alpha = abs(eno.solver.c) # 最大波速 + flux[i] = 0.5 * (F_L + F_R) - 0.5 * alpha * (u_R - u_L) + + +def boundary(u, eno): + for i in range(-eno.ighost, 1): + u[eno.ist - 1 + i] = u[eno.ied + i] + for i in range(1, eno.ighost + 2): + u[eno.ied + i] = u[eno.ist - 1 + i] + +def update_oldfield(qn, q): + qn[:] = q[:] + +def init_coef( iorder, coef ): + if iorder == 1: + coef[0] = [1.0] + coef[1] = [1.0] + elif iorder == 2: + coef[0] = [3.0/2.0, -1.0/2.0] + coef[1] = [1.0/2.0, 1.0/2.0] + coef[2] = [-1.0/2.0, 3.0/2.0] + elif iorder == 3: + coef[0] = [ 11.0/6.0, -7.0/6.0, 1.0/3.0 ] + coef[1] = [ 1.0/3.0, 5.0/6.0, -1.0/6.0 ] + coef[2] = [ -1.0/6.0, 5.0/6.0, 1.0/3.0 ] + coef[3] = [ 1.0/3.0, -7.0/6.0, 11.0/6.0 ] + elif iorder == 4: + coef[0] = [ 25.0/12.0, -23.0/12.0, 13.0/12.0, -1.0/4.0 ] + coef[1] = [ 1.0/4.0, 13.0/12.0, -5.0/12.0, 1.0/12.0 ] + coef[2] = [ -1.0/12.0, 7.0/12.0, 7.0/12.0, -1.0/12.0 ] + coef[3] = [ 1.0/12.0, -5.0/12.0, 13.0/12.0, 1.0/4.0 ] + coef[4] = [ -1.0/4.0, 13.0/12.0, -23.0/12.0, 25.0/12.0 ] + elif iorder == 5: + coef[0] = [ 137.0/60.0, -163.0/60.0, 137.0/60.0, -21.0/20.0, 1.0/5.0 ] + coef[1] = [ 1.0/5.0, 77.0/60.0, -43.0/60.0, 17.0/60.0, -1.0/20.0 ] + coef[2] = [ -1.0/20.0, 9.0/20.0, 47.0/60.0, -13.0/60.0, 1.0/30.0 ] + coef[3] = [ 1.0/30.0, -13.0/60.0, 47.0/60.0, 9.0/20.0, -1.0/20.0 ] + coef[4] = [ -1.0/20.0, 17.0/60.0, -43.0/60.0, 77.0/60.0, 1.0/5.0 ] + coef[5] = [ 1.0/5.0, -21.0/20.0, 137.0/60.0, -163.0/60.0, 137.0/60.0 ] + elif iorder == 6: + coef[0] = [ 49.0/20.0, -71.0/20.0, 79.0/20.0, -163.0/60.0, 31.0/30.0, -1.0/6.0 ] + coef[1] = [ 1.0/6.0, 29.0/20.0, -21.0/20.0, 37.0/60.0, -13.0/60.0, 1.0/30.0 ] + coef[2] = [ -1.0/30.0, 11.0/30.0, 19.0/20.0, -23.0/60.0, 7.0/60.0, -1.0/60.0 ] + coef[3] = [ 1.0/60.0, -2.0/15.0, 37.0/60.0, 37.0/60.0, -2.0/15.0, 1.0/60.0 ] + coef[4] = [ -1.0/60.0, 7.0/60.0, -23.0/60.0, 19.0/20.0, 11.0/30.0, -1.0/30.0 ] + coef[5] = [ 1.0/30.0, -13.0/60.0, 37.0/60.0, -21.0/20.0, 29.0/20.0, 1.0/6.0 ] + coef[6] = [ -1.0/6.0, 31.0/30.0, -163.0/60.0, 79.0/20.0, -71.0/20.0, 49.0/20.0 ] + elif iorder == 7: + coef[0] = [ 363.0/140.0, -617.0/140.0, 853.0/140.0, -2341.0/420.0, 667.0/210.0, -43.0/42.0, 1.0/7.0 ] + coef[1] = [ 1.0/7.0, 223.0/140.0, -197.0/140.0, 153.0/140.0, -241.0/420.0, 37.0/210.0, -1.0/42.0 ] + coef[2] = [ -1.0/42.0, 13.0/42.0, 153.0/140.0, -241.0/420.0, 109.0/420.0, -31.0/420.0, 1.0/105.0 ] + coef[3] = [ 1.0/105.0, -19.0/210.0, 107.0/210.0, 319.0/420.0, -101.0/420.0, 5.0/84.0, -1.0/140.0 ] + coef[4] = [ -1.0/140.0, 5.0/84.0, -101.0/420.0, 319.0/420.0, 107.0/210.0, -19.0/210.0, 1.0/105.0 ] + coef[5] = [ 1.0/105.0, -31.0/420.0, 109.0/420.0, -241.0/420.0, 153.0/140.0, 13.0/42.0, -1.0/42.0 ] + coef[6] = [ -1.0/42.0, 37.0/210.0, -241.0/420.0, 153.0/140.0, -197.0/140.0, 223.0/140.0, 1.0/7.0 ] + coef[7] = [ 1.0/7.0, -43.0/42.0, 667.0/210.0, -2341.0/420.0, 853.0/140.0, -617.0/140.0, 363.0/140.0 ] + +def init_field(eno): + for i in range(eno.ist, eno.ied + 1): + j = i - eno.ist + if 0.5 <= eno.mesh.xcc[j] <= 1.0: + eno.u[i] = 2.0 + else: + eno.u[i] = 1.0 + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def runge_kutta(eno): + rk = eno.solver.rk + if rk == 1: + runge_kutta_1(eno) + elif rk == 2: + runge_kutta_2(eno) + else: + runge_kutta_3(eno) + +def runge_kutta_1(eno): + dt = eno.solver.dt + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = eno.u[j] + dt * eno.res[i] + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def runge_kutta_2(eno): + dt = eno.solver.dt + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = eno.u[j] + dt * eno.res[i] + boundary(eno.u, eno) + + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = 0.5 * eno.un[j] + 0.5 * eno.u[j] + 0.5 * dt * eno.res[i] + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def runge_kutta_3(eno): + dt = eno.solver.dt + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = eno.u[j] + dt * eno.res[i] + boundary(eno.u, eno) + + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = 0.75 * eno.un[j] + 0.25 * eno.u[j] + 0.25 * dt * eno.res[i] + boundary(eno.u, eno) + + residual(eno.u, eno) + c1, c2, c3 = 1.0/3.0, 2.0/3.0, 2.0/3.0 + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = c1 * eno.un[j] + c2 * eno.u[j] + c3 * dt * eno.res[i] + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def get_ordinal_numbers(order): + if order == 1: + return 'st' + elif order == 2: + return 'nd' + elif order == 3: + return 'rd' + else: + return 'th' + +def visualize(eno): + with open('solution.plt', 'w') as f: + for i in range(eno.ist, eno.ied + 1): + j = i - eno.ist + f.write(f"{eno.xcc[j]:20.10e}{eno.u[i]:20.10e}\n") + + # 可视化 + u_numerical = np.copy(eno.u[eno.ist:eno.ied+1]) + print(f'u_numerical.size={u_numerical.size}') + print(f'eno.xcc.size={eno.xcc.size}') + #计算理论解 + u_analytical = analytical_solution(eno.mesh.xcc, eno.T, eno.c, eno.L) + print(f'u_analytical.size={u_analytical.size}') + plt.figure("OneFLOW-CFD Solver", figsize=(10, 6)) + plt.scatter(eno.xcc, u_numerical, facecolor="none", edgecolor="blue", s=20, linewidths=0.5, label=f'Numerical (Rusanov)') + plt.plot(eno.xcc, u_analytical, 'r--', label='Analytical') + plt.xlabel('x') + plt.ylabel('u') + ordinal1 = get_ordinal_numbers(eno.iorder) + ordinal2 = get_ordinal_numbers(eno.rk) + plt.title(f'1D Convection Equation at t = {eno.T:.3f} using {eno.iorder}{ordinal1}-order ENO and {eno.rk}{ordinal2}-order Runge-Kutta methods') + plt.legend() + plt.grid(True, color='gray', linestyle='--', linewidth=0.5, alpha=0.7) + plt.tight_layout() + plt.show() + +class Mesh: + def __init__(self): + self.nx = 40 + self.L = 2.0 + self.x = np.zeros(self.nx + 1) + self.xcc = np.zeros(self.nx) + self.init_mesh() + def init_mesh(self): + xstart = 0.0 + xend = self.L + self.dx = (xend - xstart) / self.nx + + for i in range(0, self.nx+1): + self.x[i] = xstart + i * self.dx + + for i in range(0, self.nx): + self.xcc[i] = 0.5 * (self.x[i] + self.x[i + 1]) + +class Solver: + def __init__(self): + self.iflux = 0 + self.rk = 1 + self.c = 1.0 + self.T = 0.625 + self.dt = .0025 + +class Eno: + def __init__(self, solver, mesh, iorder): + self.solver = solver + self.mesh = mesh + self.nx = mesh.nx + self.iorder = iorder + self.ighost = iorder + self.ishift = self.ighost + 1 + self.ist = 0 + self.ishift + self.ied = self.nx - 1 + self.ishift + self.ntcell = self.nx + 2 * self.ishift + self.isize = iorder * (iorder + 1) + + self.il = np.zeros(self.nx + 1, dtype=int) + self.ir = np.zeros(self.nx + 1, dtype=int) + self.coef = np.zeros((iorder + 1, iorder)) + self.dd = np.zeros((iorder, self.ntcell)) + self.up1_2m = np.zeros(self.nx + 1) + self.up1_2p = np.zeros(self.nx + 1) + self.flux = np.zeros(self.nx + 1) + self.res = np.zeros(self.nx) + + # Field module variables + self.u = np.zeros(self.ntcell) + self.un = np.zeros(self.ntcell) + + #self.dt = .0025 + +def plot_eno_OrderAnalysis(solver, xcc, u_list, u_analytical): + # 定义一个包含不同颜色、线形和标记的列表 + styles = [ + {'color': 'black', 'linestyle': '-', 'marker': 'o'}, + {'color': 'blue', 'linestyle': '--', 'marker': 's'}, + {'color': 'black', 'linestyle': '-', 'marker': '^'}, + {'color': 'blue', 'linestyle': '--', 'marker': 'v'}, + {'color': 'black', 'linestyle': '-', 'marker': '<'}, + {'color': 'blue', 'linestyle': '--', 'marker': '>'}, + {'color': 'black', 'linestyle': '-', 'marker': 'D'}, + ] + + n = len(u_list) + num_styles = len(styles) + ordinal = get_ordinal_numbers(solver.rk) + + plt.figure("OneFLOW-CFD Solver", figsize=(10, 6)) + plt.title(f'1D Convection Equation at t = {solver.T:.3f} using [1-7]th-order ENO and {solver.rk}{ordinal}-order Runge-Kutta methods') + for i in range(0, n): + lable = 'Numerical (Rusanov)ENO' + str(i+1) + style = styles[i % num_styles] + plt.plot(xcc, u_list[i], marker=style['marker'], markerfacecolor='none', linestyle=style['linestyle'], color=style['color'], \ + markersize=5, linewidth=0.5, alpha=1.0, label=f'{lable}') + plt.plot(xcc, u_analytical, 'r--', label='Analytical') + plt.xlabel('x') + plt.ylabel('u') + plt.legend() + plt.grid(True, color='gray', linestyle='--', linewidth=0.5, alpha=0.7) + plt.tight_layout() + plt.show() + +def plot_eno_TimestepAnalysis(solver, xcc, u_list, u_analytical, dt_list, iorder): + # 定义一个包含不同颜色、线形和标记的列表 + styles = [ + {'color': 'black', 'linestyle': '-', 'marker': 'o'}, + {'color': 'blue', 'linestyle': '--', 'marker': 's'}, + {'color': 'black', 'linestyle': '-', 'marker': '^'}, + {'color': 'blue', 'linestyle': '--', 'marker': 'v'}, + {'color': 'black', 'linestyle': '-', 'marker': '<'}, + {'color': 'blue', 'linestyle': '--', 'marker': '>'}, + {'color': 'black', 'linestyle': '-', 'marker': 'D'}, + {'color': 'blue', 'linestyle': '--', 'marker': 'o'}, + {'color': 'black', 'linestyle': '-', 'marker': 's'}, + {'color': 'blue', 'linestyle': '--', 'marker': '^'}, + {'color': 'black', 'linestyle': '-', 'marker': 'v'}, + {'color': 'blue', 'linestyle': '--', 'marker': '<'}, + {'color': 'black', 'linestyle': '-', 'marker': '>'}, + {'color': 'blue', 'linestyle': '--', 'marker': 'D'}, + ] + + n = len(u_list) + num_styles = len(styles) + + ordinalENO = get_ordinal_numbers(iorder) + ordinalRK = get_ordinal_numbers(solver.rk) + + plt.figure("OneFLOW-CFD Solver", figsize=(10, 6)) + plt.title(f'1D Convection Equation at t = {solver.T:.3f} using {iorder}{ordinalENO}-order ENO and {solver.rk}{ordinalRK}-order Runge-Kutta methods') + for i in range(0, n): + lable = 'Numerical (Rusanov)ENO' + str(iorder) + ' T='+str(dt_list[i]) + style = styles[i % num_styles] + plt.plot(xcc, u_list[i], marker=style['marker'], markerfacecolor='none', linestyle=style['linestyle'], color=style['color'], \ + markersize=5, linewidth=1.0, alpha=1.0, label=f'{lable}') + plt.plot(xcc, u_analytical, 'r--', label='Analytical') + plt.xlabel('x') + plt.ylabel('u') + plt.legend() + plt.grid(True, color='gray', linestyle='--', linewidth=0.5, alpha=0.7) + plt.tight_layout() + plt.show() + +def RunEno(solver, mesh, iorder): + eno = Eno(solver, mesh, iorder) + init_coef(eno.iorder, eno.coef) + init_field(eno) + + simu_time = solver.T + t = 0.0 + dt = solver.dt + while t < simu_time: + runge_kutta(eno) + if t + dt > simu_time: + dt = simu_time - t + t += dt + #print(f'T={t:.3f},runge_kutta{solver.rk},ENO{eno.iorder},{fluxnames[solver.iflux]} FLUX') + #visualize(eno) + return np.copy(eno.u[eno.ist:eno.ied+1]) + +def performEnoOrderAnalysis(): + iorder_max = 7 + mesh = Mesh() + solver = Solver() + #计算理论解 + u_analytical = analytical_solution(mesh.xcc, solver.T, solver.c, mesh.L) + + u_list = [] + for iorder in range(1, iorder_max+1): + u = RunEno(solver, mesh, iorder) + u_list.append(u) + + plot_eno_OrderAnalysis(solver, mesh.xcc, u_list, u_analytical) + +def performEnoTimestepAnalysis(): + mesh = Mesh() + solver = Solver() + #计算理论解 + u_analytical = analytical_solution(mesh.xcc, solver.T, solver.c, mesh.L) + + u_list = [] + dt_list = [] + solver.dt = 0.025/4 + #solver.dt = 0.025/16 + n = 12 + solver.rk = 3 + iorder = 7 + for i in range(0, n): + u = RunEno(solver, mesh, iorder) + u_list.append(u) + dt_list.append(solver.dt) + print(f'i={i+1},N={n},T={solver.T:.3f},dt={solver.dt},nt={int(solver.T/solver.dt)},runge_kutta{solver.rk},ENO{iorder},{fluxnames[solver.iflux]} FLUX') + solver.dt /= 2 + + plot_eno_TimestepAnalysis(solver, mesh.xcc, u_list, u_analytical, dt_list, iorder) + +def main(): + #performEnoOrderAnalysis() + performEnoTimestepAnalysis() + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/example/1d-linear-convection/eno/rusanov/timestep/rk3-eno/eno7/01/plot.py b/example/1d-linear-convection/eno/rusanov/timestep/rk3-eno/eno7/01/plot.py new file mode 100644 index 00000000..e389044c --- /dev/null +++ b/example/1d-linear-convection/eno/rusanov/timestep/rk3-eno/eno7/01/plot.py @@ -0,0 +1,53 @@ +import numpy as np +import matplotlib.pyplot as plt +import csv +import sys + +nvar = len(sys.argv) +print('nvar=',nvar) +print('sys.argv=',sys.argv) + +order = 1 +if nvar >= 2: + var = sys.argv[1] + print('var=',var) + order = int(var) + +print('order=',order) + +x_list = [] +u_list = [] + +with open('solution.plt', newline='') as csvfile: + #readCSV = csv.reader(csvfile, delimiter= ' ') + icount = 0 + for line in csvfile: + # 去除首尾空格,按连续空格分割 + row = line.strip().split() + #print("row=",row) + x_list.append(row[0]) + u_list.append(row[1]) + icount += 1 + +ni = icount +print("ni=",ni) + +#print("x_list=",x_list) + +x = np.zeros( ni ) +u = np.zeros( ni ) + +for i in range(0, ni): + x[i] = float(x_list[i]) + u[i] = float(u_list[i]) + +labelname = 'Eno' + str(order) + +plt.figure("OneFLOW-CFD Solver", figsize=(8, 6), dpi=100) +plt.plot(x, u, "b-", linewidth=1.0, marker = 's', markerfacecolor='None', label=labelname) +plt.xlabel("$x$") +plt.ylabel("$u$") +plt.title("burgers T=1") +plt.legend() +plt.tight_layout() +plt.show(); \ No newline at end of file diff --git a/example/1d-linear-convection/eno/rusanov/timestep/rk3-eno1/01/eno.py b/example/1d-linear-convection/eno/rusanov/timestep/rk3-eno1/01/eno.py new file mode 100644 index 00000000..4ccce148 --- /dev/null +++ b/example/1d-linear-convection/eno/rusanov/timestep/rk3-eno1/01/eno.py @@ -0,0 +1,425 @@ +import numpy as np +import matplotlib.pyplot as plt + +# 初始条件 +def initial_condition(x): + u0 = np.zeros_like(x) + for i in range(len(x)): + if 0.5 <= x[i] <= 1.0: + u0[i] = 2.0 + else: + u0[i] = 1.0 + return u0 + +# 理论解 +def analytical_solution(x, t, a, L): + # 初始条件沿 x - at 平移 + x_shifted = x - a * t + return initial_condition((x_shifted + L) % L) # 周期边界条件 + +def residual(q, eno): + reconstruction(q, eno) + inviscid_flux(eno.up1_2m, eno.up1_2p, eno.flux, eno) + for i in range(eno.nx): + eno.res[i] = -(eno.flux[i + 1] - eno.flux[i]) / eno.mesh.dx + +def reconstruction(q, eno): + # Choose the stencil by ENO method + eno.dd[0, 0:eno.ntcell-1] = q[0:eno.ntcell-1] + + for m in range(1, eno.iorder): + for j in range(0, eno.ntcell-1): + eno.dd[m, j] = eno.dd[m-1, j+1] - eno.dd[m-1, j] + + for i in range(eno.nx + 1): + eno.il[i] = i - 1 + for m in range(1, eno.iorder): + if abs(eno.dd[m, eno.il[i]-1+eno.ishift]) <= abs(eno.dd[m, eno.il[i]+eno.ishift]): + eno.il[i] -= 1 + + for i in range(eno.nx + 1): + eno.ir[i] = i + for m in range(1, eno.iorder): + if abs(eno.dd[m, eno.ir[i]-1+eno.ishift]) <= abs(eno.dd[m, eno.ir[i]+eno.ishift]): + eno.ir[i] -= 1 + + # Reconstruction u(j+1/2) + for i in range(eno.nx + 1): + k1 = eno.il[i] + k2 = eno.ir[i] + l1 = i - k1 + l2 = i - k2 + eno.up1_2m[i] = 0 + eno.up1_2p[i] = 0 + for m in range(eno.iorder): + eno.up1_2m[i] += q[k1 + eno.ishift + m] * eno.coef[l1, m] + eno.up1_2p[i] += q[k2 + eno.ishift + m] * eno.coef[l2, m] + +fluxnames = [ + 'Rusanov', + 'Engquist-Osher', +] + +def inviscid_flux(up1_2m, up1_2p, flux, eno): + if eno.solver.iflux == 0: + rusanov_flux(up1_2m, up1_2p, flux, eno) + else: + engquist_osher_flux(up1_2m, up1_2p, flux, eno) + +def engquist_osher_flux(up1_2m, up1_2p, flux, eno): + for i in range(eno.nx + 1): + u_L = up1_2m[i] + u_R = up1_2p[i] + + cp = 0.5 * ( eno.solver.c + abs(eno.solver.c) ) + cm = 0.5 * ( eno.solver.c - abs(eno.solver.c) ) + + flux[i] = cp * u_L + cm * u_R + +def rusanov_flux(up1_2m, up1_2p, flux, eno): + for i in range(eno.nx + 1): + u_L = up1_2m[i] + u_R = up1_2p[i] + F_L = eno.solver.c * u_L # 左状态通量 + F_R = eno.solver.c * u_R # 右状态通量 + alpha = abs(eno.solver.c) # 最大波速 + flux[i] = 0.5 * (F_L + F_R) - 0.5 * alpha * (u_R - u_L) + + +def boundary(u, eno): + for i in range(-eno.ighost, 1): + u[eno.ist - 1 + i] = u[eno.ied + i] + for i in range(1, eno.ighost + 2): + u[eno.ied + i] = u[eno.ist - 1 + i] + +def update_oldfield(qn, q): + qn[:] = q[:] + +def init_coef( iorder, coef ): + if iorder == 1: + coef[0] = [1.0] + coef[1] = [1.0] + elif iorder == 2: + coef[0] = [3.0/2.0, -1.0/2.0] + coef[1] = [1.0/2.0, 1.0/2.0] + coef[2] = [-1.0/2.0, 3.0/2.0] + elif iorder == 3: + coef[0] = [ 11.0/6.0, -7.0/6.0, 1.0/3.0 ] + coef[1] = [ 1.0/3.0, 5.0/6.0, -1.0/6.0 ] + coef[2] = [ -1.0/6.0, 5.0/6.0, 1.0/3.0 ] + coef[3] = [ 1.0/3.0, -7.0/6.0, 11.0/6.0 ] + elif iorder == 4: + coef[0] = [ 25.0/12.0, -23.0/12.0, 13.0/12.0, -1.0/4.0 ] + coef[1] = [ 1.0/4.0, 13.0/12.0, -5.0/12.0, 1.0/12.0 ] + coef[2] = [ -1.0/12.0, 7.0/12.0, 7.0/12.0, -1.0/12.0 ] + coef[3] = [ 1.0/12.0, -5.0/12.0, 13.0/12.0, 1.0/4.0 ] + coef[4] = [ -1.0/4.0, 13.0/12.0, -23.0/12.0, 25.0/12.0 ] + elif iorder == 5: + coef[0] = [ 137.0/60.0, -163.0/60.0, 137.0/60.0, -21.0/20.0, 1.0/5.0 ] + coef[1] = [ 1.0/5.0, 77.0/60.0, -43.0/60.0, 17.0/60.0, -1.0/20.0 ] + coef[2] = [ -1.0/20.0, 9.0/20.0, 47.0/60.0, -13.0/60.0, 1.0/30.0 ] + coef[3] = [ 1.0/30.0, -13.0/60.0, 47.0/60.0, 9.0/20.0, -1.0/20.0 ] + coef[4] = [ -1.0/20.0, 17.0/60.0, -43.0/60.0, 77.0/60.0, 1.0/5.0 ] + coef[5] = [ 1.0/5.0, -21.0/20.0, 137.0/60.0, -163.0/60.0, 137.0/60.0 ] + elif iorder == 6: + coef[0] = [ 49.0/20.0, -71.0/20.0, 79.0/20.0, -163.0/60.0, 31.0/30.0, -1.0/6.0 ] + coef[1] = [ 1.0/6.0, 29.0/20.0, -21.0/20.0, 37.0/60.0, -13.0/60.0, 1.0/30.0 ] + coef[2] = [ -1.0/30.0, 11.0/30.0, 19.0/20.0, -23.0/60.0, 7.0/60.0, -1.0/60.0 ] + coef[3] = [ 1.0/60.0, -2.0/15.0, 37.0/60.0, 37.0/60.0, -2.0/15.0, 1.0/60.0 ] + coef[4] = [ -1.0/60.0, 7.0/60.0, -23.0/60.0, 19.0/20.0, 11.0/30.0, -1.0/30.0 ] + coef[5] = [ 1.0/30.0, -13.0/60.0, 37.0/60.0, -21.0/20.0, 29.0/20.0, 1.0/6.0 ] + coef[6] = [ -1.0/6.0, 31.0/30.0, -163.0/60.0, 79.0/20.0, -71.0/20.0, 49.0/20.0 ] + elif iorder == 7: + coef[0] = [ 363.0/140.0, -617.0/140.0, 853.0/140.0, -2341.0/420.0, 667.0/210.0, -43.0/42.0, 1.0/7.0 ] + coef[1] = [ 1.0/7.0, 223.0/140.0, -197.0/140.0, 153.0/140.0, -241.0/420.0, 37.0/210.0, -1.0/42.0 ] + coef[2] = [ -1.0/42.0, 13.0/42.0, 153.0/140.0, -241.0/420.0, 109.0/420.0, -31.0/420.0, 1.0/105.0 ] + coef[3] = [ 1.0/105.0, -19.0/210.0, 107.0/210.0, 319.0/420.0, -101.0/420.0, 5.0/84.0, -1.0/140.0 ] + coef[4] = [ -1.0/140.0, 5.0/84.0, -101.0/420.0, 319.0/420.0, 107.0/210.0, -19.0/210.0, 1.0/105.0 ] + coef[5] = [ 1.0/105.0, -31.0/420.0, 109.0/420.0, -241.0/420.0, 153.0/140.0, 13.0/42.0, -1.0/42.0 ] + coef[6] = [ -1.0/42.0, 37.0/210.0, -241.0/420.0, 153.0/140.0, -197.0/140.0, 223.0/140.0, 1.0/7.0 ] + coef[7] = [ 1.0/7.0, -43.0/42.0, 667.0/210.0, -2341.0/420.0, 853.0/140.0, -617.0/140.0, 363.0/140.0 ] + +def init_field(eno): + for i in range(eno.ist, eno.ied + 1): + j = i - eno.ist + if 0.5 <= eno.mesh.xcc[j] <= 1.0: + eno.u[i] = 2.0 + else: + eno.u[i] = 1.0 + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def runge_kutta(eno): + rk = eno.solver.rk + if rk == 1: + runge_kutta_1(eno) + elif rk == 2: + runge_kutta_2(eno) + else: + runge_kutta_3(eno) + +def runge_kutta_1(eno): + dt = eno.solver.dt + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = eno.u[j] + dt * eno.res[i] + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def runge_kutta_2(eno): + dt = eno.solver.dt + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = eno.u[j] + dt * eno.res[i] + boundary(eno.u, eno) + + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = 0.5 * eno.un[j] + 0.5 * eno.u[j] + 0.5 * dt * eno.res[i] + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def runge_kutta_3(eno): + dt = eno.solver.dt + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = eno.u[j] + dt * eno.res[i] + boundary(eno.u, eno) + + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = 0.75 * eno.un[j] + 0.25 * eno.u[j] + 0.25 * dt * eno.res[i] + boundary(eno.u, eno) + + residual(eno.u, eno) + c1, c2, c3 = 1.0/3.0, 2.0/3.0, 2.0/3.0 + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = c1 * eno.un[j] + c2 * eno.u[j] + c3 * dt * eno.res[i] + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def get_ordinal_numbers(order): + if order == 1: + return 'st' + elif order == 2: + return 'nd' + elif order == 3: + return 'rd' + else: + return 'th' + +def visualize(eno): + with open('solution.plt', 'w') as f: + for i in range(eno.ist, eno.ied + 1): + j = i - eno.ist + f.write(f"{eno.xcc[j]:20.10e}{eno.u[i]:20.10e}\n") + + # 可视化 + u_numerical = np.copy(eno.u[eno.ist:eno.ied+1]) + print(f'u_numerical.size={u_numerical.size}') + print(f'eno.xcc.size={eno.xcc.size}') + #计算理论解 + u_analytical = analytical_solution(eno.mesh.xcc, eno.T, eno.c, eno.L) + print(f'u_analytical.size={u_analytical.size}') + plt.figure("OneFLOW-CFD Solver", figsize=(10, 6)) + plt.scatter(eno.xcc, u_numerical, facecolor="none", edgecolor="blue", s=20, linewidths=0.5, label=f'Numerical (Rusanov)') + plt.plot(eno.xcc, u_analytical, 'r--', label='Analytical') + plt.xlabel('x') + plt.ylabel('u') + ordinal1 = get_ordinal_numbers(eno.iorder) + ordinal2 = get_ordinal_numbers(eno.rk) + plt.title(f'1D Convection Equation at t = {eno.T:.3f} using {eno.iorder}{ordinal1}-order ENO and {eno.rk}{ordinal2}-order Runge-Kutta methods') + plt.legend() + plt.grid(True, color='gray', linestyle='--', linewidth=0.5, alpha=0.7) + plt.tight_layout() + plt.show() + +class Mesh: + def __init__(self): + self.nx = 40 + self.L = 2.0 + self.x = np.zeros(self.nx + 1) + self.xcc = np.zeros(self.nx) + self.init_mesh() + def init_mesh(self): + xstart = 0.0 + xend = self.L + self.dx = (xend - xstart) / self.nx + + for i in range(0, self.nx+1): + self.x[i] = xstart + i * self.dx + + for i in range(0, self.nx): + self.xcc[i] = 0.5 * (self.x[i] + self.x[i + 1]) + +class Solver: + def __init__(self): + self.iflux = 0 + self.rk = 3 + self.c = 1.0 + self.T = 0.625 + self.dt = .0025 + +class Eno: + def __init__(self, solver, mesh, iorder): + self.solver = solver + self.mesh = mesh + self.nx = mesh.nx + self.iorder = iorder + self.ighost = iorder + self.ishift = self.ighost + 1 + self.ist = 0 + self.ishift + self.ied = self.nx - 1 + self.ishift + self.ntcell = self.nx + 2 * self.ishift + self.isize = iorder * (iorder + 1) + + self.il = np.zeros(self.nx + 1, dtype=int) + self.ir = np.zeros(self.nx + 1, dtype=int) + self.coef = np.zeros((iorder + 1, iorder)) + self.dd = np.zeros((iorder, self.ntcell)) + self.up1_2m = np.zeros(self.nx + 1) + self.up1_2p = np.zeros(self.nx + 1) + self.flux = np.zeros(self.nx + 1) + self.res = np.zeros(self.nx) + + # Field module variables + self.u = np.zeros(self.ntcell) + self.un = np.zeros(self.ntcell) + + #self.dt = .0025 + +def plot_eno_OrderAnalysis(solver, xcc, u_list, u_analytical): + # 定义一个包含不同颜色、线形和标记的列表 + styles = [ + {'color': 'black', 'linestyle': '-', 'marker': 'o'}, + {'color': 'blue', 'linestyle': '--', 'marker': 's'}, + {'color': 'black', 'linestyle': '-', 'marker': '^'}, + {'color': 'blue', 'linestyle': '--', 'marker': 'v'}, + {'color': 'black', 'linestyle': '-', 'marker': '<'}, + {'color': 'blue', 'linestyle': '--', 'marker': '>'}, + {'color': 'black', 'linestyle': '-', 'marker': 'D'}, + ] + + n = len(u_list) + num_styles = len(styles) + ordinal = get_ordinal_numbers(solver.rk) + + plt.figure("OneFLOW-CFD Solver", figsize=(10, 6)) + plt.title(f'1D Convection Equation at t = {solver.T:.3f} using [1-7]th-order ENO and {solver.rk}{ordinal}-order Runge-Kutta methods') + for i in range(0, n): + lable = 'Numerical (Rusanov)ENO' + str(i+1) + style = styles[i % num_styles] + plt.plot(xcc, u_list[i], marker=style['marker'], markerfacecolor='none', linestyle=style['linestyle'], color=style['color'], \ + markersize=5, linewidth=0.5, alpha=1.0, label=f'{lable}') + plt.plot(xcc, u_analytical, 'r--', label='Analytical') + plt.xlabel('x') + plt.ylabel('u') + plt.legend() + plt.grid(True, color='gray', linestyle='--', linewidth=0.5, alpha=0.7) + plt.tight_layout() + plt.show() + +def plot_eno_TimestepAnalysis(solver, xcc, u_list, u_analytical, dt_list, iorder): + # 定义一个包含不同颜色、线形和标记的列表 + styles = [ + {'color': 'black', 'linestyle': '-', 'marker': 'o'}, + {'color': 'blue', 'linestyle': '--', 'marker': 's'}, + {'color': 'black', 'linestyle': '-', 'marker': '^'}, + {'color': 'blue', 'linestyle': '--', 'marker': 'v'}, + {'color': 'black', 'linestyle': '-', 'marker': '<'}, + {'color': 'blue', 'linestyle': '--', 'marker': '>'}, + {'color': 'black', 'linestyle': '-', 'marker': 'D'}, + {'color': 'blue', 'linestyle': '--', 'marker': 'o'}, + {'color': 'black', 'linestyle': '-', 'marker': 's'}, + {'color': 'blue', 'linestyle': '--', 'marker': '^'}, + {'color': 'black', 'linestyle': '-', 'marker': 'v'}, + {'color': 'blue', 'linestyle': '--', 'marker': '<'}, + {'color': 'black', 'linestyle': '-', 'marker': '>'}, + {'color': 'blue', 'linestyle': '--', 'marker': 'D'}, + ] + + n = len(u_list) + num_styles = len(styles) + + ordinalENO = get_ordinal_numbers(iorder) + ordinalRK = get_ordinal_numbers(solver.rk) + + plt.figure("OneFLOW-CFD Solver", figsize=(10, 6)) + plt.title(f'1D Convection Equation at t = {solver.T:.3f} using {iorder}{ordinalENO}-order ENO and {solver.rk}{ordinalRK}-order Runge-Kutta methods') + for i in range(0, n): + lable = 'Numerical (Rusanov)ENO' + str(iorder) + ' T='+str(dt_list[i]) + style = styles[i % num_styles] + plt.plot(xcc, u_list[i], marker=style['marker'], markerfacecolor='none', linestyle=style['linestyle'], color=style['color'], \ + markersize=5, linewidth=1.0, alpha=1.0, label=f'{lable}') + plt.plot(xcc, u_analytical, 'r--', label='Analytical') + plt.xlabel('x') + plt.ylabel('u') + plt.legend() + plt.grid(True, color='gray', linestyle='--', linewidth=0.5, alpha=0.7) + plt.tight_layout() + plt.show() + +def RunEno(solver, mesh, iorder): + eno = Eno(solver, mesh, iorder) + init_coef(eno.iorder, eno.coef) + init_field(eno) + + simu_time = solver.T + t = 0.0 + dt = solver.dt + while t < simu_time: + runge_kutta(eno) + if t + dt > simu_time: + dt = simu_time - t + t += dt + #print(f'T={t:.3f},runge_kutta{solver.rk},ENO{eno.iorder},{fluxnames[solver.iflux]} FLUX') + #visualize(eno) + return np.copy(eno.u[eno.ist:eno.ied+1]) + +def performEnoOrderAnalysis(): + iorder_max = 7 + mesh = Mesh() + solver = Solver() + #计算理论解 + u_analytical = analytical_solution(mesh.xcc, solver.T, solver.c, mesh.L) + + u_list = [] + for iorder in range(1, iorder_max+1): + u = RunEno(solver, mesh, iorder) + u_list.append(u) + + plot_eno_OrderAnalysis(solver, mesh.xcc, u_list, u_analytical) + +def performEnoTimestepAnalysis(): + mesh = Mesh() + solver = Solver() + #计算理论解 + u_analytical = analytical_solution(mesh.xcc, solver.T, solver.c, mesh.L) + + u_list = [] + dt_list = [] + solver.dt = 0.025 + #solver.dt = 0.025/16 + n = 12 + iorder = 1 + for i in range(0, n): + u = RunEno(solver, mesh, iorder) + u_list.append(u) + dt_list.append(solver.dt) + print(f'i={i+1},N={n},T={solver.T:.3f},dt={solver.dt},nt={int(solver.T/solver.dt)},runge_kutta{solver.rk},ENO{iorder},{fluxnames[solver.iflux]} FLUX') + solver.dt /= 2 + + plot_eno_TimestepAnalysis(solver, mesh.xcc, u_list, u_analytical, dt_list, iorder) + +def main(): + #performEnoOrderAnalysis() + performEnoTimestepAnalysis() + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/example/1d-linear-convection/eno/rusanov/timestep/rk3-eno1/01/plot.py b/example/1d-linear-convection/eno/rusanov/timestep/rk3-eno1/01/plot.py new file mode 100644 index 00000000..e389044c --- /dev/null +++ b/example/1d-linear-convection/eno/rusanov/timestep/rk3-eno1/01/plot.py @@ -0,0 +1,53 @@ +import numpy as np +import matplotlib.pyplot as plt +import csv +import sys + +nvar = len(sys.argv) +print('nvar=',nvar) +print('sys.argv=',sys.argv) + +order = 1 +if nvar >= 2: + var = sys.argv[1] + print('var=',var) + order = int(var) + +print('order=',order) + +x_list = [] +u_list = [] + +with open('solution.plt', newline='') as csvfile: + #readCSV = csv.reader(csvfile, delimiter= ' ') + icount = 0 + for line in csvfile: + # 去除首尾空格,按连续空格分割 + row = line.strip().split() + #print("row=",row) + x_list.append(row[0]) + u_list.append(row[1]) + icount += 1 + +ni = icount +print("ni=",ni) + +#print("x_list=",x_list) + +x = np.zeros( ni ) +u = np.zeros( ni ) + +for i in range(0, ni): + x[i] = float(x_list[i]) + u[i] = float(u_list[i]) + +labelname = 'Eno' + str(order) + +plt.figure("OneFLOW-CFD Solver", figsize=(8, 6), dpi=100) +plt.plot(x, u, "b-", linewidth=1.0, marker = 's', markerfacecolor='None', label=labelname) +plt.xlabel("$x$") +plt.ylabel("$u$") +plt.title("burgers T=1") +plt.legend() +plt.tight_layout() +plt.show(); \ No newline at end of file diff --git a/example/1d-linear-convection/eno2/fortran/01/CMakeLists.txt b/example/1d-linear-convection/eno2/fortran/01/CMakeLists.txt deleted file mode 100644 index bc555e2d..00000000 --- a/example/1d-linear-convection/eno2/fortran/01/CMakeLists.txt +++ /dev/null @@ -1,28 +0,0 @@ -cmake_minimum_required(VERSION 3.31) - -project ( testprj ) - -set ( PRJ_COMPILE_FEATURES ) -set ( PRJ_COMPILE_DEFINITIONS ) - -enable_language(Fortran) - -list ( APPEND PRJ_COMPILE_FEATURES cxx_std_20 ) - -if ( MSVC ) - set_property( DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT ${PROJECT_NAME} ) -endif() - -add_executable( ${PROJECT_NAME} - enoburgers.f90 -) - -target_compile_features ( ${PROJECT_NAME} - PRIVATE - ${PRJ_COMPILE_FEATURES} -) - -target_compile_definitions ( ${PROJECT_NAME} - PRIVATE - ${PRJ_COMPILE_DEFINITIONS} -) \ No newline at end of file diff --git a/example/1d-linear-convection/eno2/fortran/01/README.txt b/example/1d-linear-convection/eno2/fortran/01/README.txt deleted file mode 100644 index 9d453dd9..00000000 --- a/example/1d-linear-convection/eno2/fortran/01/README.txt +++ /dev/null @@ -1 +0,0 @@ -cmake ../ -T fortran=ifx \ No newline at end of file diff --git a/example/1d-linear-convection/eno2/fortran/01/enoburgers.f90 b/example/1d-linear-convection/eno2/fortran/01/enoburgers.f90 deleted file mode 100644 index 7106d53c..00000000 --- a/example/1d-linear-convection/eno2/fortran/01/enoburgers.f90 +++ /dev/null @@ -1,267 +0,0 @@ -module global - implicit none - integer, parameter :: nx = 40 - integer, parameter :: ighost = 10 - integer, parameter :: iorder = 2 - integer, parameter :: isize = iorder * ( iorder + 1 ) - real(8), parameter :: pi = 3.14159265358979323846 - integer il(0:nx),ir(0:nx) - real(8) :: coef(-1:iorder-1,0:iorder-1) - real(8) :: dd(0:ighost-1, -ighost:nx+ighost) - real(8) :: up1_2m(0:nx), up1_2p(0:nx), flux(0:nx) - real(8) :: res(1:nx) - real(8) :: dx, dt -end module global - -module mesh_module - use global, only: nx, ighost - implicit none - real(8) :: x(-ighost:nx+ighost) -endmodule mesh_module - -module field_module - use global, only: nx, ighost - implicit none - real(8) :: pu(-ighost:nx+ighost), un(-ighost:nx+ighost) -endmodule field_module - -subroutine residual(u) - use global - implicit none - real(8) :: u(-ighost:nx+ighost) - integer i - - call reconstruction(u) - call engquist_osher_flux(up1_2m,up1_2p,flux,nx) - do i = 1, nx - res(i) = - ( flux(i) - flux(i-1) ) / dx - enddo - -end subroutine residual - -subroutine reconstruction(u) - use global - implicit none - real(8) :: u(-ighost:nx+ighost) - integer :: i, j, m, k1, k2, l1, l2 - - !chose the stencil by ENO method - do j = -ighost, nx + ighost - dd(0,j)=u(j) - enddo - do i=1,iorder-1 - do j=-ighost,nx+ighost-1 - dd(i,j)=dd(i-1,j+1)-dd(i-1,j) - enddo - enddo - - do j = 0, nx - il(j) = j - ir(j) = j + 1 - do i=1,iorder-1 - if( abs(dd(i,il(j)-1)) <= abs(dd(i,il(j))) ) then - il(j)=il(j)-1 - endif - if( abs(dd(i,ir(j)-1)) <= abs(dd(i,ir(j))) ) then - ir(j)=ir(j)-1 - endif - enddo - enddo - ! reconstruction u(j+1_2) - do j=0,nx - k1=il(j) - k2=ir(j) - l1=j-k1 - l2=j-k2 - up1_2m(j)=0 - up1_2p(j)=0 - do m=0,iorder-1 - up1_2m(j)=up1_2m(j)+u(k1+m)*coef(l1,m) - up1_2p(j)=up1_2p(j)+u(k2+m)*coef(l2,m) - enddo - enddo -end subroutine reconstruction - -!calculate numerical flux -subroutine engquist_osher_flux(up1_2m,up1_2p,flux,nx) - implicit none - real(8) :: up1_2m(0:nx),up1_2p(0:nx),flux(0:nx) - integer :: i, nx - - do i = 0, nx - if ( up1_2m(i) >= 0 ) then - if ( up1_2p(i) >= 0 ) then - flux(i) = 0.5 * up1_2m(i) * up1_2m(i) - else - flux(i) = 0.5 * ( up1_2m(i) * up1_2m(i) + up1_2p(i) * up1_2p(i) ) - endif - else - if ( up1_2p(i) >= 0 ) then - flux(i) = 0 - else - flux(i) = 0.5 * up1_2p(i) * up1_2p(i) - endif - endif - enddo -end subroutine engquist_osher_flux - -subroutine boundary( u, nx, ighost ) - implicit none - integer :: nx, ighost - real(8) :: u(-ighost:nx+ighost) - integer :: i - - do i = 0, - ighost, - 1 - u( i ) = u( i + nx ) - enddo - - do i = nx + 1, nx + ighost - u( i ) = u( i - nx ) - enddo -end subroutine boundary - -subroutine update_oldfield(un, pu, nx, ighost) - implicit none - integer :: nx, ighost - real(8) :: un(-ighost:nx+ighost), pu(-ighost:nx+ighost) - integer :: i - - do i = -ighost, nx + ighost - un( i ) = pu( i ) - enddo -end subroutine update_oldfield - -subroutine init_coef - use global - implicit none - real(8) :: values(isize) = [1.5d0, -0.5d0, 0.5d0, 0.5d0, -0.5d0, 1.5d0] - integer :: i, j, icount - - icount = 1 - do i = -1, iorder-1 - do j = 0, iorder-1 - coef(i, j) = values(icount) - icount = icount + 1 - end do - end do - -end subroutine init_coef - -subroutine init_mesh - use global - use mesh_module - implicit none - integer :: i - - do i = -ighost, nx + ighost - x(i) = ( i - 1 ) * dx + dx/2 - 1.0 - enddo - -end subroutine init_mesh - -subroutine init_field() - use global - use mesh_module - use field_module - implicit none - integer :: i - - do i = 1, nx - pu(i) = 0.25 + 0.5 * sin( pi * x(i) ) - enddo - - call boundary( pu, nx, ighost ) - call update_oldfield(un, pu, nx, ighost) - -end subroutine init_field - -subroutine runge_kutta_3() - use global - use field_module - implicit none - integer :: i - real(8) :: c1, c2, c3 - - call residual(pu) - do i = 1, nx - pu(i) = pu(i) + dt * res(i) - enddo - call boundary( pu, nx, ighost ) - - call residual(pu) - - do i = 1, nx - pu(i) = 0.75 * un(i) + 0.25 * pu(i) + 0.25 * dt * res(i) - enddo - - call boundary( pu, nx, ighost ) - - call residual(pu) - - c1 = 1.0 / 3.0 - c2 = 2.0 / 3.0 - c3 = 2.0 / 3.0 - - do i = 1, nx - pu(i) = c1 * un(i) + c2 * pu(i) + c3 * dt * res(i) - enddo - call boundary( pu, nx, ighost ) - - call update_oldfield(un, pu, nx, ighost) - -end subroutine runge_kutta_3 - -subroutine visualize - use global - use mesh_module - use field_module - implicit none - integer :: i - open(1,file='solution_total.plt',status='unknown') - do i = -ighost, nx + ighost - write(1,101) x(i),pu(i) - enddo - close(1) - - open(2,file='solution.plt',status='unknown') - do i = 1, nx - write(2,101) x(i),pu(i) - enddo - close(2) - 101 format(1x,e20.10,e20.10) -end subroutine visualize - -program main - use global - use mesh_module - use field_module - implicit none - integer :: i - real(8) :: t, simu_time, xlen - xlen = 2.0 - dx = xlen / nx - dt = dx * 0.5 - write(*,*) 'nx=',nx - write(*,*) 'dx=',dx - write(*,*) 'Input T:' - read(*,*) simu_time - - call init_coef() - call init_mesh() - call init_field() - - t = 0 - do while( t < simu_time ) - call runge_kutta_3() - - t = t + dt - if ( t + dt > simu_time ) then - dt = simu_time - t - endif - enddo - - write(*,*) t - - call visualize() - -end program main \ No newline at end of file diff --git a/example/1d-linear-convection/eno3/cpp/01/BurgersField.cpp b/example/1d-linear-convection/eno3/cpp/01/BurgersField.cpp deleted file mode 100644 index 6af041ac..00000000 --- a/example/1d-linear-convection/eno3/cpp/01/BurgersField.cpp +++ /dev/null @@ -1,366 +0,0 @@ -#include "BurgersField.h" -#include "Weno.h" -#include "hxmath.h" -#include "Global.h" -#include "Grid.h" -#include "cgnslib.h" -#include -#include -#include -#include -#include - -void BurgersField::Init( std::fstream & file, Grid * grid ) -{ - this->ni = grid->ni; - this->nic = grid->nic; - grid->CalcMetrics(); - if ( Global::ifinite_volume == 1 ) - { - this->nx = this->nic; - } - else - { - // finite difference - this->nx = this->ni; - } - - Vec1d & x = grid->x; - this->dx = std::abs( x[ 1 ] - x[ 0 ] ); - this->dt = 0.0001; - this->nt = std::round( Global::total_time / dt ); - - std::print( "ni={}\n", ni ); - std::print( "dt={}\n", dt ); - std::print( "dx={}\n", dx ); - std::print( "nt={}\n", nt ); - std::cout << "this->dt = " << this->dt << "\n"; - std::cout << "this->nt = " << this->nt << "\n"; - std::cout << "this->ni = " << this->ni << "\n"; - std::cout << "nt * dt = " << nt * dt << "\n"; - - Global::nt = nt; - - int ist = 0 - Global::nghost; - int ied = this->nx - 1 + Global::nghost; - - this->u.Allocate( this->nequ, ist, ied ); - this->un.Allocate( this->nequ, ist, ied ); - this->res.Allocate( this->nequ, 0, this->nx ); //N+1 - - Vec1d &u = this->u.vec(); - - if ( Global::ifinite_volume == 0 ) - { - //node - for ( int i = 0; i < ni; ++ i ) - { - u[ i ] = std::sin( 2.0 * std::numbers::pi * x[ i ] ); - } - } - else - { - //cell center - Vec1d & xcc = grid->xcc; - for ( int i = 0; i < nic; ++ i ) - { - u[ i ] = std::sin( 2.0 * std::numbers::pi * xcc[ i ] ); - } - - } - - - int kkk = 1; -} - -void BurgersField::InviscidResidual( VecWrap & u, VecWrap & res ) -{ - if ( Global::iconservation == 0 ) - { - this->InviscidNonConservative( u, res ); - } - else - { - this->InviscidConservative( u, res ); - } -} - -void BurgersField::InviscidNonConservative( VecWrap & u, VecWrap & res ) -{ - VecWrap uL, uR; - uL.Allocate( this->nequ, 0, nx, 0 ); - uR.Allocate( this->nequ, 0, nx, 0 ); - - if ( Global::scheme.reconstruction == to_int( BasicScheme::CRWENO ) ) - { - crwenoL( nx, u, uL ); - crwenoR( nx, u, uR ); - } - else if ( Global::scheme.reconstruction == to_int( BasicScheme::WENO ) ) - { - wenoL( nx, u, uL ); - wenoR( nx, u, uR ); - } - - if ( Global::scheme.inviscid == to_int( BasicScheme::CENTER ) ) - { - for ( int m = 0; m < nequ; ++ m ) - { - Vec1d & U = u.vec( m ); - Vec1d & Res = res.vec( m ); - for ( int i = 0; i < nx; ++ i ) - { - Res[ i ] += ( - U[ i ] * ( U[ i + 1 ] - U[ i - 1 ] ) / dx ); - } - } - } - else - { - for ( int m = 0; m < nequ; ++ m ) - { - Vec1d & U = u.vec( m ); - Vec1d & Res = res.vec( m ); - Vec1d & UL = uL.vec( m ); - Vec1d & UR = uR.vec( m ); - for ( int i = 0; i < nx; ++ i ) - { - if ( U[ i ] >= 0.0 ) - { - Res[ i ] += ( - U[ i ] * ( UL[ i + 1 ] - UL[ i ] ) / dx ); - } - else - { - Res[ i ] += ( - U[ i ] * ( UR[ i + 1 ] - UR[ i ] ) / dx ); - } - } - } - } -} - -void BurgersField::WaveSpeed( VecWrap & um, VecWrap & psm ) -{ - for ( int m = 0; m < nequ; ++ m ) - { - Vec1d & u = um.vec( m ); - Vec1d & ps = psm.vec( m ); - - for ( int i = 0; i <= nx; ++ i ) - { - ps[ i ] = std::max( { std::abs( u[ i - 2 ] ), std::abs( u[ i - 1 ] ), std::abs( u[ i ] ), std::abs( u[ i + 1 ] ), std::abs( u[ i + 2 ] ) } ); - } - - for ( int i = ps.ist; i < 0; ++ i ) - { - ps[ i ] = ps[ 0 ]; - } - - for ( int i = nx + 1; i <= ps.ied; ++ i ) - { - ps[ i ] = ps[ nx ]; - } - } -} - -void BurgersField::LaxFriedrichs( VecWrap & u, VecWrap & res ) -{ - VecWrap fL, fR; - fL.Allocate( this->nequ, 0, nx, 0 ); - fR.Allocate( this->nequ, 0, nx, 0 ); - - int ist = 0 - Global::nghost; - int ied = this->nx - 1 + Global::nghost; - - VecWrap f, fP, fN; - - f.Allocate( this->nequ, ist, ied, 0 ); - fP.Allocate( this->nequ, ist, ied, 0 ); - fN.Allocate( this->nequ, ist, ied, 0 ); - - burgers_fluxes( ist, ied, u, f ); - - VecWrap psm; - psm.Allocate( this->nequ, ist, ied, 0 ); - - WaveSpeed( u, psm ); - - // left and right side fluxes at the interface - for ( int m = 0; m < nequ; ++ m ) - { - Vec1d & u = this->u.vec( m ); - Vec1d & FP = fP.vec( m ); - Vec1d & FN = fN.vec( m ); - Vec1d & F = f.vec( m ); - Vec1d & ps = psm.vec( m ); - for ( int i = ist; i <= ied; ++ i ) - { - FP[ i ] = 0.5 * ( F[ i ] + ps[ i ] * u[ i ] ); - FN[ i ] = 0.5 * ( F[ i ] - ps[ i ] * u[ i ] ); - } - } - - if ( Global::scheme.reconstruction == to_int( BasicScheme::CRWENO ) ) - { - crwenoL( nx, fP, fL ); - crwenoR( nx, fN, fR ); - } - else if ( Global::scheme.reconstruction == to_int( BasicScheme::WENO ) ) - { - wenoL( nx, fP, fL ); - wenoR( nx, fN, fR ); - } - - for ( int m = 0; m < nequ; ++ m ) - { - Vec1d & FL = fL.vec( m ); - Vec1d & FR = fR.vec( m ); - Vec1d & res = this->res.vec( m ); - for ( int i = 0; i < nx; ++ i ) - { - res[ i ] -= ( FL[ i + 1 ] - FL[ i ] ) / dx + ( FR[ i + 1 ] - FR[ i ] ) / dx; - } - } -} - -void BurgersField::burgers_fluxes( int ist, int ied, VecWrap & u, VecWrap & f ) -{ - Vec1d & F = f.vec(); - Vec1d & U = u.vec(); - for ( int i = ist; i <= ied; ++ i ) - { - F[ i ] = 0.5 * U[ i ] * U[ i ]; - } -} - -void BurgersField::Rusanov( VecWrap & u, VecWrap & res ) -{ - VecWrap uL, uR; - uL.Allocate( this->nequ, 0, nx, 0 ); - uR.Allocate( this->nequ, 0, nx, 0 ); - - //WENO Reconstruction - if ( Global::scheme.reconstruction == to_int( BasicScheme::CRWENO ) ) - { - crwenoL( nx, u, uL ); - crwenoR( nx, u, uR ); - } - else if ( Global::scheme.reconstruction == to_int( BasicScheme::WENO ) ) - { - wenoL( nx, u, uL ); - wenoR( nx, u, uR ); - } - - //left and right side fluxes at the interface - VecWrap fL, fR; - fL.Allocate( this->nequ, 0, nx, 0 ); - fR.Allocate( this->nequ, 0, nx, 0 ); - - int ist = 0 - Global::nghost; - int ied = this->nx - 1 + Global::nghost; - - //Computing fluxes - burgers_fluxes( 0, nx, uL, fL ); - burgers_fluxes( 0, nx, uR, fR ); - - VecWrap psm; - psm.Allocate( this->nequ, ist, ied, 0 ); - - WaveSpeed( u, psm ); - - //fluxes at the interface - Vec1d f; - f.Allocate( 0, nx, 0 ); - - //Interface fluxes (Rusanov) - for ( int m = 0; m < nequ; ++ m ) - { - Vec1d & u = this->u.vec( m ); - Vec1d & res = this->res.vec( m ); - Vec1d & qL = uL.vec( m ); - Vec1d & qR = uR.vec( m ); - Vec1d & FL = fL.vec( m ); - Vec1d & FR = fR.vec( m ); - Vec1d & ps = psm.vec( m ); - - for ( int i = 0; i <= nx; ++ i ) - { - f[ i ] = 0.5 * ( FR[ i ] + FL[ i ] ) - 0.5 * ps[ i ] * ( qR[ i ] - qL[ i ] ); - } - for ( int i = 0; i < nx; ++ i ) - { - res[ i ] -= ( f[ i + 1 ] - f[ i ] ) / dx; - } - } - -} - - -void BurgersField::InviscidConservative( VecWrap & u, VecWrap & res ) -{ - if ( Global::scheme.inviscid == to_int( BasicScheme::LAX ) ) - { - this->LaxFriedrichs( u, res ); - } - else if ( Global::scheme.inviscid == to_int( BasicScheme::Rusanov ) ) - { - this->Rusanov( u, res ); - } - } - -void BurgersField::ViscousResidual( VecWrap & u, VecWrap & res ) -{ - ; -} - -void BurgersField::Rhs( VecWrap & u, VecWrap & res ) -{ - res = 0; - InviscidResidual( u, res ); - if ( Global::iviscous > 0 ) - { - ViscousResidual( u, res ); - } - } - -void BurgersField::UpdateOldField() -{ - this->un = this->u; -} - -void BurgersField::DumpField( Grid * grid ) -{ - if ( Global::ifinite_volume == 1 ) - { - this->DumpField( grid->xcc, u ); - } - else - { - this->DumpField( grid->x, u ); - } - -} - -void BurgersField::PostProcess( Grid * grid ) -{ - if ( Global::ifinite_volume == 1 ) - { - this->DumpField( grid->xcc, u ); - } - else - { - this->DumpField( grid->x, u ); - } -} - -void BurgersField::DumpField( Vec1d & x, VecWrap & u ) -{ - for ( int i = 0; i < x.size(); ++ i ) - { - Global::file_string += std::format( "{:.16f}", x[ i ] ); - for ( int m = 0; m < nequ; ++ m ) - { - Vec1d & u = this->u.vec( m ); - Global::file_string += std::format( " {:.16f}", u[ i ] ); - } - Global::file_string += std::format( "\n" ); - } -} diff --git a/example/1d-linear-convection/eno3/cpp/01/BurgersField.h b/example/1d-linear-convection/eno3/cpp/01/BurgersField.h deleted file mode 100644 index bd07a1f2..00000000 --- a/example/1d-linear-convection/eno3/cpp/01/BurgersField.h +++ /dev/null @@ -1,31 +0,0 @@ -#pragma once -#include "Vec1d.h" -#include "Field.h" -#include - -class BurgersField : public Field -{ -public: - int nt; - double dx; -public: - void Init( std::fstream & file, Grid * grid ); -public: - void Rhs( VecWrap & u, VecWrap & res ); - void InviscidResidual( VecWrap & u, VecWrap & res ); - void ViscousResidual( VecWrap & u, VecWrap & res ); - void InviscidNonConservative( VecWrap & u, VecWrap & res ); - void InviscidConservative( VecWrap & u, VecWrap & res ); - void WaveSpeed( VecWrap & um, VecWrap & psm ); -public: - void LaxFriedrichs( VecWrap & u, VecWrap & res ); - void Rusanov( VecWrap & u, VecWrap & res ); - void burgers_fluxes( int ist, int ied, VecWrap & u, VecWrap & f ); -public: - void UpdateOldField(); - void DumpField( Grid * grid ); - void PostProcess( Grid * grid ); - void DumpField( Vec1d & x, VecWrap & u ); -}; - - diff --git a/example/1d-linear-convection/eno3/cpp/01/CMakeLists.txt b/example/1d-linear-convection/eno3/cpp/01/CMakeLists.txt deleted file mode 100644 index cbc3f9bb..00000000 --- a/example/1d-linear-convection/eno3/cpp/01/CMakeLists.txt +++ /dev/null @@ -1,106 +0,0 @@ -cmake_minimum_required(VERSION 3.31) - -project( testprj ) - -set ( PRJ_COMPILE_FEATURES ) -set ( PRJ_COMPILE_DEFINITIONS ) -set ( PRJ_LIBRARIES ) -set ( PRJ_INCLUDE_DIRS ) - -list ( APPEND PRJ_COMPILE_FEATURES cxx_std_23 ) - -message ( STATUS "EIGEN3_INCLUDE_DIR = ${EIGEN3_INCLUDE_DIR}" ) - -find_package(nlohmann_json) - -list ( APPEND PRJ_LIBRARIES nlohmann_json::nlohmann_json ) - -find_package ( MPI ) - -message ( STATUS "MPI_FOUND=${MPI_FOUND}" ) -message ( STATUS "MPI_CXX_INCLUDE_DIRS=${MPI_CXX_INCLUDE_DIRS}" ) -message ( STATUS "MPI_LIBRARIES=${MPI_LIBRARIES}" ) -if ( MPI_FOUND ) - list ( APPEND PRJ_INCLUDE_DIRS ${MPI_CXX_INCLUDE_DIRS} ) - list ( APPEND PRJ_LIBRARIES ${MPI_LIBRARIES} ) -endif () - -list ( APPEND PRJ_LIBRARIES MPI::MPI_C ) - -set ( CGNS_INCLUDE_DIRS $ENV{CGNS_INC} ) -set ( CGNS_LIBRARIES $ENV{CGNS_LIB_SHARED_NAME} ) - -if ( ${CMAKE_SYSTEM_NAME} MATCHES "Windows" ) - set ( CGNS_ROOT "C:/dev/cgns/4.4.0" ) - set ( CGNS_LIBNAME "cgnsdll.lib" ) - - set ( CGNS_INCLUDE_DIRS "${CGNS_ROOT}/include" CACHE PATH "path to CGNS headers" ) - set ( CGNS_LIBRARIES "${CGNS_ROOT}/lib/${CGNS_LIBNAME}" CACHE PATH "path to CGNS library" ) -endif() - -list ( APPEND PRJ_LIBRARIES ${CGNS_LIBRARIES} ) -list ( APPEND PRJ_INCLUDE_DIRS ${CGNS_INCLUDE_DIRS} ) - -if ( WIN32 ) - list ( APPEND PRJ_COMPILE_DEFINITIONS USE_DLL ) -endif () - -list ( APPEND PRJ_COMPILE_DEFINITIONS HX_PARALLEL ) - -message( STATUS "PRJ_INCLUDE_DIRS = ${PRJ_INCLUDE_DIRS}") - -if ( MSVC ) - set_property( DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT ${PROJECT_NAME} ) -endif() - -add_executable( ${PROJECT_NAME} -) - -set( PROJECT_SOURCES - main.cpp - Vec1d.h Vec1d.cpp - CgnsUtil.h CgnsUtil.cpp - ConvectionField.h ConvectionField.cpp - Field.h Field.cpp - BurgersField.h BurgersField.cpp - EulerField.h EulerField.cpp - HeatField.h HeatField.cpp - Global.h Global.cpp - Grid.h Grid.cpp - hxmath.h hxmath.cpp - LogFile.h LogFile.cpp - Parallel.h Parallel.cpp - Post.h Post.cpp - Solver.h Solver.cpp - Eno.h Eno.cpp - Weno.h Weno.cpp - ZoneState.h ZoneState.cpp -) - -message( STATUS "PROJECT_NAME = ${PROJECT_NAME}") -message( STATUS "PROJECT_SOURCES = ${PROJECT_SOURCES}") - -target_sources( ${PROJECT_NAME} - PRIVATE - ${PROJECT_SOURCES} -) - -target_include_directories ( ${PROJECT_NAME} - PRIVATE - ${PRJ_INCLUDE_DIRS} -) - -target_link_libraries( ${PROJECT_NAME} - PRIVATE - ${PRJ_LIBRARIES} -) - -target_compile_features ( ${PROJECT_NAME} - PRIVATE - ${PRJ_COMPILE_FEATURES} -) - -target_compile_definitions ( ${PROJECT_NAME} - PRIVATE - ${PRJ_COMPILE_DEFINITIONS} -) diff --git a/example/1d-linear-convection/eno3/cpp/01/CgnsUtil.cpp b/example/1d-linear-convection/eno3/cpp/01/CgnsUtil.cpp deleted file mode 100644 index 0e10b205..00000000 --- a/example/1d-linear-convection/eno3/cpp/01/CgnsUtil.cpp +++ /dev/null @@ -1,584 +0,0 @@ -#include "CgnsUtil.h" -#include "Global.h" -#include "Grid.h" -#include "Parallel.h" -#include "ZoneState.h" -#include "cgnslib.h" -#include -#include - -BaseZoneList global_zone_names; - -void ReadCgnsGridBaseZone( const std::string & filename ) -{ - int fileId = -1; - if ( Parallel::IsServer() ) - { - cg_open( filename.c_str(), CG_MODE_READ, &fileId ); - std::cout << "Parallel::pid = " << Parallel::pid << " "; - std::cout << "fileId = " << fileId << "\n"; - } - - int nbases = -1; - if ( Parallel::IsServer() ) - { - cg_nbases( fileId, &nbases ); - } - HXBcastData( &nbases, 1, Parallel::serverid ); - std::cout << "Parallel::pid = " << Parallel::pid << " "; - std::cout << "nbases = " << nbases << "\n"; - - for ( int iBase = 0; iBase < nbases; ++ iBase ) - { - char basename[ 33 ]; - int baseId = iBase + 1; - int icelldim = -1; - int iphysdim = -1; - if ( Parallel::IsServer() ) - { - cg_base_read( fileId, baseId, basename, &icelldim, &iphysdim ); - } - - HXBcastData( &icelldim, 1, Parallel::serverid ); - HXBcastData( &iphysdim, 1, Parallel::serverid ); - - std::cout << "Parallel::pid = " << Parallel::pid << " "; - std::cout << "icelldim = " << icelldim << " iphysdim = " << iphysdim << "\n"; - - int nzones = -1; - if ( Parallel::IsServer() ) - { - cg_nzones( fileId, baseId, &nzones ); - } - - HXBcastData( &nzones, 1, Parallel::serverid ); - - ZoneState::nZones = nzones; - ZoneState::pids.resize( nzones ); - ZoneState::g2lzoneids.resize( nzones ); - std::vector pcount( Parallel::nProc, 0 ); - - for ( int iZone = 0; iZone < ZoneState::nZones; ++ iZone ) - { - int zone_pid = iZone % Parallel::nProc; - ZoneState::pids[ iZone ] = zone_pid; - ZoneState::g2lzoneids[ iZone ] = pcount[ zone_pid ]; - pcount[ zone_pid ] ++; - } - - std::cout << "Parallel::pid = " << Parallel::pid << " "; - std::cout << "nzones = " << nzones << "\n"; - - for ( int iZone = 0; iZone < nzones; ++ iZone ) - { - int zoneId = iZone + 1; - std::cout << "Parallel::pid = " << Parallel::pid << " "; - std::cout << "iZone = " << iZone << "\n"; - - int index_dim = -1; - if ( Parallel::IsServer() ) - { - cg_index_dim( fileId, baseId, zoneId, &index_dim ); - } - HXBcastData( &index_dim, 1, Parallel::serverid ); - - std::cout << "Parallel::pid = " << Parallel::pid << " "; - std::cout << "index_dim = " << index_dim << "\n"; - - std::vector isize( index_dim * 3 ); - - char zonename[ 33 ]; - if ( Parallel::IsServer() ) - { - cg_zone_read( fileId, baseId, zoneId, zonename, isize.data() ); - } - - HXBcastData( zonename, 33, Parallel::serverid ); - HXBcastData( isize.data(), isize.size(), Parallel::serverid); - - std::cout << "Parallel::pid = " << Parallel::pid << " "; - std::cout << "zonename = " << zonename << "\n"; - - for ( int i = 0; i < isize.size(); ++ i ) - { - std::cout << "Parallel::pid = " << Parallel::pid << " "; - std::cout << "i = " << i << " isize = " << isize[ i ] << "\n"; - } - - BaseZone baseZone; - baseZone.zone_name = zonename; - - global_zone_names.AddBaseZone( baseZone ); - } - } - - if ( Parallel::IsServer() ) - { - cg_close( fileId ); - } -} - -void ReadCgnsGrid( const std::string & filename ) -{ - int fileId = -1; - if ( Parallel::IsServer() ) - { - cg_open( filename.c_str(), CG_MODE_READ, &fileId ); - std::cout << "fileId = " << fileId << "\n"; - } - - int nbases = -1; - if ( Parallel::IsServer() ) - { - cg_nbases( fileId, &nbases ); - } - HXBcastData( &nbases, 1, Parallel::serverid ); - std::cout << "Parallel::pid = " << Parallel::pid << " "; - std::cout << "nbases = " << nbases << "\n"; - - for ( int iBase = 0; iBase < nbases; ++ iBase ) - { - char basename[ 33 ]; - int baseId = iBase + 1; - int icelldim = -1; - int iphysdim = -1; - if ( Parallel::IsServer() ) - { - cg_base_read( fileId, baseId, basename, &icelldim, &iphysdim ); - } - - HXBcastData( &icelldim, 1, Parallel::serverid ); - HXBcastData( &iphysdim, 1, Parallel::serverid ); - std::cout << "Parallel::pid = " << Parallel::pid << " "; - std::cout << "icelldim = " << icelldim << " iphysdim = " << iphysdim << "\n"; - - Global::cell_dim = icelldim; - Global::phys_dim = iphysdim; - - int nzones = -1; - if ( Parallel::IsServer() ) - { - cg_nzones( fileId, baseId, &nzones ); - } - HXBcastData( &nzones, 1, Parallel::serverid ); - std::cout << "Parallel::pid = " << Parallel::pid << " "; - std::cout << "nzones = " << nzones << "\n"; - - for ( int iZone = 0; iZone < nzones; ++ iZone ) - { - int zoneId = iZone + 1; - int index_dim = -1; - if ( Parallel::IsServer() ) - { - cg_index_dim( fileId, baseId, zoneId, &index_dim ); - } - HXSendRecvData( &index_dim, 1, Parallel::serverid, ZoneState::GetProcID( iZone ) ); - - if ( ZoneState::IsValid( iZone ) ) - { - std::cout << "Parallel::pid = " << Parallel::pid << " "; - std::cout << "index_dim = " << index_dim << "\n"; - } - - std::vector isize; - char zonename[ 33 ]; - if ( Parallel::IsServer() ) - { - isize.resize( index_dim * 3 ); - cg_zone_read( fileId, baseId, zoneId, zonename, isize.data() ); - } - - if ( ZoneState::IsValid( iZone ) ) - { - isize.resize( index_dim * 3 ); - } - - HXSendRecvData( zonename, 33, Parallel::serverid, ZoneState::GetProcID( iZone ) ); - HXSendRecvData( isize.data(), index_dim * 3, Parallel::serverid, ZoneState::GetProcID( iZone ) ); - - if ( ZoneState::IsValid( iZone ) ) - { - std::cout << "Parallel::pid = " << Parallel::pid << " "; - std::cout << "zonename = " << zonename << "\n"; - - for ( int i = 0; i < isize.size(); ++ i ) - { - std::cout << "Parallel::pid = " << Parallel::pid << " "; - std::cout << "i = " << i << " isize = " << isize[ i ] << "\n"; - } - } - - std::vector irmin; - std::vector irmax; - int nNodes = 1; - if ( ZoneState::IsValid( iZone ) || Parallel::IsServer() ) - { - irmin.resize( index_dim ); - irmax.resize( index_dim ); - for ( int m = 0; m < index_dim; ++ m ) - { - /* lower range index */ - irmin[ m ] = 1; - /* upper range index of vertices */ - irmax[ m ] = isize[ m ]; - nNodes *= irmax[ m ]; - } - std::cout << "Parallel::pid = " << Parallel::pid << " "; - std::cout << "nNodes = " << nNodes << "\n"; - } - - ZoneType_t zoneType; - if ( Parallel::IsServer() ) - { - cg_zone_type( fileId, baseId, zoneId, &zoneType ); - } - HXSendRecvData( &zoneType, 1, Parallel::serverid, ZoneState::GetProcID( iZone ) ); - - if ( ZoneState::IsValid( iZone ) || Parallel::IsServer() ) - { - std::cout << "Parallel::pid = " << Parallel::pid << " "; - std::cout << "zoneType = " << zoneType << " ZoneTypeName = " << ZoneTypeName[ zoneType ] << "\n"; - } - - Zone * zone = nullptr; - if ( ZoneState::IsValid( iZone ) ) - { - zone = new Zone(); - Global::zones.push_back( zone ); - LocalZone::global_zoneids.push_back( iZone ); - LocalZone::nZones = LocalZone::global_zoneids.size(); - for ( int m = 0; m < index_dim; ++ m ) - { - zone->nijk.push_back( isize[ m ] ); - } - } - - Grid * grid = nullptr; - if ( ZoneState::IsValid( iZone ) ) - { - grid = new Grid(); - Global::grids.push_back( grid ); - } - - BaseZone baseZone; - - int gZoneId = -1; - if ( Parallel::IsServer() ) - { - baseZone.zone_name = zonename; - gZoneId = global_zone_names.FindBaseZone( baseZone ); - } - - HXSendRecvData( &gZoneId, 1, Parallel::serverid, ZoneState::GetProcID( iZone ) ); - - if ( ZoneState::IsValid( iZone ) || Parallel::IsServer() ) - { - std::cout << "Parallel::pid = " << Parallel::pid << " "; - std::cout << "gZoneId = " << gZoneId << "\n"; - } - - int ncoords = -1; - if ( Parallel::IsServer() ) - { - cg_ncoords( fileId, baseId, zoneId, &ncoords ); - } - HXSendRecvData( &ncoords, 1, Parallel::serverid, ZoneState::GetProcID( iZone ) ); - if ( ZoneState::IsValid( iZone ) || Parallel::IsServer() ) - { - std::cout << "Parallel::pid = " << Parallel::pid << " "; - std::cout << "ncoords = " << ncoords << "\n"; - } - - for ( int icoord = 0; icoord < ncoords; ++ icoord ) - { - int coorId = icoord + 1; - DataType_t dataType; - char coordname[ 33 ]; - if ( Parallel::IsServer() ) - { - cg_coord_info( fileId, baseId, zoneId, coorId, &dataType, coordname ); - } - HXSendRecvData( coordname, 33, Parallel::serverid, ZoneState::GetProcID( iZone ) ); - HXSendRecvData( &dataType, 1, Parallel::serverid, ZoneState::GetProcID( iZone ) ); - if ( ZoneState::IsValid( iZone ) || Parallel::IsServer() ) - { - std::cout << "Parallel::pid = " << Parallel::pid << " "; - std::cout << "coordname = " << coordname << "\n"; - std::cout << "Parallel::pid = " << Parallel::pid << " "; - std::cout << "dataType = " << dataType << " DataTypeName = " << DataTypeName[ dataType ] << "\n"; - } - - std::vector coord; - - if ( ZoneState::IsValid( iZone ) || Parallel::IsServer() ) - { - coord.resize( nNodes * sizeof( double ) ); - } - - if ( Parallel::IsServer() ) - { - cg_coord_read( fileId, baseId, zoneId, coordname, dataType, irmin.data(), irmax.data(), coord.data() ); - } - - HXSendRecvData( coord.data(), coord.size(), Parallel::serverid, ZoneState::GetProcID( iZone ) ); - - Coor * coor = nullptr; - if ( ZoneState::IsValid( iZone ) ) - { - coor = new Coor(); - zone->coors.push_back( coor ); - coor->coorname = coordname; - coor->nNodes = nNodes; - coor->coord = coord; - - std::cout << "Parallel::pid = " << Parallel::pid << " "; - coor->DumpCoor(); - - if ( icoord == 0 ) - { - grid->Allocate( nNodes ); - coor->DumpCoorX( grid->x ); - } - } - } - - int nbocos = -1; - if ( Parallel::IsServer() ) - { - cg_nbocos( fileId, baseId, zoneId, &nbocos ); - } - HXSendRecvData( &nbocos, 1, Parallel::serverid, ZoneState::GetProcID( iZone ) ); - - if ( ZoneState::IsValid( iZone ) || Parallel::IsServer() ) - { - std::cout << "Parallel::pid = " << Parallel::pid << " "; - std::cout << "nbocos = " << nbocos << "\n"; - } - - for ( int iboco = 0; iboco < nbocos; ++ iboco ) - { - int bccoId = iboco + 1; - GridLocation_t location; - if ( Parallel::IsServer() ) - { - cg_boco_gridlocation_read( fileId, baseId, zoneId, bccoId, &location ); - } - HXSendRecvData( &location, 1, Parallel::serverid, ZoneState::GetProcID( iZone ) ); - - if ( ZoneState::IsValid( iZone ) || Parallel::IsServer() ) - { - std::cout << "Parallel::pid = " << Parallel::pid << " "; - std::cout << "iboco = " << iboco << " location = " << location << " GridLocationName = " << GridLocationName[location] << "\n"; - } - - char boconame[ 33 ]; - BCType_t bocotype; - PointSetType_t ptset_type; - cgsize_t npnts = 0; - //std::vector normalIndex( index_dim, -1 ); - std::vector normalIndex; - cgsize_t normalListSize = 0; - DataType_t normalDataType; - int ndataset = -1; - if ( Parallel::IsServer() ) - { - normalIndex.resize( index_dim ); - cg_boco_info( fileId, baseId, zoneId, bccoId, boconame, &bocotype, &ptset_type, - &npnts, normalIndex.data(), &normalListSize, &normalDataType, &ndataset ); - } - - if ( ZoneState::IsValid( iZone ) ) - { - normalIndex.resize( index_dim ); - } - - HXSendRecvData( boconame, 33, Parallel::serverid, ZoneState::GetProcID( iZone ) ); - HXSendRecvData( &bocotype, 1, Parallel::serverid, ZoneState::GetProcID( iZone ) ); - HXSendRecvData( &ptset_type, 1, Parallel::serverid, ZoneState::GetProcID( iZone ) ); - HXSendRecvData( &npnts, 1, Parallel::serverid, ZoneState::GetProcID( iZone ) ); - HXSendRecvData( &normalDataType, 1, Parallel::serverid, ZoneState::GetProcID( iZone ) ); - HXSendRecvData( &normalListSize, 1, Parallel::serverid, ZoneState::GetProcID( iZone ) ); - HXSendRecvData( normalIndex.data(), index_dim, Parallel::serverid, ZoneState::GetProcID( iZone ) ); - HXSendRecvData( &ndataset, 1, Parallel::serverid, ZoneState::GetProcID( iZone ) ); - - if ( ZoneState::IsValid( iZone ) || Parallel::IsServer() ) - { - std::cout << "Parallel::pid = " << Parallel::pid << " "; - std::cout << "boconame = " << boconame << " bocotype = " << bocotype << " BCTypeName = " << BCTypeName[ bocotype ] << "\n"; - std::cout << "Parallel::pid = " << Parallel::pid << " "; - std::cout << "ptset_type = " << ptset_type << " PointSetTypeName = " << PointSetTypeName[ptset_type] << "\n"; - std::cout << "Parallel::pid = " << Parallel::pid << " "; - std::cout << "npnts = " << npnts << "\n"; - std::cout << "Parallel::pid = " << Parallel::pid << " "; - std::cout << "normalListSize = " << normalListSize << "\n"; - std::cout << "Parallel::pid = " << Parallel::pid << " "; - std::cout << "normalDataType = " << normalDataType << " DataTypeName = " << DataTypeName[ normalDataType ] << "\n"; - std::cout << "Parallel::pid = " << Parallel::pid << " "; - std::cout << "normalIndex = "; - for ( int i = 0; i < index_dim; ++ i ) - { - std::cout << normalIndex[ i ] << " "; - } - std::cout << "\n"; - std::cout << "Parallel::pid = " << Parallel::pid << " "; - std::cout << "ndataset = " << ndataset << "\n"; - } - - std::vector normalList; - std::vector pnts; - - if ( ZoneState::IsValid( iZone ) || Parallel::IsServer() ) - { - if ( normalDataType == DataTypeNull ) - { - normalList.resize( sizeof( int ) ); - } - else - { - int nSize = nNodes * index_dim * sizeof( double ); - normalList.resize( nSize ); - } - pnts.resize( npnts * index_dim ); - } - - if ( Parallel::IsServer() ) - { - cg_boco_read( fileId, baseId, zoneId, bccoId, pnts.data(), normalList.data() ); - } - - HXSendRecvData( pnts.data(), npnts * index_dim, Parallel::serverid, ZoneState::GetProcID( iZone ) ); - - if ( ZoneState::IsValid( iZone ) || Parallel::IsServer() ) - { - std::cout << "Parallel::pid = " << Parallel::pid << " "; - std::cout << "pnts = "; - for ( int i = 0; i < pnts.size(); ++ i ) - { - std::cout << pnts[ i ] << " "; - } - std::cout << "\n"; - } - HXSendRecvData( normalList.data(), normalList.size(), Parallel::serverid, ZoneState::GetProcID(iZone)); - - ZoneBc * zonebc = nullptr; - if ( ZoneState::IsValid( iZone ) ) - { - zonebc = new ZoneBc(); - zone->bccos.push_back( zonebc ); - zonebc->bcType = bocotype; - for ( int i = 0; i < pnts.size(); ++ i ) - { - zonebc->pnts.push_back( pnts[ i ] ); - } - } - } - int n1to1 = -1; - if ( Parallel::IsServer() ) - { - cg_n1to1( fileId, baseId, zoneId, &n1to1 ); - } - - HXSendRecvData( &n1to1, 1, Parallel::serverid, ZoneState::GetProcID( iZone ) ); - - if ( ZoneState::IsValid( iZone ) || Parallel::IsServer() ) - { - std::cout << "Parallel::pid = " << Parallel::pid << " "; - std::cout << "n1to1 = " << n1to1 << "\n"; - } - - for ( int i1to1 = 0; i1to1 < n1to1; ++ i1to1 ) - { - int i1to1Id = i1to1 + 1; - - char connectname[ 33 ]; - char donorname[ 33 ]; - cgsize_t npnts = 2; - std::vector range; - std::vector donor_range; - std::vector transform; - if ( ZoneState::IsValid( iZone ) || Parallel::IsServer() ) - { - range.resize( npnts * index_dim ); - donor_range.resize( npnts * index_dim ); - transform.resize( index_dim ); - } - - if ( Parallel::IsServer() ) - { - cg_1to1_read( fileId, baseId, zoneId, i1to1Id, connectname, donorname, range.data(), donor_range.data(), transform.data() ); - } - - HXSendRecvData( connectname, 33, Parallel::serverid, ZoneState::GetProcID( iZone ) ); - HXSendRecvData( donorname, 33, Parallel::serverid, ZoneState::GetProcID( iZone ) ); - HXSendRecvData( range.data(), range.size(), Parallel::serverid, ZoneState::GetProcID( iZone ) ); - HXSendRecvData( donor_range.data(), donor_range.size(), Parallel::serverid, ZoneState::GetProcID( iZone ) ); - HXSendRecvData( transform.data(), transform.size(), Parallel::serverid, ZoneState::GetProcID( iZone ) ); - - if ( ZoneState::IsValid( iZone ) || Parallel::IsServer() ) - { - std::cout << "Parallel::pid = " << Parallel::pid << " "; - std::cout << "connectname = " << connectname << "\n"; - std::cout << "Parallel::pid = " << Parallel::pid << " "; - std::cout << "donorname = " << donorname << "\n"; - - std::cout << "Parallel::pid = " << Parallel::pid << " "; - std::cout << "range = "; - for ( int i = 0; i < range.size(); ++ i ) - { - std::cout << range[ i ] << " "; - } - std::cout << "\n"; - std::cout << "Parallel::pid = " << Parallel::pid << " "; - std::cout << "donor_range = "; - for ( int i = 0; i < donor_range.size(); ++ i ) - { - std::cout << donor_range[ i ] << " "; - } - std::cout << "\n"; - - std::cout << "Parallel::pid = " << Parallel::pid << " "; - std::cout << "transform = "; - for ( int i = 0; i < transform.size(); ++ i ) - { - std::cout << transform[ i ] << " "; - } - std::cout << "\n"; - } - - int gDonorZoneId = -1; - if ( Parallel::IsServer() ) - { - BaseZone baseZoneDonor; - baseZoneDonor.zone_name = donorname; - - gDonorZoneId = global_zone_names.FindBaseZone( baseZoneDonor ); - } - - HXSendRecvData( &gDonorZoneId, 1, Parallel::serverid, ZoneState::GetProcID( iZone ) ); - - ZoneBc1To1 * zonebc_1to1 = nullptr; - if ( ZoneState::IsValid( iZone ) ) - { - zonebc_1to1 = new ZoneBc1To1(); - zone->bc1to1s.push_back( zonebc_1to1 ); - zonebc_1to1->zoneid = gZoneId; - zonebc_1to1->transform = transform; - zonebc_1to1->donor_zoneid = gDonorZoneId; - - for ( int i = 0; i < range.size(); ++ i ) - { - zonebc_1to1->pnts.push_back( range[ i ] ); - zonebc_1to1->donor_pnts.push_back( donor_range[ i ] ); - } - } - } - } - } - - { - std::cout << "Parallel::pid = " << Parallel::pid << " "; - std::cout << "Global::zones.size() = " << Global::zones.size() << "\n"; - } - - cg_close( fileId ); -} \ No newline at end of file diff --git a/example/1d-linear-convection/eno3/cpp/01/CgnsUtil.h b/example/1d-linear-convection/eno3/cpp/01/CgnsUtil.h deleted file mode 100644 index dba4a529..00000000 --- a/example/1d-linear-convection/eno3/cpp/01/CgnsUtil.h +++ /dev/null @@ -1,50 +0,0 @@ -#pragma once -#include -#include -#include - -class BaseZone -{ -public: - //int baseId; - std::string zone_name; - bool operator < ( const BaseZone & rhs ) const - { - //if ( this->baseId != rhs.baseId ) - //{ - // return this->baseId < rhs.baseId; - //} - - return this->zone_name < rhs.zone_name; - } -}; - -class BaseZoneList -{ -public: - std::map basezone_map; -public: - void AddBaseZone( const BaseZone & baseZone ) - { - std::map::iterator iter; - iter = basezone_map.find( baseZone ); - if ( iter == basezone_map.end() ) - { - int id = basezone_map.size(); - basezone_map.insert( std::make_pair( baseZone, id ) ); - } - } - - int FindBaseZone( const BaseZone & baseZone ) - { - std::map::iterator iter = basezone_map.find( baseZone ); - if ( iter != basezone_map.end() ) - { - return iter->second; - } - return -1; - } -}; - -void ReadCgnsGridBaseZone( const std::string & filename ); -void ReadCgnsGrid( const std::string & filename ); \ No newline at end of file diff --git a/example/1d-linear-convection/eno3/cpp/01/ConvectionField.cpp b/example/1d-linear-convection/eno3/cpp/01/ConvectionField.cpp deleted file mode 100644 index 4a4eddfb..00000000 --- a/example/1d-linear-convection/eno3/cpp/01/ConvectionField.cpp +++ /dev/null @@ -1,287 +0,0 @@ -#include "ConvectionField.h" -#include "Weno.h" -#include "Eno.h" -#include "hxmath.h" -#include "Grid.h" -#include "Global.h" -#include "cgnslib.h" -#include -#include -#include - -void ConvectionField::InitFieldCommon( Grid * grid ) -{ - this->grid = grid; - this->nequ = Global::nequ; - this->ni = grid->ni; - this->nic = grid->nic; - grid->CalcMetrics(); - if ( Global::ifinite_volume == 1 ) - { - this->nx = this->nic; - } - else - { - // finite difference - this->nx = this->ni; - } - - Vec1d & x = grid->x; - this->dx = std::abs( x[ 1 ] - x[ 0 ] ); - this->dt = Global::dt; - this->nt = std::round( Global::total_time / dt ); - - std::print( "ni={}\n", ni ); - std::print( "dt={}\n", dt ); - std::print( "dx={}\n", dx ); - std::print( "nt={}\n", nt ); - std::cout << "this->dt = " << this->dt << "\n"; - std::cout << "this->nt = " << this->nt << "\n"; - std::cout << "this->ni = " << this->ni << "\n"; - std::cout << "nt * dt = " << nt * dt << "\n"; - - Global::nt = nt; - - int ist = 0 - Global::nghost; - int ied = this->nx - 1 + Global::nghost; - - this->u.Allocate( this->nequ, ist, ied ); - this->un.Allocate( this->nequ, ist, ied ); - this->res.Allocate( this->nequ, 0, this->nx ); //N+1 - - this->c = 1.0; -} - -void ConvectionField::InitFieldAsRestart( Grid * grid ) -{ - Vec1d &u = this->u.vec(); - - if ( Global::ifinite_volume == 0 ) - { - //node - Vec1d & x = grid->x; - for ( int i = 0; i < ni; ++ i ) - { - if ( x[ i ] >= 0.5 && x[ i ] <= 1.0 ) - { - u[ i ] = 2; - } - else - { - u[ i ] = 1; - } - } - } - else - { - //cell center - Vec1d & xcc = grid->xcc; - - for ( int i = 0; i < nic; ++ i ) - { - if ( xcc[ i ] >= 0.5 && xcc[ i ] <= 1.0 ) - { - u[ i ] = 2; - } - else - { - u[ i ] = 1; - } - } - } -} - -void ConvectionField::ReadFlowField( std::fstream & file, Grid * grid ) -{ - if ( Global::ifinite_volume == 1 ) - { - this->ReadFlowField( file, grid->xcc, u ); - } - else - { - this->ReadFlowField( file, grid->x, u ); - } -} - -void ConvectionField::ReadFlowField( std::fstream & file, Vec1d & x, VecWrap & u ) -{ - for ( int i = 0; i < x.size(); ++ i ) - { - std::string line; - std::getline( file, line ); - std::stringstream ss( line ); - std::string item; - std::vector row; - while ( std::getline(ss, item, ' ') ) - { - row.push_back( item ); - } - double um = std::atof( row[ 1 ].data() ); - this->u[ 0 ][ i ] = um; - } - int kkk = 1; -} - -void ConvectionField::FTCS( Zone * zone ) -{ - this->Rhs( this->u, this->res ); - for ( int m = 0; m < nequ; ++ m ) - { - Vec1d & u = this->u.vec( m ); - Vec1d & res = this->res.vec( m ); - for ( int i = 0; i < nx; ++ i ) - { - u[ i ] = u[ i ] + dt * res[ i ]; - } - } -} - -void ConvectionField::CN( Zone * zone ) -{ - double rr = 0.5 * this->alpha * dt / ( dx * dx ); - for ( int m = 0; m < nequ; ++ m ) - { - Vec1d & u = this->u.vec( m ); - - std::vector a( ni ); - std::vector b( ni ); - std::vector c( ni ); - std::vector d( ni ); - - for ( int i = 0; i < nx; ++ i ) - { - a[ i ] = - rr; - b[ i ] = 1.0 + 2.0 * rr; - c[ i ] = - rr; - } - - for ( int i = 0; i < nx; ++ i ) - { - d[ i ] = rr * u[ i - 1 ] + ( 1.0 - 2.0 * rr ) * u[ i ] + rr * u[ i + 1 ]; - } - - double uleft = u[ -1 ] + 2 * rr * ( u[ - 1 ] - 2 * u[ 0 ] + u[ 1 ] ); - double uright = u[ nx ] + 2 * rr * ( u[ nx - 2 ] - 2 * u[ nx - 1 ] + u[ nx ] ); - - d[ 0 ] -= a[ 0 ] * uleft; - d[ nx - 1 ] -= c[ nx - 1 ] * uright; - - std::vector values( d.size() ); - - thomas_algorithm( a, b, c, d, values ); - - for ( int i = 0; i < nx; ++ i ) - { - u[ i ] = values[ i ]; - } - } -} - -void ConvectionField::UpdateOldField() -{ - this->un = this->u; -} - -void ConvectionField::InviscidResidual( VecWrap & u, VecWrap & res ) -{ - if ( Global::iconservation == 0 ) - { - this->InviscidNonConservative( u, res ); - } - else - { - this->InviscidConservative( u, res ); - } -} - -void ConvectionField::InviscidNonConservative( VecWrap & u, VecWrap & res ) -{ - VecWrap uL, uR; - uL.Allocate( this->nequ, 0, nx, 0 ); - uR.Allocate( this->nequ, 0, nx, 0 ); - - if ( Global::scheme.reconstruction == to_int( BasicScheme::CRWENO ) ) - { - crwenoL( nx, u, uL ); - crwenoR( nx, u, uR ); - } - else if ( Global::scheme.reconstruction == to_int( BasicScheme::WENO ) ) - { - wenoL( nx, u, uL ); - wenoR( nx, u, uR ); - } - else if ( Global::scheme.reconstruction == to_int( BasicScheme::ENO ) ) - { - enoL( nx, u, uL ); - enoR( nx, u, uR ); - } - else if ( Global::scheme.reconstruction == to_int( BasicScheme::UpWind1 ) ) - { - Upwind1L( nx, u, uL ); - Upwind1R( nx, u, uR ); - } - - for ( int m = 0; m < nequ; ++ m ) - { - Vec1d & u = this->u.vec( m ); - Vec1d & res = this->res.vec( m ); - Vec1d & u_L = uL.vec( m ); - Vec1d & u_R = uR.vec( m ); - double cp = 0.5 * ( c + std::abs( c ) ); - double cn = 0.5 * ( c - std::abs( c ) ); - for ( int i = 0; i < nx; ++ i ) - { - double fip = cp * u_L[ i + 1 ] + cn * u_R[ i + 1 ]; - double fim = cp * u_L[ i ] + cn * u_R[ i ]; - res[ i ] += - ( fip - fim ) / dx; - } - } -} - -void ConvectionField::InviscidConservative( VecWrap & u, VecWrap & res ) -{ -} - -void ConvectionField::ViscousResidual( VecWrap & u, VecWrap & res ) -{ - //double coef = this->alpha / ( dx * dx ); - //for ( int m = 0; m < nequ; ++ m ) - //{ - // Vec1d & u = this->u.vec( m ); - // Vec1d & res = this->res.vec( m ); - // for ( int i = 0; i < ni; ++ i ) - // { - // res[ i ] += coef * ( u[ i + 1 ] - 2.0 * u[ i ] + u[ i - 1 ] ); - // } - //} -} -void ConvectionField::Rhs( VecWrap & u, VecWrap & res ) -{ - res = 0; - InviscidResidual( u, res ); - ViscousResidual( u, res ); -} - -void ConvectionField::DumpField( Grid * grid ) -{ - this->DumpField( grid->x, u ); -} - -void ConvectionField::PostProcess( Grid * grid ) -{ - this->DumpField( grid->x, u ); -} - -void ConvectionField::DumpField( Vec1d & x, VecWrap & u ) -{ - for ( int i = 0; i < x.size(); ++ i ) - { - Global::file_string += std::format( "{:.25f}", x[ i ] ); - for ( int m = 0; m < nequ; ++ m ) - { - Vec1d & u = this->u.vec( m ); - Global::file_string += std::format( " {:.25f}", u[ i ] ); - } - Global::file_string += std::format( "\n" ); - } -} \ No newline at end of file diff --git a/example/1d-linear-convection/eno3/cpp/01/ConvectionField.h b/example/1d-linear-convection/eno3/cpp/01/ConvectionField.h deleted file mode 100644 index ef8848e2..00000000 --- a/example/1d-linear-convection/eno3/cpp/01/ConvectionField.h +++ /dev/null @@ -1,33 +0,0 @@ -#pragma once -#include -#include "Vec1d.h" -#include "Field.h" - -class ConvectionField : public Field -{ -public: - int nt; - double dx; - double c; - double alpha, beta; -public: - void InitFieldCommon( Grid * grid ) override; - void InitFieldAsRestart( Grid * grid ) override; - void ReadFlowField( std::fstream & file, Grid * grid ) override; - void ReadFlowField( std::fstream & file, Vec1d & x, VecWrap & u ); -public: - void FTCS( Zone * zone ); - void CN( Zone * zone ); -public: - void Rhs( VecWrap & u, VecWrap & res ); - void InviscidResidual( VecWrap & u, VecWrap & res ); - void InviscidNonConservative( VecWrap & u, VecWrap & res ); - void InviscidConservative( VecWrap & u, VecWrap & res ); - void ViscousResidual( VecWrap & u, VecWrap & res ); - void UpdateOldField(); -public: - void DumpField( Grid * grid ); - void PostProcess( Grid * grid ); - void DumpField( Vec1d & x, VecWrap & u ); -}; - diff --git a/example/1d-linear-convection/eno3/cpp/01/Eno.cpp b/example/1d-linear-convection/eno3/cpp/01/Eno.cpp deleted file mode 100644 index deae576a..00000000 --- a/example/1d-linear-convection/eno3/cpp/01/Eno.cpp +++ /dev/null @@ -1,135 +0,0 @@ -#include "Eno.h" - -//std::vector> enocoef = { -// { 11.0/6, -7.0/6, 1.0/3 } -// { 1.0/3, 5.0/6, -1.0/6 }, -// { -1.0/6, 5.0/6, 1.0/3 }, -// { 1.0/3, -7.0/6, 11.0/6 } -//}; - -std::vector> enocoef = { - { 3.0/2, -1.0/2 }, - { 1.0/2, 1.0/2 }, - { -1.0/2, 3.0/2 } -}; - -void enoL( int N, Vec1d & u, Vec1d & f ) -{ - int ighost = 3; - int iorder = 2; - int ist = 0 - ighost; - int ied = N - 1 + ighost; - - VecWrap dd; - dd.Allocate( iorder, ist, ied, 0 ); - - std::vector ir( N + 1 ); - - for ( int j = -ighost; j < N + ighost; ++j ) - { - dd[ 0 ][ j ] = u[ j ]; - } - - for ( int i = 1; i < iorder; ++ i ) - { - for ( int j = -ighost; j < N + ighost - 1; ++j ) - { - dd[ i ][ j ] = dd[ i - 1 ][ j + 1 ] - dd[ i - 1 ][ j ]; - } - } - - for ( int j = 0; j <= N; ++ j ) - { - ir[ j ] = j; - for ( int i = 1; i < iorder; ++ i ) - { - if ( std::abs( dd[ i ][ ir[ j ] - 1 ] ) <= std::abs( dd[ i ][ ir[ j ] ] ) ) - { - ir[ j ] = ir[ j ] - 1; - } - } - } - - // reconstruction u(j+1_2) - for ( int i = 0; i <= N; ++ i ) - { - int kk = ir[ i ]; - int l = i - kk; - int L = l + 1; - f[ i ] = 0; - for ( int m = 0; m < iorder; ++ m ) - { - f[ i ] += u[ kk + m ] * enocoef[ L ][ m ]; - } - } -} - -void enoR( int N, Vec1d & u, Vec1d & f ) -{ - int ighost = 3; - int iorder = 2; - int ist = 0 - ighost; - int ied = N - 1 + ighost; - - VecWrap dd; - dd.Allocate( iorder, ist, ied, 0 ); - - std::vector ir( N + 1 ); - - for ( int j = -ighost; j < N + ighost; ++j ) - { - dd[ 0 ][ j ] = u[ j ]; - } - - for ( int i = 1; i < iorder; ++ i ) - { - for ( int j = -ighost; j < N + ighost - 1; ++j ) - { - dd[ i ][ j ] = dd[ i - 1 ][ j + 1 ] - dd[ i - 1 ][ j ]; - } - } - - for ( int j = 0; j <= N; ++ j ) - { - ir[ j ] = j + 1; - for ( int i = 1; i < iorder; ++ i ) - { - if ( std::abs( dd[ i ][ ir[ j ] - 1 ] ) <= std::abs( dd[ i ][ ir[ j ] ] ) ) - { - ir[ j ] = ir[ j ] - 1; - } - } - } - - // reconstruction u(j+1_2) - for ( int i = 0; i <= N; ++ i ) - { - int kk = ir[ i ]; - int l = i - kk; - int L = l + 1; - f[ i ] = 0; - for ( int m = 0; m < iorder; ++ m ) - { - f[ i ] += u[ kk + m ] * enocoef[ L ][ m ]; - } - } -} - -void enoL( int ni, VecWrap & u, VecWrap & f ) -{ - int nequ = u.get_nequ(); - for ( int m = 0; m < nequ; ++ m ) - { - enoL( ni, u.vec( m ), f.vec( m ) ); - } -} - -void enoR( int ni, VecWrap & u, VecWrap & f ) -{ - int nequ = u.get_nequ(); - for ( int m = 0; m < nequ; ++ m ) - { - enoR( ni, u.vec( m ), f.vec( m ) ); - } -} - diff --git a/example/1d-linear-convection/eno3/cpp/01/Eno.h b/example/1d-linear-convection/eno3/cpp/01/Eno.h deleted file mode 100644 index 7b2c1c11..00000000 --- a/example/1d-linear-convection/eno3/cpp/01/Eno.h +++ /dev/null @@ -1,7 +0,0 @@ -#pragma once -#include "Vec1d.h" - -void enoL( int N, Vec1d & u, Vec1d & f ); -void enoR( int N, Vec1d & u, Vec1d & f ); -void enoL( int ni, VecWrap & u, VecWrap & f ); -void enoR( int ni, VecWrap & u, VecWrap & f ); \ No newline at end of file diff --git a/example/1d-linear-convection/eno3/cpp/01/EulerField.cpp b/example/1d-linear-convection/eno3/cpp/01/EulerField.cpp deleted file mode 100644 index fa1ef8ca..00000000 --- a/example/1d-linear-convection/eno3/cpp/01/EulerField.cpp +++ /dev/null @@ -1,818 +0,0 @@ -#include "EulerField.h" -#include "Weno.h" -#include "hxmath.h" -#include "Global.h" -#include "Grid.h" -#include "cgnslib.h" -#include -#include -#include -#include -#include - -void EulerField::InitFieldCommon( Grid * grid ) -{ - this->grid = grid; - this->nequ = Global::nequ; - this->ni = grid->ni; - this->nic = grid->nic; - grid->CalcMetrics(); - if ( Global::ifinite_volume == 1 ) - { - this->nx = this->nic; - } - else - { - // finite difference - this->nx = this->ni; - } - - Vec1d & x = grid->x; - this->dx = std::abs( x[ 1 ] - x[ 0 ] ); - this->dt = Global::dt; - this->nt = std::round( Global::total_time / dt ); - - std::print( "ni={}\n", ni ); - std::print( "dt={}\n", dt ); - std::print( "dx={}\n", dx ); - std::print( "nt={}\n", nt ); - std::cout << "this->dt = " << this->dt << "\n"; - std::cout << "this->nt = " << this->nt << "\n"; - std::cout << "this->ni = " << this->ni << "\n"; - std::cout << "nt * dt = " << nt * dt << "\n"; - - Global::nt = nt; - - int ist = 0 - Global::nghost; - int ied = this->nx - 1 + Global::nghost; - - this->u.Allocate( this->nequ, ist, ied ); - this->un.Allocate( this->nequ, ist, ied ); - this->res.Allocate( this->nequ, 0, this->nx ); //N+1 - - gamma = 1.4; // specific gas ratio -} - -void EulerField::InitFieldAsRestart( Grid * grid ) -{ - this->InitSodShockTube( grid ); -} - -void EulerField::InitSodShockTube( Grid * grid ) -{ - //Sod's Riemann problem - // Left side - double rhoL = 1.0; - double uL = 0.0; - double pL = 1.0; - // Right side - double rhoR = 0.125; - double uR = 0.0; - double pR = 0.1; - - double xc = 0.5; //seperator location - - if ( Global::ifinite_volume == 0 ) - { - } - else - { - //cell center - Vec1d & xcc = grid->xcc; - Vec1d & q0 = this->u.vec( 0 ); - Vec1d & q1 = this->u.vec( 1 ); - Vec1d & q2 = this->u.vec( 2 ); - - double rho, u, p, e; - //i=0,1,...,nx-1 - for ( int i = 0; i < nic; ++ i ) - { - if ( xcc[ i ] > xc ) - { - rho = rhoR; - u = uR; - p = pR; - } - else - { - rho = rhoL; - u = uL; - p = pL; - } - e = p / ( rho * ( gamma - 1.0 ) ) + 0.5 * u * u; - - //conservative variables - q0[ i ] = rho; - q1[ i ] = rho * u; - q2[ i ] = rho * e; - } - } - - int kkk = 1; -} - -void EulerField::ReadFlowField( std::fstream & file, Grid * grid ) -{ - if ( Global::ifinite_volume == 1 ) - { - this->ReadFlowField( file, grid->xcc, u ); - } - else - { - this->ReadFlowField( file, grid->x, u ); - } -} - -void EulerField::ReadFlowField( std::fstream & file, Vec1d & x, VecWrap & u ) -{ - for ( int i = 0; i < x.size(); ++ i ) - { - std::string line; - std::getline( file, line ); - std::stringstream ss( line ); - std::string item; - std::vector row; - while ( std::getline(ss, item, ' ') ) - { - row.push_back( item ); - } - double rho = std::atof( row[ 1 ].data() ); - double rhou = std::atof( row[ 2 ].data() ); - double rhoe = std::atof( row[ 3 ].data() ); - this->u[ 0 ][ i ] = rho; - this->u[ 1 ][ i ] = rhou; - this->u[ 2 ][ i ] = rhoe; - if ( std::isnan( rho ) ) - { - int kkk = 1; - } - } - int kkk = 1; -} - -void EulerField::InviscidResidual( VecWrap & u, VecWrap & res ) -{ - this->InviscidConservative( u, res ); -} - -void EulerField::WaveSpeed( VecWrap & qL, VecWrap & qR, Vec1d & ps ) -{ - //spectral radius of Jacobian - double gm1 = gamma - 1.0; - for ( int i = 0; i <= nx; ++ i ) - { - // left state - double rhoL = qL[ 0 ][ i ]; - double uL = qL[ 1 ][ i ] / rhoL; - double eL = qL[ 2 ][ i ] / rhoL; - double pL = gm1 * ( rhoL * eL - 0.5 * rhoL * ( uL * uL ) ); - double hL = eL + pL / rhoL; - - // Right state; - double rhoR = qR[ 0 ][ i ]; - double uR = qR[ 1 ][ i ] / rhoR; - double eR = qR[ 2 ][ i ] / rhoR; - double pR = gm1 * ( rhoR * eR - 0.5 * rhoR * ( uR * uR ) ); - double hR = eR + pR / rhoR; - - double alpha = 1.0 / ( std::sqrt( std::abs( rhoL ) ) + std::sqrt( std::abs( rhoR ) ) ); - - double ubar = ( std::sqrt( std::abs( rhoL ) ) * uL + std::sqrt( std::abs( rhoR ) ) * uR ) * alpha; - double hbar = ( std::sqrt( std::abs( rhoL ) ) * hL + std::sqrt( std::abs( rhoR ) ) * hR ) * alpha; - double cbar = std::sqrt( std::abs( gm1 * ( hbar - 0.5 * ubar * ubar ) ) ); - - ps[ i ] = std::abs( cbar + ubar ); - } - - for ( int i = ps.ist; i < 0; ++ i ) - { - ps[ i ] = ps[ 0 ]; - } - - for ( int i = nx + 1; i <= ps.ied; ++ i ) - { - ps[ i ] = ps[ nx ]; - } -} - -void EulerField::LaxWaveSpeed( VecWrap & q, Vec1d & ps ) -{ - //spectral radius of Jacobian - double gm1 = gamma - 1.0; - int ist = ps.ist; - int ied = ps.ied; - for ( int i = ist; i <= ied; ++ i ) - { - // left state - double rhom = q[ 0 ][ i ]; - double um = q[ 1 ][ i ] / rhom; - double em = q[ 2 ][ i ] / rhom; - double pm = gm1 * ( rhom * em - 0.5 * rhom * ( um * um ) ); - double hm = em + pm / rhom; - - double ubar = std::sqrt( std::abs( rhom ) ) * um; - double hbar = std::sqrt( std::abs( rhom ) ) * hm; - double cbar = std::sqrt( std::abs( gm1 * ( hbar - 0.5 * ubar * ubar ) ) ); - - ps[ i ] = std::abs( cbar + ubar ); - } -} - -void EulerField::LaxFriedrichs( VecWrap & u, VecWrap & res ) -{ - VecWrap fL, fR; - fL.Allocate( this->nequ, 0, nx, 0 ); - fR.Allocate( this->nequ, 0, nx, 0 ); - - int ist = 0 - Global::nghost; - int ied = this->nx - 1 + Global::nghost; - - VecWrap f, fP, fN; - - f.Allocate( this->nequ, ist, ied, 0 ); - fP.Allocate( this->nequ, ist, ied, 0 ); - fN.Allocate( this->nequ, ist, ied, 0 ); - - euler_fluxes( ist, ied, u, f ); - - Vec1d ps; - ps.Allocate( ist, ied, 0 ); - LaxWaveSpeed( u, ps ); - - // left and right side fluxes at the interface - for ( int m = 0; m < nequ; ++ m ) - { - for ( int i = ist; i <= ied; ++ i ) - { - fP[ m ][ i ] = 0.5 * ( f[ m ][ i ] + ps[ i ] * u[ m ][ i ] ); - fN[ m ][ i ] = 0.5 * ( f[ m ][ i ] - ps[ i ] * u[ m ][ i ] ); - } - } - - if ( Global::scheme.reconstruction == to_int( BasicScheme::CRWENO ) ) - { - crwenoL( nx, fP, fL ); - crwenoR( nx, fN, fR ); - } - else if ( Global::scheme.reconstruction == to_int( BasicScheme::WENO ) ) - { - wenoL( nx, fP, fL ); - wenoR( nx, fN, fR ); - } - - for ( int m = 0; m < nequ; ++ m ) - { - Vec1d & FL = fL.vec( m ); - Vec1d & FR = fR.vec( m ); - Vec1d & res = this->res.vec( m ); - for ( int i = 0; i < nx; ++ i ) - { - res[ i ] -= ( FL[ i + 1 ] - FL[ i ] ) / dx + ( FR[ i + 1 ] - FR[ i ] ) / dx; - } - } - -} - -//Calculate fluxes -void EulerField::euler_fluxes( int ist, int ied, VecWrap & q, VecWrap & f ) -{ - //i=0,1,...,nx - for ( int i = ist; i <= ied; ++ i ) - { - double rho = q[ 0 ][ i ]; - double rhou = q[ 1 ][ i ]; - double rhoe = q[ 2 ][ i ]; - double p = ( gamma - 1.0 ) * ( rhoe - 0.5 * SQR( rhou ) / rho ); - f[ 0 ][ i ] = rhou; - f[ 1 ][ i ] = rhou * rhou / rho + p; - f[ 2 ][ i ] = rhou * rhoe / rho + p * rhou / rho; - if ( std::isnan( rho ) ) - { - int kkk = 1; - } - - } -} - -void EulerField::rusanov_flux( VecWrap & qL, VecWrap & qR, VecWrap & fL, VecWrap & fR, VecWrap & f ) -{ - Vec1d ps; - ps.Allocate( 0, nx, 0 ); - - WaveSpeed( qL, qR, ps ); - - for ( int m = 0; m < nequ; ++ m ) - { - for ( int i = 0; i <= nx; ++ i ) - { - //Interface fluxes (Rusanov) - f[ m ][ i ] = 0.5 * ( fR[ m ][ i ] + fL[ m ][ i ] ) - 0.5 * ps[ i ] * ( qR[ m ][ i ] - qL[ m ][ i ] ); - } - } -} - -void EulerField::hllc_flux( VecWrap & qL, VecWrap & qR, VecWrap & fL, VecWrap & fR, VecWrap & f ) -{ - std::vector Ds( 3, 0 ); - double gm = gamma - 1.0; - - // i=0,1,...,nx - for ( int i = 0; i <= nx; ++ i ) - { - //left state - double rhoL = qL[ 0 ][ i ]; - double uL = qL[ 1 ][ i ] / rhoL; - double eL = qL[ 2 ][ i ] / rhoL; - double pL = gm * ( rhoL * eL - 0.5 * rhoL * ( uL * uL ) ); - double hL = eL + pL / rhoL; - double cL = std::sqrt( std::abs( gamma * pL / rhoL ) ); - - //right state - double rhoR = qR[ 0 ][ i ]; - double uR = qR[ 1 ][ i ] / rhoR; - double eR = qR[ 2 ][ i ] / rhoR; - double pR = gm * ( rhoR * eR - 0.5 * rhoR * ( uR * uR ) ); - double hR = eR + pR / rhoR; - double cR = std::sqrt( std::abs( gamma * pR / rhoR ) ); - - //compute SL and Sr - double SL = std::min( uL, uR ) - std::max( cL, cR ); - double SR = std::max( uL, uR ) + std::max( cL, cR ); - - //compute compound speed - double term1 = pR - pL + rhoL * uL * ( SL - uL ) - rhoR * uR * ( SR - uR ); - double term2 = rhoL * ( SL - uL ) - rhoR * ( SR - uR ); - double SP = term1 / term2; //never get zero; - - //compute compound pressure - double PLR = 0.5 * ( pL + pR + rhoL * ( SL - uL ) * ( SP - uL ) + rhoR * ( SR - uR ) * ( SP - uR ) ); - - //compute D - Ds[ 0 ] = 0.0; - Ds[ 1 ] = 1.0; - Ds[ 2 ] = SP; - - if ( std::isnan( fL[ 0 ][ i ] ) || std::isnan( fR[ 0 ][ i ] ) ) - { - int kkk = 1; - } - - if ( SL >= 0.0 ) - { - for ( int m = 0; m < nequ; ++ m ) - { - f[ m ][ i ] = fL[ m ][ i ]; - } - } - else if ( SR <= 0.0 ) - { - for ( int m = 0; m < nequ; ++ m ) - { - f[ m ][ i ] = fR[ m ][ i ]; - } - } - else if ( ( SP >= 0.0 ) && ( SL <= 0.0 ) ) - { - for ( int m = 0; m < nequ; ++ m ) - { - f[ m ][ i ] = ( SP * ( SL * qL[ m ][ i ] - fL[ m ][ i ] ) + SL * PLR * Ds[ m ] ) / ( SL - SP ); - } - } - else if ( ( SP <= 0.0 ) && ( SR >= 0.0 ) ) - { - for ( int m = 0; m < nequ; ++ m ) - { - f[ m ][ i ] = ( SP * ( SR * qR[ m ][ i ] - fR[ m ][ i ] ) + SR * PLR * Ds[ m ] ) / ( SR - SP ); - } - } - } -} - -void EulerField::roe_flux( VecWrap & qL, VecWrap & qR, VecWrap & fL, VecWrap & fR, VecWrap & f ) -{ - std::vector dd( 3, 0 ); - std::vector dF( 3, 0 ); - std::vector dQ( 3, 0 ); - double gm = gamma - 1.0; - - // i=0,1,...,nx - for ( int i = 0; i <= nx; ++ i ) - { - //Left and right states: - double rhoL = qL[ 0 ][ i ]; - double uL = qL[ 1 ][ i ] / rhoL; - double eL = qL[ 2 ][ i ] / rhoL; - double pL = gm * ( rhoL * eL - 0.5 * rhoL * ( uL * uL ) ); - double hL = eL + pL / rhoL; - - double rhoR = qR[ 0 ][ i ]; - double uR = qR[ 1 ][ i ] / rhoR; - double eR = qR[ 2 ][ i ] / rhoR; - double pR = gm * ( rhoR * eR - 0.5 * rhoR * ( uR * uR ) ); - double hR = eR + pR / rhoR; - - double alpha = 1.0 / ( std::sqrt( std::abs( rhoL ) ) + std::sqrt( std::abs( rhoR ) ) ); - - double uu = ( std::sqrt( std::abs( rhoL ) ) * uL + std::sqrt( std::abs( rhoR ) ) * uR ) * alpha; - double hh = ( std::sqrt( std::abs( rhoL ) ) * hL + std::sqrt( std::abs( rhoR ) ) * hR ) * alpha; - double aa = std::sqrt( std::abs( gm * ( hh - 0.5 * uu * uu ) ) ); - - double D11 = std::abs( uu ); - double D22 = std::abs( uu + aa ); - double D33 = std::abs( uu - aa ); - - double beta = 0.5 / ( aa * aa ); - double phi2 = 0.5 * gm * uu * uu; - - //Right eigenvector matrix - double R11 = 1.0; - double R21 = uu; - double R31 = phi2 / gm; - double R12 = beta; - double R22 = beta * ( uu + aa ); - double R32 = beta * ( hh + uu * aa ); - double R13 = beta; - double R23 = beta * ( uu - aa ); - double R33 = beta * ( hh - uu * aa ); - - //Left eigenvector matrix - double L11 = 1.0 - phi2 / ( aa * aa ); - double L12 = gm * uu / ( aa * aa ); - double L13 = -gm / ( aa * aa ); - - double L21 = phi2 - uu * aa; - double L22 = - gm * uu + aa; - double L23 = gm; - - double L31 = phi2 + uu * aa; - double L32 = - gm * uu - aa; - double L33 = gm; - - for ( int m = 0; m < nequ; ++ m ) - { - dQ[ m ] = qR[ m ][ i ] - qL[ m ][ i ]; - } - - dd[ 0 ] = D11 * ( L11 * dQ[ 0 ] + L12 * dQ[ 1 ] + L13 * dQ[ 2 ] ); - dd[ 1 ] = D22 * ( L21 * dQ[ 0 ] + L22 * dQ[ 1 ] + L23 * dQ[ 2 ] ); - dd[ 2 ] = D33 * ( L31 * dQ[ 0 ] + L32 * dQ[ 1 ] + L33 * dQ[ 2 ] ); - - dF[ 0 ] = R11 * dd[ 0 ] + R12 * dd[ 1 ] + R13 * dd[ 2 ]; - dF[ 1 ] = R21 * dd[ 0 ] + R22 * dd[ 1 ] + R23 * dd[ 2 ]; - dF[ 2 ] = R31 * dd[ 0 ] + R32 * dd[ 1 ] + R33 * dd[ 2 ]; - - for ( int m = 0; m < nequ; ++ m ) - { - //Interface fluxes (Roe) - f[ m ][ i ] = 0.5 * ( fR[ m ][ i ] + fL[ m ][ i ] ) - 0.5 * dF[ m ]; - } - } -} - -void EulerField::Hllc( VecWrap & u, VecWrap & res ) -{ - VecWrap uL, uR; - uL.Allocate( this->nequ, 0, nx, 0 ); - uR.Allocate( this->nequ, 0, nx, 0 ); - - //WENO Reconstruction - if ( Global::scheme.reconstruction == to_int( BasicScheme::CRWENO ) ) - { - crwenoL( nx, u, uL ); - crwenoR( nx, u, uR ); - } - else if ( Global::scheme.reconstruction == to_int( BasicScheme::WENO ) ) - { - wenoL( nx, u, uL ); - wenoR( nx, u, uR ); - } - - //left and right side fluxes at the interface - VecWrap fL, fR; - fL.Allocate( this->nequ, 0, nx, 0 ); - fR.Allocate( this->nequ, 0, nx, 0 ); - - int ist = 0 - Global::nghost; - int ied = this->nx - 1 + Global::nghost; - - //Computing fluxes - euler_fluxes( 0, nx, uL, fL ); - euler_fluxes( 0, nx, uR, fR ); - - //fluxes at the interface - VecWrap f; - f.Allocate( this->nequ, 0, nx, 0 ); - - //compute Riemann solver using Roe scheme(flux at interface) - hllc_flux( uL, uR, fL, fR, f ); - - //Interface fluxes (Rusanov) - for ( int m = 0; m < nequ; ++ m ) - { - for ( int i = 0; i < nx; ++ i ) - { - res[ m ][ i ] -= ( f[ m ][ i + 1 ] - f[ m ][ i ] ) / dx; - if ( std::isnan( res[ m ][ i ] ) ) - { - int kkk = 1; - } - } - } -} - -void EulerField::Roe( VecWrap & u, VecWrap & res ) -{ - VecWrap uL, uR; - uL.Allocate( this->nequ, 0, nx, 0 ); - uR.Allocate( this->nequ, 0, nx, 0 ); - - //WENO Reconstruction - if ( Global::scheme.reconstruction == to_int( BasicScheme::CRWENO ) ) - { - crwenoL( nx, u, uL ); - crwenoR( nx, u, uR ); - } - else if ( Global::scheme.reconstruction == to_int( BasicScheme::WENO ) ) - { - wenoL( nx, u, uL ); - wenoR( nx, u, uR ); - } - - //left and right side fluxes at the interface - VecWrap fL, fR; - fL.Allocate( this->nequ, 0, nx, 0 ); - fR.Allocate( this->nequ, 0, nx, 0 ); - - int ist = 0 - Global::nghost; - int ied = this->nx - 1 + Global::nghost; - - //Computing fluxes - euler_fluxes( 0, nx, uL, fL ); - euler_fluxes( 0, nx, uR, fR ); - - //fluxes at the interface - VecWrap f; - f.Allocate( this->nequ, 0, nx, 0 ); - - //compute Riemann solver using Roe scheme(flux at interface) - roe_flux( uL, uR, fL, fR, f ); - - //Interface fluxes (Rusanov) - for ( int m = 0; m < nequ; ++ m ) - { - for ( int i = 0; i < nx; ++ i ) - { - res[ m ][ i ] -= ( f[ m ][ i + 1 ] - f[ m ][ i ] ) / dx; - } - } - -} - -void EulerField::Rusanov( VecWrap & u, VecWrap & res ) -{ - VecWrap uL, uR; - uL.Allocate( this->nequ, 0, nx, 0 ); - uR.Allocate( this->nequ, 0, nx, 0 ); - - //WENO Reconstruction - if ( Global::scheme.reconstruction == to_int( BasicScheme::CRWENO ) ) - { - crwenoL( nx, u, uL ); - crwenoR( nx, u, uR ); - } - else if ( Global::scheme.reconstruction == to_int( BasicScheme::WENO ) ) - { - wenoL( nx, u, uL ); - wenoR( nx, u, uR ); - } - - //left and right side fluxes at the interface - VecWrap fL, fR; - fL.Allocate( this->nequ, 0, nx, 0 ); - fR.Allocate( this->nequ, 0, nx, 0 ); - - int ist = 0 - Global::nghost; - int ied = this->nx - 1 + Global::nghost; - - //Computing fluxes - euler_fluxes( 0, nx, uL, fL ); - euler_fluxes( 0, nx, uR, fR ); - - //fluxes at the interface - VecWrap f; - f.Allocate( this->nequ, 0, nx, 0 ); - - //compute Riemann solver using HLLC scheme - rusanov_flux( uL, uR, fL, fR, f ); - - //Interface fluxes (Rusanov) - for ( int m = 0; m < nequ; ++ m ) - { - for ( int i = 0; i < nx; ++ i ) - { - res[ m ][ i ] -= ( f[ m ][ i + 1 ] - f[ m ][ i ] ) / dx; - } - } - -} - -void EulerField::InviscidConservative( VecWrap & u, VecWrap & res ) -{ - if ( Global::scheme.inviscid == to_int( BasicScheme::HLLC ) ) - { - this->Hllc( u, res ); - } - else if ( Global::scheme.inviscid == to_int( BasicScheme::LAX ) ) - { - this->LaxFriedrichs( u, res ); - } - else if ( Global::scheme.inviscid == to_int( BasicScheme::Roe ) ) - { - this->Roe( u, res ); - } - else if ( Global::scheme.inviscid == to_int( BasicScheme::Rusanov ) ) - { - this->Rusanov( u, res ); - } - } - -void EulerField::ViscousResidual( VecWrap & u, VecWrap & res ) -{ - ; -} - -void EulerField::Rhs( VecWrap & u, VecWrap & res ) -{ - res = 0; - InviscidResidual( u, res ); - if ( Global::iviscous > 0 ) - { - ViscousResidual( u, res ); - } - } - -void EulerField::UpdateOldField() -{ - this->un = this->u; -} - -void EulerField::DumpField( Grid * grid ) -{ - if ( Global::ifinite_volume == 1 ) - { - this->DumpField( grid->xcc, u ); - } - else - { - this->DumpField( grid->x, u ); - } -} - -void EulerField::PostProcess( Grid * grid ) -{ - if ( Global::ifinite_volume == 1 ) - { - this->DumpField( grid->xcc, u ); - } - else - { - this->DumpField( grid->x, u ); - } -} - -//void EulerField::DumpField( Vec1d & x, VecWrap & u ) -//{ -// for ( int i = 0; i < x.size(); ++ i ) -// { -// Global::file_string += std::format( "{:.25f}", x[ i ] ); -// for ( int m = 0; m < nequ; ++ m ) -// { -// Vec1d & u = this->u.vec( m ); -// Global::file_string += std::format( " {:.25f}", u[ i ] ); -// } -// Global::file_string += std::format( "\n" ); -// } -//} - -void EulerField::DumpField( Vec1d & x, VecWrap & u ) -{ - for ( int i = 0; i < x.size(); ++ i ) - { - Global::file_string += std::format( "{:.25f}", x[ i ] ); - double rho = u[ 0 ][ i ]; - double rhou = u[ 1 ][ i ]; - double rhoe = u[ 2 ][ i ]; - double um = rhou / rho; - Global::file_string += std::format( " {:.25f}", rho ); - Global::file_string += std::format( " {:.25f}", rhou ); - Global::file_string += std::format( " {:.25f}", rhoe ); - Global::file_string += std::format( " {:.25f}", um ); - - Global::file_string += std::format( "\n" ); - } -} - -void EulerField::Boundary( Region ®ion, int bcType ) -{ - if ( bcType == BCInflow ) - { - this->InflowBc( region ); - } - else if ( bcType == BCExtrapolate || bcType == BCOutflow ) - { - this->OutflowBc( region ); - } -} - -void EulerField::InflowBc( Region ®ion ) -{ - int index_dim = region.start.size(); - if ( index_dim != 1 ) return; - int st = region.start[ 0 ]; - int ed = region.end[ 0 ]; - - for ( int i = st; i <= ed; ++ i ) - { - int idir = 1; - int ib = i - 1; //index from 0 - if ( i == 1 ) - { - idir = -1; - } - else - { - ib -= Global::ifinite_volume; - } - int in = ib; - int ig1 = ib + idir; - - for ( int m = 0; m < nequ; ++ m ) - { - u[ m ][ ig1 ] = u[ m ][ in ]; - } - - if ( Global::nghost >= 2 ) - { - int ig2 = ig1 + idir; - for ( int m = 0; m < nequ; ++ m ) - { - u[ m ][ ig2 ] = u[ m ][ in ]; - } - - if ( Global::nghost >= 3 ) - { - int ig3 = ig2 + idir; - for ( int m = 0; m < nequ; ++ m ) - { - u[ m ][ ig3 ] = u[ m ][ in ]; - } - } - } - } -} - -void EulerField::OutflowBc( Region ®ion ) -{ - int index_dim = region.start.size(); - if ( index_dim != 1 ) return; - int st = region.start[ 0 ]; - int ed = region.end[ 0 ]; - for ( int i = st; i <= ed; ++ i ) - { - int idir = 1; - int ib = i - 1; //index from 0 - if ( i == 1 ) - { - idir = -1; - } - else - { - ib -= Global::ifinite_volume; - } - int in = ib; - int ig1 = ib + idir; - - for ( int m = 0; m < nequ; ++ m ) - { - u[ m ][ ig1 ] = u[ m ][ in ]; - } - - if ( Global::nghost >= 2 ) - { - int ig2 = ig1 + idir; - for ( int m = 0; m < nequ; ++ m ) - { - u[ m ][ ig2 ] = u[ m ][ in ]; - } - - if ( Global::nghost >= 3 ) - { - int ig3 = ig2 + idir; - for ( int m = 0; m < nequ; ++ m ) - { - u[ m ][ ig3 ] = u[ m ][ in ]; - } - } - } - } -} \ No newline at end of file diff --git a/example/1d-linear-convection/eno3/cpp/01/EulerField.h b/example/1d-linear-convection/eno3/cpp/01/EulerField.h deleted file mode 100644 index 7e71cfdc..00000000 --- a/example/1d-linear-convection/eno3/cpp/01/EulerField.h +++ /dev/null @@ -1,45 +0,0 @@ -#pragma once -#include "Vec1d.h" -#include "Field.h" -#include - -class EulerField : public Field -{ -public: - int nt; - double dx; - double gamma; -public: - void InitFieldCommon( Grid * grid ) override; - void InitFieldAsRestart( Grid * grid ) override; - void ReadFlowField( std::fstream & file, Grid * grid ) override; - void ReadFlowField( std::fstream & file, Vec1d & x, VecWrap & u ); - void InitSodShockTube( Grid * grid ); -public: - void Rhs( VecWrap & u, VecWrap & res ); - void InviscidResidual( VecWrap & u, VecWrap & res ); - void ViscousResidual( VecWrap & u, VecWrap & res ); - void InviscidConservative( VecWrap & u, VecWrap & res ); - void WaveSpeed( VecWrap & qL, VecWrap & qR, Vec1d & ps ); - void LaxWaveSpeed( VecWrap & q, Vec1d & ps ); -public: - void Hllc( VecWrap & u, VecWrap & res ); - void LaxFriedrichs( VecWrap & u, VecWrap & res ); - void Roe( VecWrap & u, VecWrap & res ); - void Rusanov( VecWrap & u, VecWrap & res ); - void euler_fluxes( int ist, int ied, VecWrap & u, VecWrap & f ); - void hllc_flux( VecWrap & qL, VecWrap & qR, VecWrap & fL, VecWrap & fR, VecWrap & f ); - void roe_flux( VecWrap & qL, VecWrap & qR, VecWrap & fL, VecWrap & fR, VecWrap & f ); - void rusanov_flux( VecWrap & qL, VecWrap & qR, VecWrap & fL, VecWrap & fR, VecWrap & f ); -public: - void UpdateOldField(); - void DumpField( Grid * grid ); - void PostProcess( Grid * grid ); - void DumpField( Vec1d & x, VecWrap & u ); -public: - void Boundary( Region & region, int bcType ); - void InflowBc( Region & region ); - void OutflowBc( Region & region ); -}; - - diff --git a/example/1d-linear-convection/eno3/cpp/01/Field.cpp b/example/1d-linear-convection/eno3/cpp/01/Field.cpp deleted file mode 100644 index e18c65a4..00000000 --- a/example/1d-linear-convection/eno3/cpp/01/Field.cpp +++ /dev/null @@ -1,342 +0,0 @@ -#include "Field.h" -#include "hxmath.h" -#include "Grid.h" -#include "Global.h" -#include "cgnslib.h" -#include -#include - -void Field::CrankNicolsonSeries( Zone * zone ) -{ - BasicScheme time_scheme = to_BasicScheme( Global::scheme.time_scheme ); - switch ( time_scheme ) { - case BasicScheme::CN: - this->CN( zone ); - break; - case BasicScheme::ICP: - this->ICP( zone ); - break; - default: - this->CN( zone ); - } -} - -void Field::RungeKutta( Zone * zone, int nStage, int istage ) -{ - if ( nStage == 1 ) - { - this->RungeKutta1( zone, istage ); - } - else if ( nStage == 3 ) - { - this->RungeKutta3( zone, istage ); - } -} - -void Field::RungeKutta1( Zone * zone, int istage ) -{ - this->RungeKutta3Stage0( zone ); -} - -void Field::RungeKutta3( Zone * zone, int istage ) -{ - if ( istage == 0 ) - { - this->RungeKutta3Stage0( zone ); - return; - } - - if ( istage == 1 ) - { - this->RungeKutta3Stage1( zone ); - return; - } - - if ( istage == 2 ) - { - this->RungeKutta3Stage2( zone ); - return; - } -} - -void Field::RungeKutta3Stage0( Zone * zone ) -{ - this->Rhs( this->u, this->res ); - for ( int m = 0; m < nequ; ++ m ) - { - Vec1d & u = this->u.vec( m ); - Vec1d & res = this->res.vec( m ); - for ( int i = 0; i < this->nx; ++ i ) - { - u[ i ] = u[ i ] + dt * res[ i ]; - } - } -} - -void Field::RungeKutta3Stage1( Zone * zone ) -{ - this->Rhs( this->u, this->res ); - for ( int m = 0; m < nequ; ++ m ) - { - Vec1d & u = this->u.vec( m ); - Vec1d & un = this->un.vec( m ); - Vec1d & res = this->res.vec( m ); - for ( int i = 0; i < this->nx; ++ i ) - { - u[ i ] = 0.75 * un[ i ] + 0.25 * u[ i ] + 0.25 * dt * res[ i ]; - } - } -} - -void Field::RungeKutta3Stage2( Zone * zone ) -{ - this->Rhs( this->u, this->res ); - - double c1 = 1.0 / 3.0; - double c2 = 2.0 / 3.0; - double c3 = 2.0 / 3.0; - for ( int m = 0; m < nequ; ++ m ) - { - Vec1d & u = this->u.vec( m ); - Vec1d & un = this->un.vec( m ); - Vec1d & res = this->res.vec( m ); - - for ( int i = 0; i < this->nx; ++ i ) - { - u[ i ] = c1 * un[ i ] + c2 * u[ i ] + c3 * dt * res[ i ]; - } - } -} - -void Field::PhysicalBoundary( Zone * zone ) -{ - int nbccos = zone->bccos.size(); - for ( int ibcco = 0; ibcco < nbccos; ++ ibcco ) - { - ZoneBc * zonebc = zone->bccos[ ibcco ]; - Region region; - region.SetRegion( zonebc->pnts ); - Boundary( region, zonebc->bcType ); - } -} - -void Field::InterfaceBoundary( Zone * zone ) -{ - int nbc1to1s = zone->bc1to1s.size(); - - for ( int ibc1to1 = 0; ibc1to1 < nbc1to1s; ++ ibc1to1 ) - { - ZoneBc1To1 * bc1to1 = zone->bc1to1s[ ibc1to1 ]; - Region region; - region.SetRegion( bc1to1->pnts ); - this->InterfaceBc( region ); - } -} - -void Field::Boundary( Region ®ion, int bcType ) -{ - if ( bcType == BCInflow ) - { - this->InflowBc( region ); - } - else if ( bcType == BCOutflow ) - { - this->OutflowBc( region ); - } - else if ( bcType == BCExtrapolate ) - { - this->ExtrapolateBc( region ); - } - else if ( bcType == BCDirichlet ) - { - this->DirichletBc( region ); - } -} - -void Field::DirichletBc( Region ®ion ) -{ - int index_dim = region.start.size(); - if ( index_dim != 1 ) return; - int st = region.start[ 0 ]; - int ed = region.end[ 0 ]; - - Vec1d & u = this->u.vec(); - - for ( int i = st; i <= ed; ++ i ) - { - int idir = 1; - int ib = i - 1; //index from 0 - if ( i == 1 ) - { - idir = -1; - } - else - { - ib -= Global::ifinite_volume; - } - int in = ib - idir; - - int ig1 = ib + idir; - double ub = 0.0; - double uin = u[ in ]; - - if ( Global::ifinite_volume == 0 ) - { - u[ ib ] = ub; - } - - u[ ig1 ] = 2.0 * ub - 1.0 * uin; - - if ( Global::nghost >= 2 ) - { - int ig2 = ig1 + idir; - u[ ig2 ] = 3.0 * ub - 2.0 * uin; - if ( Global::nghost >= 3 ) - { - int ig3 = ig2 + idir; - u[ ig3 ] = 4.0 * ub - 3.0 * uin; - } - } - } -} - -void Field::InflowBc( Region ®ion ) -{ - int index_dim = region.start.size(); - if ( index_dim != 1 ) return; - int st = region.start[ 0 ]; - int ed = region.end[ 0 ]; - - Vec1d & u = this->u.vec(); - - for ( int i = st; i <= ed; ++ i ) - { - int idir = 1; - int ib = i - 1; //index from 0 - if ( i == 1 ) - { - idir = -1; - } - else - { - ib -= Global::ifinite_volume; - } - int in = ib - idir; - - int ig1 = ib + idir; - double ub = 0.0; - double uin = u[ in ]; - - if ( Global::ifinite_volume == 0 ) - { - u[ ib ] = ub; - } - - u[ ig1 ] = 2.0 * ub - 1.0 * uin; - - if ( Global::nghost >= 2 ) - { - int ig2 = ig1 + idir; - u[ ig2 ] = 3.0 * ub - 2.0 * uin; - if ( Global::nghost >= 3 ) - { - int ig3 = ig2 + idir; - u[ ig3 ] = 4.0 * ub - 3.0 * uin; - } - } - } -} - -void Field::OutflowBc( Region ®ion ) -{ - int index_dim = region.start.size(); - if ( index_dim != 1 ) return; - int st = region.start[ 0 ]; - int ed = region.end[ 0 ]; - Vec1d & u = this->u.vec(); - for ( int i = st; i <= ed; ++ i ) - { - int idir = 1; - int ib = i - 1; //index from 0 - if ( i == 1 ) - { - idir = -1; - } - else - { - ib -= Global::ifinite_volume; - } - int in = ib; - int ig1 = ib + idir; - double uin = u[ in ]; - - u[ ig1 ] = uin; - - if ( Global::nghost >= 2 ) - { - int ig2 = ig1 + idir; - u[ ig2 ] = uin; - if ( Global::nghost >= 3 ) - { - int ig3 = ig2 + idir; - u[ ig3 ] = uin; - } - } - } -} - -void Field::ExtrapolateBc( Region ®ion ) -{ - int index_dim = region.start.size(); - if ( index_dim != 1 ) return; - int st = region.start[ 0 ]; - int ed = region.end[ 0 ]; - - Vec1d & u = this->u.vec(); - - for ( int i = st; i <= ed; ++ i ) - { - int idir = 1; - int ib = i - 1; //index from 0 - if ( i == 1 ) - { - idir = -1; - } - else - { - ib -= Global::ifinite_volume; - } - int in = ib; - - int ig1 = ib + idir; - double uin = u[ in ]; - - u[ ig1 ] = uin; - - if ( Global::nghost >= 2 ) - { - int ig2 = ig1 + idir; - u[ ig2 ] = uin; - if ( Global::nghost >= 3 ) - { - int ig3 = ig2 + idir; - u[ ig3 ] = uin; - } - } - } -} - -void Field::InterfaceBc( Region & region ) -{ - //int index_dim = region.start.size(); - //if ( index_dim != 1 ) return; - //int st = region.start[ 0 ]; - //int ed = region.end[ 0 ]; - //for ( int i = st; i <= ed; ++ i ) - //{ - // int ib = i - 1; //index from 0 - - // double value = 0.25 * ( 2 * this->u[ ib ] + this->u[ ib + 1 ] + this->u[ ib - 1 ] ); - // this->u[ ib ] = value; - //} -} \ No newline at end of file diff --git a/example/1d-linear-convection/eno3/cpp/01/Field.h b/example/1d-linear-convection/eno3/cpp/01/Field.h deleted file mode 100644 index ed1b3773..00000000 --- a/example/1d-linear-convection/eno3/cpp/01/Field.h +++ /dev/null @@ -1,54 +0,0 @@ -#pragma once -#include -#include -#include "Vec1d.h" - -class Zone; -class Grid; -class Region; - -class Field -{ -public: - Field() {} - virtual ~Field() {}; -public: - virtual void Init( std::fstream & file, Grid * grid ) {} - virtual void InitFieldCommon( Grid * grid ) {} - virtual void InitFieldAsRestart( Grid * grid ) {} - virtual void ReadFlowField( std::fstream & file, Grid * grid ) {} - virtual void UpdateOldField() {} - virtual void FTCS( Zone * zone ) {} - virtual void CrankNicolsonSeries( Zone * zone ); - virtual void CN( Zone * zone ) {}; - virtual void ICP( Zone * zone ) {} - virtual void DumpField( Grid * grid ) {} - virtual void PostProcess( Grid * grid ) {} - virtual void Rhs( Vec1d & u, Vec1d & r ) {}; - virtual void Rhs( VecWrap & u, VecWrap & r ) {}; -public: - void RungeKutta( Zone * zone, int nStage, int istage ); - void RungeKutta1( Zone * zone, int istage ); - void RungeKutta3( Zone * zone, int istage ); - void RungeKutta3Stage0( Zone * zone ); - void RungeKutta3Stage1( Zone * zone ); - void RungeKutta3Stage2( Zone * zone ); -public: - void PhysicalBoundary( Zone * zone ); - void InterfaceBoundary( Zone * zone ); - virtual void Boundary( Region & region, int bcType ); - virtual void InflowBc( Region & region ); - virtual void OutflowBc( Region & region ); - virtual void DirichletBc( Region & region ); - virtual void ExtrapolateBc( Region & region ); - virtual void InterfaceBc( Region & region ); -public: - Grid * grid; - VecWrap u, un; - VecWrap res; - int nequ = 1; - int ni ,nic; //nnode, ncell; - int nx; - double dt; -}; - diff --git a/example/1d-linear-convection/eno3/cpp/01/Global.cpp b/example/1d-linear-convection/eno3/cpp/01/Global.cpp deleted file mode 100644 index f6f55f50..00000000 --- a/example/1d-linear-convection/eno3/cpp/01/Global.cpp +++ /dev/null @@ -1,465 +0,0 @@ -#include "Global.h" -#include "Grid.h" -#include "ZoneState.h" -#include "Parallel.h" -#include - -std::vector Global::grids; -std::vector Global::fields; - -Scheme Global::scheme; -GoverningEquation Global::governing_equation; -int Global::istart = 0; -int Global::iviscous = 0; -int Global::iconservation = 1; -int Global::nsave = -1; -int Global::idump_initial_field = -1; -int Global::ifinite_volume = 1; -double Global::total_time = 0.0; -double Global::dt = 0.1; -int Global::nt = -1; -int Global::iter = -1; -int Global::iter_start = 0; -int Global::cell_dim = -1; -int Global::phys_dim = -1; -int Global::nghost = -1; -int Global::nequ = -1; -std::string Global::file_string=""; - -std::vector Global::zones; -std::vector Global::interfaces; - -std::map Global::faceMap; -std::map Global::facePairMap; -std::vector Global::facePairList; -std::vector Global::mpi_facePairList; - -std::vector> Global::donor_zone_sets; -std::vector> Global::donor_zones; - -InterfaceTopo Global::interfaceTopo; - -void PrintPidHeader() -{ - std::cout << "Parallel::pid = " << Parallel::pid << " "; -} - -void Scheme::read( const json & j ) -{ - this->set_inviscid_scheme( j[ "inviscid" ] ); - this->set_reconstruction_scheme( j[ "reconstruction" ] ); - this->set_viscous_scheme( j[ "viscous" ] ); - this->set_time_scheme( j[ "time" ] ); -} - -void Scheme::set_inviscid_scheme( const std::string & name ) -{ - if ( name == "center" ) - { - this->inviscid = to_int( BasicScheme::CENTER ); - } - else if ( name == "ftcs" ) - { - this->inviscid = to_int( BasicScheme::CENTER ); - } - else if ( name == "hllc" ) - { - this->inviscid = to_int( BasicScheme::HLLC ); - } - else if ( name == "lax" ) - { - this->inviscid = to_int( BasicScheme::LAX ); - } - else if ( name == "roe" ) - { - this->inviscid = to_int( BasicScheme::Roe ); - } - else if ( name == "rusanov" ) - { - this->inviscid = to_int( BasicScheme::Rusanov ); - } - else if ( name == "upwind1" ) - { - this->inviscid = to_int( BasicScheme::UpWind1 ); - } - else if ( name == "upwind2" ) - { - this->inviscid = to_int( BasicScheme::UpWind2 ); - } - else if ( name == "weno5" ) - { - this->inviscid = to_int( BasicScheme::WENO ); - } - else if ( name == "crweno5" ) - { - this->inviscid = to_int( BasicScheme::CRWENO ); - } - else - { - this->inviscid = to_int( BasicScheme::WENO ); - } -} - -void Scheme::set_reconstruction_scheme( const std::string & name ) -{ - if ( name == "eno3" ) - { - this->reconstruction = to_int( BasicScheme::ENO ); - } - else if ( name == "weno5" ) - { - this->reconstruction = to_int( BasicScheme::WENO ); - } - else if ( name == "crweno5" ) - { - this->reconstruction = to_int( BasicScheme::CRWENO ); - } - else if ( name == "upwind1" ) - { - this->reconstruction = to_int( BasicScheme::UpWind1 ); - } - else if ( name == "upwind2" ) - { - this->reconstruction = to_int( BasicScheme::UpWind2 ); - } -} - -void Scheme::set_viscous_scheme( const std::string & name ) -{ - if ( name == "center" ) - { - this->viscous = to_int( BasicScheme::CENTER ); - } - else - { - this->viscous = to_int( BasicScheme::CENTER ); - } -} - -void Scheme::set_time_scheme( const std::string & name ) -{ - if ( name == "cn" ) - { - this->time_scheme = to_int( BasicScheme::CN ); - } - else if ( name == "icp" ) - { - this->time_scheme = to_int( BasicScheme::ICP ); - } - else if ( name == "rk1" ) - { - this->time_scheme = to_int( BasicScheme::RK1 ); - } - else if ( name == "rk2" ) - { - this->time_scheme = to_int( BasicScheme::RK2 ); - } - else if ( name == "rk3" ) - { - this->time_scheme = to_int( BasicScheme::RK3 ); - } - else if ( name == "ftcs" ) - { - this->time_scheme = to_int( BasicScheme::RK1 ); - } - else - { - this->time_scheme = to_int( BasicScheme::RK1 ); - } -} - - -bool Face::operator < ( const Face & rhs ) const -{ - if ( this->zone != rhs.zone ) - { - return this->zone < rhs.zone; - } - - if ( this->i != rhs.i ) - { - return this->i < rhs.i; - } - - if ( this->j != rhs.j ) - { - return this->j < rhs.j; - } - - return this->k < rhs.k; -} - -bool Face::operator == ( const Face & rhs ) const -{ - if ( this->zone != rhs.zone ) - { - return false; - } - - if ( this->i != rhs.i ) - { - return false; - } - - if ( this->j != rhs.j ) - { - return false; - } - - return this->k == rhs.k; -} - -void Face::Print() -{ - std::cout << "(" << this->zone << "," << this->i << ")"; -} - -void FacePair::AddPair( const Face & face1, const Face & face2 ) -{ - if ( face1 < face2 ) - { - this->left = face1; - this->right = face2; - } - else - { - this->left = face2; - this->right = face1; - } -} - -bool FacePair::operator < ( const FacePair & rhs ) const -{ - if ( this->left == rhs.left || this->left == rhs.right ) - { - return false; - } - - return this->left < rhs.left; -} - -void FacePair::Print() -{ - this->left.Print(); - std::cout << " "; - this->right.Print(); - std::cout << "\n"; -} - -void InterfaceTopo::InitNeighborInfo() -{ - this->linkmap.resize( ZoneState::nZones ); - - for ( int iZone = 0; iZone < ZoneState::nZones; ++ iZone ) - { - if ( ! ZoneState::IsValid( iZone ) ) continue; - - int local_zoneid = ZoneState::g2lzoneids[ iZone ]; - - Interface * interface = Global::interfaces[ local_zoneid ]; - - std::vector & t = this->linkmap[ iZone ]; - t = interface->neighbor_donor_zones; - } -} - -void InterfaceTopo::SwapNeighborInfo() -{ - for ( int iZone = 0; iZone < ZoneState::nZones; ++ iZone ) - { - int pid = ZoneState::pids[ iZone ]; - - std::vector & donor_zones = this->linkmap[ iZone ]; - int nNeighbor = donor_zones.size(); - - HXBcastData( &nNeighbor, 1, pid ); - - donor_zones.resize( nNeighbor ); - - HXBcastData( donor_zones.data(), donor_zones.size(), pid ); - } - - this->SwapNeighborDonorfaces(); -} - -void InterfaceTopo::SwapNeighborDonorfaces() -{ - int gl = 0; - for ( int iZone = 0; iZone < ZoneState::nZones; ++ iZone ) - { - int send_pid = ZoneState::pids[ iZone ]; - - std::vector & donor_zones = this->linkmap[ iZone ]; - int ndonor_zones = donor_zones.size(); - - for ( int iNei = 0; iNei < ndonor_zones; ++ iNei ) - { - int donor_zone = donor_zones[ iNei ]; - int recv_pid = ZoneState::pids[ donor_zone ]; - int nInterFaces = 0; - std::vector donorfaces; - - if ( Parallel::pid == send_pid ) - { - int local_zoneid = ZoneState::g2lzoneids[ iZone ]; - - Interface * interface = Global::interfaces[ local_zoneid ]; - - std::vector> & neighbor_donorfaces = interface->neighbor_donorfaces; - - std::vector & neighbor_donorface = neighbor_donorfaces[ iNei ]; - - nInterFaces = neighbor_donorface.size(); - - donorfaces = neighbor_donorface; - } - - HXSendRecvData( &nInterFaces, 1, send_pid, recv_pid ); - - if ( Parallel::pid == recv_pid && send_pid != recv_pid ) - { - donorfaces.resize( nInterFaces ); - } - - HXSendRecvData( donorfaces.data(), donorfaces.size(), send_pid, recv_pid ); - - if ( Parallel::pid == recv_pid ) - { - int local_donor_zoneid = ZoneState::g2lzoneids[ donor_zone ]; - Interface * interface_recv = Global::interfaces[ local_donor_zoneid ]; - interface_recv->SendGeom( iZone, donorfaces ); - } - } - } -} - - -void Interface::CalcInterface( Transform * transform, std::vector & start, std::vector & end, int donor_zoneid ) -{ - int ist = start[ 0 ]; - int ied = end[ 0 ]; - int dim = start.size(); - std::vector index1( dim ); - std::vector index2( dim ); - - int icount = this->zoneList.size(); - for ( int i = ist; i <= ied; ++ i ) - { - int faceid = icount; - this->zoneList.push_back( donor_zoneid ); - this->local_faceids.push_back( faceid ); - index1[ 0 ] = i; - transform->MapIndex( index1, index2 ); - Face face; - face.zone = zoneid; - face.i = i; - - int i_donor = index2[ 0 ]; - - Face face_donor; - face_donor.zone = donor_zoneid; - face_donor.i = i_donor; - - FacePair facePair; - facePair.AddPair( face, face_donor ); - - Global::facePairList.push_back( facePair ); - int nSize = Global::facePairList.size(); - this->proc_global_faceids.push_back( nSize - 1 ); - - if ( i == 1 ) - { - //ig = 0: interface value - //ig=1,2,... ghost cell value - int ic = i; - for ( int ig = Global::ifinite_volume; ig <= Global::nghost; ++ ig ) - { - int iig = ig - Global::ifinite_volume; - ijk_ghosts.push_back( ic - ig ); - ijk_donors.push_back( ic + iig ); - } - } - else - { - //ig = 0: interface value - //ig=1,2,... ghost cell value - int ic = i - Global::ifinite_volume; - for ( int ig = Global::ifinite_volume; ig <= Global::nghost; ++ ig ) - { - int iig = ig - Global::ifinite_volume; - ijk_ghosts.push_back( ic + ig ); - ijk_donors.push_back( ic - iig ); - } - } - - icount ++; - } -} - -void Interface::SendGeom( int zone, std::vector & donorfaces ) -{ - Interface * interface = this; - - std::vector & send_to_zones = interface->send_to_zones; - - send_to_zones.push_back( zone ); - interface->donorfaces_for_send.push_back( donorfaces ); - - int nface = donorfaces.size(); - std::vector sub_donorijk; - int index_dim = 1; - int ngsize = ( Global::nghost + 1 - Global::ifinite_volume ); - for ( int i = 0; i < nface; ++ i ) - { - int global_faceid = donorfaces[ i ]; - int local_faceid = interface->global_local_face_map[ global_faceid ]; - int ijkpos = index_dim * local_faceid * ngsize; - - for ( int ig = Global::ifinite_volume; ig <= Global::nghost; ++ ig ) - { - int iig = ig - Global::ifinite_volume; - int i_donor_cell = interface->ijk_donors[ ijkpos + iig ]; - sub_donorijk.push_back( i_donor_cell ); - } - int kkk = 1; - } - - interface->donorijk_for_send.push_back( sub_donorijk ); - - int ndata = sub_donorijk.size() * Global::nequ; - - std::vector sub_donordata( ndata ); - interface->donordata_for_send.push_back( sub_donordata ); -} - -void Global::InsertFaceMap( const Face & face ) -{ - std::map::iterator iter; - iter = Global::faceMap.find( face ); - if ( iter == Global::faceMap.end() ) - { - int faceid = Global::faceMap.size(); - Global::faceMap.insert( std::make_pair( face, faceid ) ); - } -} - -int Global::InsertFacePairMap( const FacePair & facePair ) -{ - std::map::iterator iter; - iter = Global::facePairMap.find( facePair ); - if ( iter == Global::facePairMap.end() ) - { - int facePairId = Global::facePairMap.size(); - Global::facePairMap.insert( std::make_pair( facePair, facePairId ) ); - return facePairId; - } - return iter->second; -} - -void Global::AddFacePairList( std::vector & a, std::vector & b ) -{ - for ( int i = 0; i < b.size(); ++ i ) - { - a.push_back( b[ i ] ); - } -} diff --git a/example/1d-linear-convection/eno3/cpp/01/Global.h b/example/1d-linear-convection/eno3/cpp/01/Global.h deleted file mode 100644 index 55498419..00000000 --- a/example/1d-linear-convection/eno3/cpp/01/Global.h +++ /dev/null @@ -1,180 +0,0 @@ -#pragma once -#include "Vec1d.h" -#include -#include -#include -#include -#include -#include -#include -using json = nlohmann::json; - -class Face -{ -public: - int zone = 0; - int i = 0; - int j = 1; - int k = 1; -public: - bool operator < ( const Face & rhs ) const; - bool operator == ( const Face & rhs ) const; -public: - void Print(); -}; - -class FacePair -{ -public: - Face left; - Face right; -public: - bool operator < ( const FacePair & rhs ) const; - void AddPair( const Face &face1, const Face &face2); -public: - void Print(); -}; - -class Transform; - -class InterfaceTopo -{ -public: - std::vector> linkmap; -public: - void InitNeighborInfo(); - void SwapNeighborInfo(); - void SwapNeighborDonorfaces(); -}; - - -class Interface -{ -public: - int zoneid; - std::vector zoneList; - std::vector global_faceids; - std::vector mpi_global_faceids; - std::vector proc_global_faceids; - std::vector local_faceids; - std::vector ijk_ghosts; - std::vector ijk_donors; - std::vector data_recv; - std::vector data_send; - std::unordered_map global_local_face_map; -public: - std::vector neighbor_donor_zones; - std::vector> neighbor_donorfaces; - std::vector> sub_local_faceids; - std::vector send_to_zones; - std::vector> donorfaces_for_send; - std::vector> donorijk_for_send; - std::vector> donordata_for_send; -public: - void CalcInterface( Transform * transform, std::vector & start, std::vector & end, int donor_zoneid ); - void SendGeom( int zone, std::vector & donorfaces ); -}; - -class Field; -class InterFaceZone; -class Zone; -class Grid; - -enum class BasicScheme -{ - FTCS = 0, - CENTER, //Central Space - CN, //CrankCNicolson - ICP, //Implicit Compact Pade (ICP) Scheme - ENO, //Weighted Essentially Non-oscillatory - WENO, //Weighted Essentially Non-oscillatory - CRWENO, //Compact Reconstruction WENO-5 Scheme - HLLC,//HLLC scheme - LAX, //Lax-Friedrichs flux splitting - Roe, // - Rusanov, // - UpWind1, - UpWind2, - RungeKutta, - RK1, - RK2, - RK3 -}; - -enum class GoverningEquation -{ - Heat = 0, - LinearConvection, - Burgers, - Euler -}; - -template -int to_int( const T & t ) -{ - return static_cast( t ); -} - -template -BasicScheme to_BasicScheme( const T & t ) -{ - return static_cast( t ); -} - -class Scheme -{ -public: - int inviscid; - int viscous; - int time_scheme; - int reconstruction; -public: - void read( const json & j ); - void set_inviscid_scheme( const std::string & name ); - void set_reconstruction_scheme( const std::string & name ); - void set_viscous_scheme( const std::string & name ); - void set_time_scheme( const std::string & name ); -}; - -class Global -{ -public: - static std::vector grids; - static std::vector fields; -public: - static std::vector zones; - static std::vector interfaces; -public: - static std::map faceMap; - static std::map facePairMap; - static std::vector facePairList; - static std::vector mpi_facePairList; - static std::vector> donor_zone_sets; - static std::vector> donor_zones; - static InterfaceTopo interfaceTopo; -public: - static Scheme scheme; - static GoverningEquation governing_equation; - static double total_time; - static double dt; - static int istart; - static int iconservation; - static int iviscous; - static int nsave; - static int idump_initial_field; - static int ifinite_volume; - static int nt; - static int iter_start; - static int iter; - static int cell_dim; - static int phys_dim; - static int nghost; - static int nequ; - static std::string file_string; -public: - static void InsertFaceMap( const Face & face ); - static int InsertFacePairMap( const FacePair & facePair ); - static void AddFacePairList( std::vector & a, std::vector & b ); -}; - -void PrintPidHeader(); diff --git a/example/1d-linear-convection/eno3/cpp/01/Grid.cpp b/example/1d-linear-convection/eno3/cpp/01/Grid.cpp deleted file mode 100644 index e4f62efb..00000000 --- a/example/1d-linear-convection/eno3/cpp/01/Grid.cpp +++ /dev/null @@ -1,290 +0,0 @@ -#include "Grid.h" -#include "Vec1d.h" -#include -#include - -void Grid::Allocate( int nNodes ) -{ - this->ni = nNodes; - this->nic = nNodes - 1; //ncells - this->x.Allocate( 0, nNodes - 1 ); - this->xcc.Allocate( 0, this->nic - 1 ); //cell center; -} - -void Grid::CalcMetrics() -{ - for ( int i = 0; i < nic; ++ i ) - { - xcc[ i ] = 0.5 * ( x[ i ] + x[ i + 1 ] ); - } -} - -Region::Region() -{ -} - -Region::~Region() -{ -} - -Region & Region::operator = ( const Region & rhs ) -{ - if ( this == & rhs ) return * this; - - this->start = rhs.start; - this->end = rhs.end; - - return * this; -} - -void Region::SetRegion( std::vector & pnts ) -{ - int index_dim = pnts.size() / 2; - this->start.resize( index_dim ); - this->end.resize( index_dim ); - for ( int m = 0; m < index_dim; ++ m ) - { - this->start[ m ] = pnts[ m ]; - this->end[ m ] = pnts[ index_dim + m ]; - } -} - -void Region::Print() -{ - int nSize = this->start.size(); - std::cout << "start:("; - for ( int m = 0; m < nSize; ++ m ) - { - std::cout << this->start[ m ]; - if ( m != nSize - 1 ) - { - std::cout << ","; - } - } - std::cout << ")\n"; - std::cout << "end :("; - for ( int m = 0; m < nSize; ++ m ) - { - std::cout << this->end[ m ]; - if ( m != nSize - 1 ) - { - std::cout << ","; - } - } - std::cout << ")\n"; -} - -Coor::Coor() -{ - ; -} - -Coor::~Coor() -{ -} - -void Coor::DumpCoor() -{ - double * xd = reinterpret_cast( const_cast( coord.data() ) ); - for ( int i = 0; i < this->nNodes; ++ i ) - { - //std::cout << coord[i] << " "; - std::cout << xd[ i ] << " "; - if ( ( i + 1 ) % 5 == 0 ) std::cout << "\n"; - } - std::cout << "\n"; -} - -void Coor::DumpCoorX( Vec1d &x ) -{ - double * xd = reinterpret_cast( const_cast( coord.data() ) ); - for ( int i = 0; i < this->nNodes; ++ i ) - { - x[ i ] = xd[ i ]; - } -} - -ZoneBc::ZoneBc() -{ - ; -} - -ZoneBc::~ZoneBc() -{ -} - -ZoneBc1To1::ZoneBc1To1() -{ - ; -} - -ZoneBc1To1::~ZoneBc1To1() -{ -} - -Zone::Zone() -{ - ; -} - -Zone::~Zone() -{ - for ( int i = 0; i < bccos.size(); ++ i ) - { - delete bccos[ i ]; - } - - for ( int i = 0; i < coors.size(); ++ i ) - { - delete coors[ i ]; - } -} - -int Trans::M[ 3 ][ 3 ]; -std::vector Trans::transform; - -int Trans::sgn( int x ) -{ - if ( x >= 0 ) - { - return 1; - } - else - { - return -1; - } -} - -int Trans::del( int x, int y ) -{ - if ( std::abs( x ) == std::abs( y ) ) - { - return 1; - } - return 0; -} - -void Trans::ZeroMatrix() -{ - int dim = 3; - for ( int j = 0; j < dim; ++ j ) - { - for ( int i = 0; i < dim; ++ i ) - { - Trans::M[ i ][ j ] = 0; - } - } -} - -void Trans::CalcTransformMatrix() -{ - int dim = Trans::transform.size(); - if ( dim == 1 ) - { - int a = Trans::transform[ 0 ]; - int sgna = Trans::sgn( a ); - int a1 = Trans::del( a, 1 ); - Trans::M[ 0 ][ 0 ] = sgna * a1; - } - else if ( dim == 2 ) - { - int a = Trans::transform[ 0 ]; - int b = Trans::transform[ 1 ]; - int sgna = Trans::sgn( a ); - int sgnb = Trans::sgn( b ); - int a1 = Trans::del( a, 1 ); - int a2 = Trans::del( a, 2 ); - int b1 = Trans::del( b, 1 ); - int b2 = Trans::del( b, 2 ); - Trans::M[ 0 ][ 0 ] = sgna * a1; - Trans::M[ 1 ][ 0 ] = sgna * a2; - Trans::M[ 0 ][ 1 ] = sgnb * b1; - Trans::M[ 1 ][ 1 ] = sgnb * b2; - } - else if ( dim == 3 ) - { - int a = Trans::transform[ 0 ]; - int b = Trans::transform[ 1 ]; - int c = Trans::transform[ 2 ]; - int sgna = Trans::sgn( a ); - int sgnb = Trans::sgn( b ); - int sgnc = Trans::sgn( c ); - int a1 = Trans::del( a, 1 ); - int a2 = Trans::del( a, 2 ); - int a3 = Trans::del( a, 3 ); - int b1 = Trans::del( b, 1 ); - int b2 = Trans::del( b, 2 ); - int b3 = Trans::del( b, 3 ); - int c1 = Trans::del( c, 1 ); - int c2 = Trans::del( c, 2 ); - int c3 = Trans::del( c, 3 ); - Trans::M[ 0 ][ 0 ] = sgna * a1; - Trans::M[ 1 ][ 0 ] = sgna * a2; - Trans::M[ 2 ][ 0 ] = sgna * a3; - Trans::M[ 0 ][ 1 ] = sgnb * b1; - Trans::M[ 1 ][ 1 ] = sgnb * b2; - Trans::M[ 2 ][ 1 ] = sgnb * b3; - Trans::M[ 0 ][ 2 ] = sgnc * c1; - Trans::M[ 1 ][ 2 ] = sgnc * c2; - Trans::M[ 2 ][ 2 ] = sgnc * c3; - } -} - -Transform::Transform() -{ - //int dim = Dim::dim; - int dim = 1; - this->diff.resize( dim ); - this->mul.resize( dim ); -} - -Transform::~Transform() -{ - ; -} - -void Transform::Init() -{ - Trans::ZeroMatrix(); - Trans::transform = this->transform; - Trans::CalcTransformMatrix(); - - int dim = 3; - for ( int j = 0; j < dim; ++ j ) - { - for ( int i = 0; i < dim; ++ i ) - { - this->Mt[ i ][ j ] = Trans::M[ i ][ j ]; - } - } -} - -void Transform::MapIndex( std::vector & index1, std::vector & index2 ) -{ - int dim = index1.size(); - for ( int m = 0; m < dim; ++ m ) - { - this->diff[ m ] = index1[ m ] - this->begin1[ m ]; - } - - this->Multiply( diff, this->mul ); - - for ( int m = 0; m < dim; ++ m ) - { - index2[ m ] = this->mul[ m ] + this->begin2[ m ]; - } - -} - -void Transform::Multiply( std::vector & a, std::vector & b ) -{ - int dim = a.size(); - for ( int i = 0; i < dim; ++ i ) - { - b[ i ] = 0; - for ( int j = 0; j < dim; ++ j ) - { - b[ i ] += this->Mt[ i ][ j ] * a[ j ]; - } - } -} diff --git a/example/1d-linear-convection/eno3/cpp/01/Grid.h b/example/1d-linear-convection/eno3/cpp/01/Grid.h deleted file mode 100644 index b7f81e8d..00000000 --- a/example/1d-linear-convection/eno3/cpp/01/Grid.h +++ /dev/null @@ -1,115 +0,0 @@ -#pragma once -#include "Vec1d.h" -#include -#include - -class Vec1d; - -class Grid -{ -public: - int zoneIndex; - int ni, nic; //nnode, ncell; - Vec1d x; - Vec1d xcc; -public: - void Allocate( int nNodes ); - void CalcMetrics(); -}; - -class Region -{ -public: - Region(); - ~Region(); -public: - std::vector start; - std::vector end; -public: - Region & operator = ( const Region & rhs ); - void SetRegion( std::vector & pnts ); - void Print(); -}; - -class Coor -{ -public: - Coor(); - ~Coor(); -public: - std::string coorname; - int nNodes; - std::vector nijk; - std::vector coord; -public: - void DumpCoor(); - void DumpCoorX( Vec1d & x ); -}; - -class ZoneBc -{ -public: - ZoneBc(); - ~ZoneBc(); -public: - int bcType; - int zoneid; - std::vector pnts; -}; - -class ZoneBc1To1 -{ -public: - ZoneBc1To1(); - ~ZoneBc1To1(); -public: - int zoneid; - int donor_zoneid; - std::vector pnts; - std::vector donor_pnts; - std::vector transform; -}; - - -class Zone -{ -public: - Zone(); - ~Zone(); -public: - int zoneIndex; - std::vector nijk; - std::vector bccos; - std::vector bc1to1s; - std::vector coors; -}; - -class Trans -{ -public: - static int M[ 3 ][ 3 ]; - static std::vector transform; - static int sgn( int x ); - static int del( int x, int y ); - static void ZeroMatrix(); - static void CalcTransformMatrix(); -}; - -class Transform -{ -public: - Transform(); - ~Transform(); -private: - std::vector diff; - std::vector mul; -public: - int Mt[ 3 ][ 3 ]; - std::vector begin1; - std::vector begin2; - std::vector transform; -public: - void Init(); - void MapIndex( std::vector & index1, std::vector & index2 ); - void Multiply( std::vector & a, std::vector & b ); -}; diff --git a/example/1d-linear-convection/eno3/cpp/01/HeatField.cpp b/example/1d-linear-convection/eno3/cpp/01/HeatField.cpp deleted file mode 100644 index a160d532..00000000 --- a/example/1d-linear-convection/eno3/cpp/01/HeatField.cpp +++ /dev/null @@ -1,228 +0,0 @@ -#include "HeatField.h" -#include "hxmath.h" -#include "Grid.h" -#include "Global.h" -#include "cgnslib.h" -#include -#include - -void HeatField::Init( std::fstream & file, Grid * grid ) -{ - this->ni = grid->ni; - this->nic = grid->nic; - grid->CalcMetrics(); - if ( Global::ifinite_volume == 1 ) - { - this->nx = this->nic; - } - else - { - // finite difference - this->nx = this->ni; - } - std::cout << "ni = " << ni << "\n"; - - Vec1d & x = grid->x; - this->dx = std::abs( x[ 1 ] - x[ 0 ] ); - this->dt = dx / 10.0; - this->nt = std::round( Global::total_time / dt ); - - std::cout << "this->dt = " << this->dt << "\n"; - std::cout << "this->nt = " << this->nt << "\n"; - std::cout << "this->ni = " << this->ni << "\n"; - std::cout << "nt * dt = " << nt * dt << "\n"; - - Global::nt = nt; - - this->alpha = 1 / ( std::numbers::pi * std::numbers::pi ); - this->beta = this->alpha * dt / ( dx * dx ); - - int ist = 0 - Global::nghost; - int ied = this->ni - 1 + Global::nghost; - - this->u.Allocate( this->nequ, ist, ied ); - this->un.Allocate( this->nequ, ist, ied ); - this->res.Allocate( this->nequ, 0, this->nx ); //N+1 - - Vec1d &u = this->u.vec(); - - if ( Global::ifinite_volume == 0 ) - { - //node - for ( int i = 0; i < ni; ++ i ) - { - u[ i ] = - std::sin( std::numbers::pi * x[ i ] ); //initial condition @ t=0 - } - } - else - { - //cell center - Vec1d & xcc = grid->xcc; - for ( int i = 0; i < nic; ++ i ) - { - u[ i ] = - std::sin( 2.0 * std::numbers::pi * xcc[ i ] ); //initial condition @ t=0 - } - - } - int kkk = 1; -} - -void HeatField::FTCS( Zone * zone ) -{ - this->Rhs( this->u, this->res ); - for ( int m = 0; m < nequ; ++ m ) - { - Vec1d & u = this->u.vec( m ); - Vec1d & res = this->res.vec( m ); - for ( int i = 0; i < ni; ++ i ) - { - u[ i ] = u[ i ] + dt * res[ i ]; - } - } -} - -void HeatField::CN( Zone * zone ) -{ - double rr = 0.5 * this->alpha * dt / ( dx * dx ); - for ( int m = 0; m < nequ; ++ m ) - { - Vec1d & u = this->u.vec( m ); - - std::vector a( ni ); - std::vector b( ni ); - std::vector c( ni ); - std::vector d( ni ); - - for ( int i = 0; i < ni; ++ i ) - { - a[ i ] = - rr; - b[ i ] = 1.0 + 2.0 * rr; - c[ i ] = - rr; - } - - for ( int i = 0; i < ni; ++ i ) - { - d[ i ] = rr * u[ i - 1 ] + ( 1.0 - 2.0 * rr ) * u[ i ] + rr * u[ i + 1 ]; - } - - double uleft = u[ -1 ] + 2 * rr * ( u[ - 1 ] - 2 * u[ 0 ] + u[ 1 ] ); - double uright = u[ ni ] + 2 * rr * ( u[ ni - 2 ] - 2 * u[ ni - 1 ] + u[ ni ] ); - - d[ 0 ] -= a[ 0 ] * uleft; - d[ ni - 1 ] -= c[ ni - 1 ] * uright; - - std::vector values( d.size() ); - - thomas_algorithm( a, b, c, d, values ); - - for ( int i = 0; i < ni; ++ i ) - { - u[ i ] = values[ i ]; - } - } -} - -void HeatField::ICP( Zone * zone ) -{ - double beta = 0.5 * this->alpha * dt / ( dx * dx ); - for ( int m = 0; m < nequ; ++ m ) - { - Vec1d & u = this->u.vec( m ); - std::vector a( ni );//0:ni-1 - std::vector b( ni );//0:ni-1 - std::vector c( ni );//0:ni-1 - std::vector d( ni );//0:ni-1 - - for ( int i = 0; i < ni; ++ i ) - { - a[ i ] = 1.0 / 12.0 - beta; - b[ i ] = 10.0 / 12.0 + 2.0 * beta; - c[ i ] = 1.0 / 12.0 - beta; - - double aa = 1.0 / 12.0 + beta; - double bb = 10.0 / 12.0 - 2.0 * beta; - double cc = 1.0 / 12.0 + beta; - d[ i ] = aa * u[ i - 1 ] + bb * u[ i ] + cc * u[ i + 1 ]; - } - - - //double uleft = u[ -1 ] + 2 * beta * ( u[ - 1 ] - 2 * u[ 0 ] + u[ 1 ] ); - //double uright = u[ ni ] + 2 * beta * ( u[ ni - 2 ] - 2 * u[ ni - 1 ] + u[ ni ] ); - - //double uleft = u[ -1 ]; - //double uright = u[ ni ]; - - double uleft = u[ -1 ] + beta * ( u[ - 1 ] - 2 * u[ 0 ] + u[ 1 ] ); - double uright = u[ ni ] + beta * ( u[ ni - 2 ] - 2 * u[ ni - 1 ] + u[ ni ] ); - - d[ 0 ] -= a[ 0 ] * uleft; - d[ ni - 1 ] -= c[ ni - 1 ] * uright; - - //d[ 0 ] -= a[ 0 ] * u[ -1 ]; - //d[ ni - 1 ] -= c[ ni - 1 ] * u[ ni ]; - - - std::vector values( d.size() ); - - thomas_algorithm( a, b, c, d, values ); - - for ( int i = 0; i < ni; ++ i ) - { - u[ i ] = values[ i ]; - } - } -} - -void HeatField::UpdateOldField() -{ - this->un = this->u; -} - -void HeatField::InviscidResidual( VecWrap & u, VecWrap & res ) -{ - ; -} - -void HeatField::ViscousResidual( VecWrap & u, VecWrap & res ) -{ - double coef = this->alpha / ( dx * dx ); - for ( int m = 0; m < nequ; ++ m ) - { - Vec1d & u = this->u.vec( m ); - Vec1d & res = this->res.vec( m ); - for ( int i = 0; i < ni; ++ i ) - { - res[ i ] += coef * ( u[ i + 1 ] - 2.0 * u[ i ] + u[ i - 1 ] ); - } - } -} -void HeatField::Rhs( VecWrap & u, VecWrap & res ) -{ - res = 0; - InviscidResidual( u, res ); - ViscousResidual( u, res ); -} - -void HeatField::DumpField( Grid * grid ) -{ - this->DumpField( grid->x, u ); -} - -void HeatField::PostProcess( Grid * grid ) -{ - this->DumpField( grid->x, u ); -} - -void HeatField::DumpField( Vec1d & x, VecWrap & u ) -{ - for ( int i = 0; i < x.size(); ++ i ) - { - Global::file_string += std::format( "{:.16f}", x[ i ] ); - for ( int m = 0; m < nequ; ++ m ) - { - Vec1d & u = this->u.vec( m ); - Global::file_string += std::format( " {:.16f}", u[ i ] ); - } - Global::file_string += std::format( "\n" ); - } -} \ No newline at end of file diff --git a/example/1d-linear-convection/eno3/cpp/01/HeatField.h b/example/1d-linear-convection/eno3/cpp/01/HeatField.h deleted file mode 100644 index 4fcb3e37..00000000 --- a/example/1d-linear-convection/eno3/cpp/01/HeatField.h +++ /dev/null @@ -1,28 +0,0 @@ -#pragma once -#include -#include "Vec1d.h" -#include "Field.h" - -class HeatField : public Field -{ -public: - int nt; - double dx; - double alpha, beta; -public: - void Init( std::fstream & file, Grid * grid ); -public: - void FTCS( Zone * zone ); - void CN( Zone * zone ); - void ICP( Zone * zone ); -public: - void Rhs( VecWrap & u, VecWrap & res ); - void InviscidResidual( VecWrap & u, VecWrap & res ); - void ViscousResidual( VecWrap & u, VecWrap & res ); - void UpdateOldField(); -public: - void DumpField( Grid * grid ); - void PostProcess( Grid * grid ); - void DumpField( Vec1d & x, VecWrap & u ); -}; - diff --git a/example/1d-linear-convection/eno3/cpp/01/Linear Convection_plot.py b/example/1d-linear-convection/eno3/cpp/01/Linear Convection_plot.py deleted file mode 100644 index 7efc5d78..00000000 --- a/example/1d-linear-convection/eno3/cpp/01/Linear Convection_plot.py +++ /dev/null @@ -1,70 +0,0 @@ -import numpy as np -import matplotlib.pyplot as plt -import csv -import sys - -def set_fuction(nx, u, x, ct) : - for i in range(nx): - xm = x[i] - if 0.5 <= xm - ct <= 1: - u[i] = 2 - else: - u[i] = 1 - -filename = 'field_final.csv' - -nvar = len(sys.argv) -print('nvar=',nvar) -print('sys.argv=',sys.argv) - -labelname = "FTBS solution" -if nvar >= 2: - scheme = sys.argv[1] - print('scheme=',scheme) - labelname = scheme + ' solution' - -print("labelname=",labelname) - -with open(filename, newline='') as csvfile: - readCSV = csv.reader(csvfile, delimiter= ' ') - icount = 0 - for row in readCSV: - icount += 1 - -ni = icount -print("ni=",ni) - -x = np.zeros( (ni) ) -u = np.zeros( (ni) ) -utheory= np.zeros( (ni) ) - -with open(filename, newline='') as csvfile: - readCSV = csv.reader(csvfile, delimiter= ' ') - i = 0 - for row in readCSV: - x[i] = float(row[0]) - u[i] = float(row[1]) - i += 1 -#sort -sorted_indices = np.argsort(x) -xt=x[sorted_indices] -ut=u[sorted_indices] -x=xt -u=ut - -c = 1 -#total_t = 0.625 -total_t = 0.025 -# theory solution -set_fuction(ni, utheory, x, c * total_t ) - -plt.figure("OneFLOW-CFD Solver") -plt.plot(x, utheory, "k-", linewidth=1.0, label="Exact solution") -plt.scatter(x, u, facecolor="none", edgecolor="blue", s=20, linewidths=0.5, label=labelname) -plt.xlabel("$x$") -plt.ylabel("$u$") -plt.title("Solution field") -plt.legend() -plt.tight_layout() -plt.show(); - diff --git a/example/1d-linear-convection/eno3/cpp/01/Linear Convection_plotBAK.py b/example/1d-linear-convection/eno3/cpp/01/Linear Convection_plotBAK.py deleted file mode 100644 index 55f0fe08..00000000 --- a/example/1d-linear-convection/eno3/cpp/01/Linear Convection_plotBAK.py +++ /dev/null @@ -1,69 +0,0 @@ -import numpy as np -import matplotlib.pyplot as plt -import csv -import sys - -def set_fuction(nx, u, x, ct) : - for i in range(nx): - xm = x[i] - if 0.5 <= xm - ct <= 1: - u[i] = 2 - else: - u[i] = 1 - -filename = 'field_final.csv' - -nvar = len(sys.argv) -print('nvar=',nvar) -print('sys.argv=',sys.argv) - -labelname = "FTBS solution" -if nvar >= 2: - scheme = sys.argv[1] - print('scheme=',scheme) - labelname = scheme + ' solution' - -print("labelname=",labelname) - -with open(filename, newline='') as csvfile: - readCSV = csv.reader(csvfile, delimiter= ' ') - icount = 0 - for row in readCSV: - icount += 1 - -ni = icount -print("ni=",ni) - -x = np.zeros( (ni) ) -u = np.zeros( (ni) ) -utheory= np.zeros( (ni) ) - -with open(filename, newline='') as csvfile: - readCSV = csv.reader(csvfile, delimiter= ' ') - i = 0 - for row in readCSV: - x[i] = float(row[0]) - u[i] = float(row[1]) - i += 1 -#sort -sorted_indices = np.argsort(x) -xt=x[sorted_indices] -ut=u[sorted_indices] -x=xt -u=ut - -c = 1 -total_t = 0.625 -# theory solution -set_fuction(ni, utheory, x, c * total_t ) - -plt.figure("OneFLOW-CFD Solver") -plt.plot(x, utheory, "k-", linewidth=1.0, label="Exact solution") -plt.scatter(x, u, facecolor="none", edgecolor="blue", s=20, linewidths=0.5, label=labelname) -plt.xlabel("$x$") -plt.ylabel("$u$") -plt.title("Solution field") -plt.legend() -plt.tight_layout() -plt.show(); - diff --git a/example/1d-linear-convection/eno3/cpp/01/LogFile.cpp b/example/1d-linear-convection/eno3/cpp/01/LogFile.cpp deleted file mode 100644 index 08ccd453..00000000 --- a/example/1d-linear-convection/eno3/cpp/01/LogFile.cpp +++ /dev/null @@ -1,138 +0,0 @@ -#include "LogFile.h" -#include "Parallel.h" -#include -#include - -#ifdef _WINDOWS -#include -#include -#include -#else -#include -#include -#endif - -LogFile logFile; - -class OStream : public std::ostringstream -{ -public: - OStream() {} - ~OStream() {} -public: - void ClearAll() - { - this->clear(); - this->str(""); - } -}; - -OStream StrIO; -std::string GetPrjDirName( const std::string & fileName ); -bool DirExist( const std::string & dirName ); -void MakeDir( const std::string & dirName ); - -std::string GetPrjDirName( const std::string & fileName ) -{ - size_t pos = fileName.find_last_of("\\/"); - if ( std::string::npos == pos ) - { - return ""; - } - else - { - return fileName.substr( 0, pos ); - } -} - -bool DirExist( const std::string & dirName ) -{ -#ifdef _WINDOWS - bool flag = ( _access( dirName.c_str(), 0 ) == 0 ); - return flag; -#else - bool flag = ( access( dirName.c_str(), 0 ) == 0 ); - return flag; -#endif -} - -void MakeDir( const std::string & dirName ) -{ - int flag; -#ifdef _WINDOWS - flag = _mkdir( dirName.c_str() ); -#else - flag = mkdir( dirName.c_str(), S_IRWXU ); -#endif - if ( flag == 0 ) - { - std::cout << dirName << " directory has been created successfully !\n"; - } -} - -void CreateDirIfNeeded( std::string & prjFileName ) -{ - std::string prj_dir = GetPrjDirName( prjFileName ); - - if ( ! DirExist( prj_dir ) ) - { - MakeDir( prj_dir ); - } -} - - -void OpenLogFile( int logFileIndex, std::fstream & file ) -{ - static int ifReWrite = 0; - - StrIO.ClearAll(); - StrIO << "log/log" << logFileIndex << ".log"; - std::string fileName = StrIO.str(); - - std::ios_base::openmode openMode; - - if ( ifReWrite == 0 ) - { - CreateDirIfNeeded( fileName ); - - openMode = std::ios_base::out | std::ios_base::trunc; - - ifReWrite = 1; - } - else - { - openMode = std::ios_base::out | std::ios_base::app; - } - - file.open( fileName.c_str(), openMode ); - if ( ! file ) - { - std::cout << "could not open " << fileName << std::endl; - exit( 0 ); - } -} - -void CloseLogFile( std::fstream & file ) -{ - file.close(); - file.clear(); -} - -LogFile::LogFile() -{ -} - -LogFile::~LogFile() -{ -} - -void LogFile::Open() -{ - int pid = Parallel::pid; - OpenLogFile( pid, this->my_fstream ); -} - -void LogFile::Close() -{ - CloseLogFile( this->my_fstream ); -} diff --git a/example/1d-linear-convection/eno3/cpp/01/LogFile.h b/example/1d-linear-convection/eno3/cpp/01/LogFile.h deleted file mode 100644 index 00e775ab..00000000 --- a/example/1d-linear-convection/eno3/cpp/01/LogFile.h +++ /dev/null @@ -1,27 +0,0 @@ -#pragma once -#include - -void OpenLogFile( int logFileIndex, std::fstream & file ); -void CloseLogFile( std::fstream & file ); -class LogFile; -extern LogFile logFile; - -class LogFile -{ -public: - LogFile(); - ~LogFile(); - std::fstream my_fstream; -public: - void Open(); - void Close(); -}; - -template< typename T > -LogFile & operator << ( LogFile & f, const T & value ) -{ - f.Open(); - f.my_fstream << value; - f.Close(); - return f; -} diff --git a/example/1d-linear-convection/eno3/cpp/01/MyCRWenoPlot.py b/example/1d-linear-convection/eno3/cpp/01/MyCRWenoPlot.py deleted file mode 100644 index 752ec7f3..00000000 --- a/example/1d-linear-convection/eno3/cpp/01/MyCRWenoPlot.py +++ /dev/null @@ -1,64 +0,0 @@ -import numpy as np -import matplotlib.pyplot as plt -import csv -import sys - -nvar = len(sys.argv) -print('nvar=',nvar) -print('sys.argv=',sys.argv) - -ns = 10 -if nvar >= 2: - ms = sys.argv[1] - print('ms=',ms) - ns = int(ms) - -print('ns=',ns) - -with open('field_final0.csv', newline='') as csvfile: - readCSV = csv.reader(csvfile, delimiter= ' ') - icount = 0 - for row in readCSV: - icount += 1 - -ni = icount -print("ni=",ni) - -u = np.zeros( (ni, ns + 1 ) ) -x = np.zeros( (ni) ) - -for j in range(ns+1): - filename = 'field_final'+str((j)*250)+'.csv' - print('filename=',filename) - with open(filename, newline='') as csvfile: - readCSV = csv.reader(csvfile, delimiter= ' ') - i = 0 - for row in readCSV: - x[i] = float(row[0]) - u[i][j] = float(row[1]) - i += 1 - -print("u.shape=",u.shape) -n1 = u.shape[0] -n2 = u.shape[1] -print(f"n1={n1},n2={n2}") -#exit() -#x = np.linspace(0,1, num=ni) - -#sort -sorted_indices = np.argsort(x) -xt=x[sorted_indices] - -for k in range(ns+1): - ut = u[sorted_indices,k] - u[:,k] = ut[:] -tm = 0.25 - -plt.figure("OneFLOW-CFD Solver", figsize=(6, 4), dpi=100) -for k in range(0, ns+1): - plt.plot(xt, u[:,k], linewidth=1.0, label="t="+format(tm*k/ns, ".4f")) -plt.xlabel("$x$") -plt.ylabel("$u$") -plt.title("Inviscid Burgers Equation: CRWENO-5 Scheme+Dirichlet BC") -plt.legend(loc='upper right', fontsize='6') -plt.show() \ No newline at end of file diff --git a/example/1d-linear-convection/eno3/cpp/01/MyWenoPlot.py b/example/1d-linear-convection/eno3/cpp/01/MyWenoPlot.py deleted file mode 100644 index b44106d1..00000000 --- a/example/1d-linear-convection/eno3/cpp/01/MyWenoPlot.py +++ /dev/null @@ -1,53 +0,0 @@ -import numpy as np -import matplotlib.pyplot as plt -import csv - -with open('field_final0.csv', newline='') as csvfile: - readCSV = csv.reader(csvfile, delimiter= ' ') - icount = 0 - for row in readCSV: - icount += 1 - -ni = icount -print("ni=",ni) - -ns = 10 - -u = np.zeros( (ni, ns + 1 ) ) -x = np.zeros( (ni) ) - -for j in range(ns+1): - filename = 'field_final'+str((j)*250)+'.csv' - print('filename=',filename) - with open(filename, newline='') as csvfile: - readCSV = csv.reader(csvfile, delimiter= ' ') - i = 0 - for row in readCSV: - x[i] = float(row[0]) - u[i][j] = float(row[1]) - i += 1 - -print("u.shape=",u.shape) -n1 = u.shape[0] -n2 = u.shape[1] -print(f"n1={n1},n2={n2}") -#exit() -#x = np.linspace(0,1, num=ni) - -#sort -sorted_indices = np.argsort(x) -xt=x[sorted_indices] - -for k in range(ns+1): - ut = u[sorted_indices,k] - u[:,k] = ut[:] -tm = 0.25 - -plt.figure("OneFLOW-CFD Solver", figsize=(6, 4), dpi=100) -for k in range(0, ns+1): - plt.plot(xt, u[:,k], linewidth=1.0, label="t="+format(tm*k/ns, ".4f")) -plt.xlabel("$x$") -plt.ylabel("$u$") -plt.title("Inviscid Burgers Equation: Non-Conservative Form-WENO-5 Scheme") -plt.legend(loc='upper right', fontsize='6') -plt.show() \ No newline at end of file diff --git a/example/1d-linear-convection/eno3/cpp/01/Parallel.cpp b/example/1d-linear-convection/eno3/cpp/01/Parallel.cpp deleted file mode 100644 index c0199572..00000000 --- a/example/1d-linear-convection/eno3/cpp/01/Parallel.cpp +++ /dev/null @@ -1,100 +0,0 @@ -#include "Parallel.h" -#include - -int Parallel::pid = 0; -int Parallel::nProc = 1; -int Parallel::serverid = 0; -int Parallel::tag = 0; - -void Parallel::Init() -{ -#ifdef HX_PARALLEL - int argc = 0; - char ** argv = 0; - MPI_Init( &argc, &argv ); - MPI_Comm_rank( MPI_COMM_WORLD, &Parallel::pid ); - MPI_Comm_size( MPI_COMM_WORLD, &Parallel::nProc ); - int len = -1; - char version[ MPI_MAX_LIBRARY_VERSION_STRING ]; - MPI_Get_library_version( version, &len ); - std::cout << "Hello, world! I am " << Parallel::pid << " of " << Parallel::nProc - << "(" << version << ", " << len << ")" << std::endl; -#endif -} - -void Parallel::Finalize() -{ -#ifdef HX_PARALLEL - MPI_Finalize(); -#endif -} - -bool Parallel::IsServer() -{ - return Parallel::pid == Parallel::serverid; -} - -void HXSendChar( void * data, int size, int pid, int tag ) -{ -#ifdef HX_PARALLEL - if ( size <= 0 ) return; - MPI_Send( data, size, MPI_CHAR, pid, tag, MPI_COMM_WORLD ); -#endif -} - -void HXRecvChar( void * data, int size, int pid, int tag ) -{ -#ifdef HX_PARALLEL - if ( size <= 0 ) return; - - MPI_Status status; - MPI_Recv( data, size, MPI_CHAR, pid, tag, MPI_COMM_WORLD, & status ); -#endif -} - -void HXSendString( std::string const & str, int recv_pid, int tag ) -{ -#ifdef HX_PARALLEL - unsigned len = str.size(); - MPI_Send( &len, 1, MPI_UNSIGNED, recv_pid, tag, MPI_COMM_WORLD ); - if ( len == 0 ) return; - MPI_Send( str.data(), len, MPI_CHAR, recv_pid, tag, MPI_COMM_WORLD ); -#endif -} - -void HXRecvString( std::string & str, int send_pid, int tag ) -{ -#ifdef HX_PARALLEL - unsigned len; - MPI_Status status; - MPI_Recv( &len, 1, MPI_UNSIGNED, send_pid, tag, MPI_COMM_WORLD, &status ); - if ( len == 0 ) return; - str.resize( len ); - MPI_Recv( str.data(), len, MPI_CHAR, send_pid, tag, MPI_COMM_WORLD, &status ); -#endif -} - -void HXSendRecvString( std::string & str, int send_pid, int recv_pid, int tag ) -{ - if ( send_pid == recv_pid ) return; - if ( Parallel::pid == send_pid ) - { - HXSendString( str, recv_pid, tag ); - } - else if ( Parallel::pid == recv_pid ) - { - HXRecvString( str, send_pid, tag ); - } -} - -void HXBcastString( std::string & str, int send_pid ) -{ - int nlen = 0; - if ( Parallel::pid == send_pid ) - { - nlen = str.size(); - } - HXBcastData( &nlen, 1, send_pid ); - str.resize( nlen ); - HXBcastData( str.data(), str.size(), send_pid ); -} diff --git a/example/1d-linear-convection/eno3/cpp/01/Parallel.h b/example/1d-linear-convection/eno3/cpp/01/Parallel.h deleted file mode 100644 index 41f46dad..00000000 --- a/example/1d-linear-convection/eno3/cpp/01/Parallel.h +++ /dev/null @@ -1,85 +0,0 @@ -#pragma once -#ifdef HX_PARALLEL -#include "mpi.h" -#endif -#include -#include "LogFile.h" - -class Parallel -{ -public: - static int pid; - static int nProc; - static int serverid; - static int tag; -public: - static void Init(); - static void Finalize(); -public: - static bool IsServer(); -}; - -void HXSendChar( void * data, int size, int pid, int tag = 0 ); -void HXRecvChar( void * data, int size, int pid, int tag = 0 ); -void HXSendRecvString( std::string & str, int send_pid, int recv_pid, int tag = 0 ); -void HXSendString( std::string const & str, int recv_pid, int tag = 0 ); -void HXRecvString( std::string & str, int send_pid, int tag = 0 ); - -template< typename T > -void HXSendData( T * field, int nElement, int recv_pid, int tag ); - -template< typename T > -void HXRecvData( T * field, int nElement, int send_pid, int tag ); - -template< typename T > -void HXSendData( T * field, int nElement, int recv_pid, int tag = 0 ) -{ - if ( nElement <= 0 ) return; - - int buffer_size = nElement * sizeof( T ); - - HXSendChar( field, buffer_size, recv_pid, tag ); -} - -template< typename T > -void HXRecvData( T * field, int nElement, int send_pid, int tag = 0 ) -{ - if ( nElement <= 0 ) return; - - int buffer_size = nElement * sizeof( T ); - - HXRecvChar( field, buffer_size, send_pid, tag ); -} - -template< typename T > -void HXSendRecvData( T * field, int nElement, int send_pid, int recv_pid, int tag = 0 ) -{ - if ( send_pid == recv_pid ) return; - - if ( nElement <= 0 ) return; - - int buffer_size = nElement * sizeof( T ); - - if ( Parallel::pid == send_pid ) - { - HXSendChar( field, buffer_size, recv_pid, tag ); - } - else if ( Parallel::pid == recv_pid ) - { - HXRecvChar( field, buffer_size, send_pid, tag ); - } -} - -template< typename T > -void HXBcastData( T * field, int nElement, int send_pid ) -{ - if ( nElement <= 0 ) return; - int buffer_size = nElement * sizeof( T ); -#ifdef HX_PARALLEL - MPI_Bcast( field, buffer_size, MPI_CHAR, send_pid, MPI_COMM_WORLD ); -#endif -} - -void HXBcastString( std::string & str, int send_pid ); - - diff --git a/example/1d-linear-convection/eno3/cpp/01/Post.cpp b/example/1d-linear-convection/eno3/cpp/01/Post.cpp deleted file mode 100644 index b1b1c3d3..00000000 --- a/example/1d-linear-convection/eno3/cpp/01/Post.cpp +++ /dev/null @@ -1,38 +0,0 @@ -#include "Post.h" -#include "Parallel.h" -#include "ZoneState.h" -#include "Global.h" -#include "Field.h" -#include "Grid.h" -#include -#include -#include -#include -#include - -double compute_l2norm( int ni, std::vector & r ) -{ - double rms = 0.0; - for ( int i = 1; i < ni - 1; ++ i ) - { - rms += r[ i ] * r[ i ]; - } - rms = std::sqrt( rms / ( ni - 2 ) ); - return rms; -} - -double compute_max_error( int ni, std::vector & u_error ) -{ - double val_max = -1; - int ipos = -1; - for ( int i = 1; i < ni - 1; ++ i ) - { - if ( val_max < std::abs( u_error[ i ] ) ) - { - ipos = i; - val_max = std::abs( u_error[ i ] ); - } - } - std::cout << " ipos = " << ipos << "\n"; - return val_max; -} diff --git a/example/1d-linear-convection/eno3/cpp/01/Post.h b/example/1d-linear-convection/eno3/cpp/01/Post.h deleted file mode 100644 index 1ab1fb51..00000000 --- a/example/1d-linear-convection/eno3/cpp/01/Post.h +++ /dev/null @@ -1,6 +0,0 @@ -#pragma once -#include -#include - -double compute_l2norm( int ni, std::vector & r ); -double compute_max_error( int ni, std::vector & u_error ); diff --git a/example/1d-linear-convection/eno3/cpp/01/README.txt b/example/1d-linear-convection/eno3/cpp/01/README.txt deleted file mode 100644 index 5a4410fb..00000000 --- a/example/1d-linear-convection/eno3/cpp/01/README.txt +++ /dev/null @@ -1,3 +0,0 @@ -cmake -DCMAKE_TOOLCHAIN_FILE="c:/dev/vcpkg/scripts/buildsystems/vcpkg.cmake" .. - -PS D:\github\OneFLOW\example\1d-heat-equation\ftcs\cpp\multiblock\parallel\8blocks\01\build> mpiexec -n 8 .\Debug\testprj.exe diff --git a/example/1d-linear-convection/eno3/cpp/01/Solver.cpp b/example/1d-linear-convection/eno3/cpp/01/Solver.cpp deleted file mode 100644 index 9b175c8d..00000000 --- a/example/1d-linear-convection/eno3/cpp/01/Solver.cpp +++ /dev/null @@ -1,795 +0,0 @@ -#include "Solver.h" -#include "Field.h" -#include "HeatField.h" -#include "ConvectionField.h" -#include "BurgersField.h" -#include "EulerField.h" -#include "CgnsUtil.h" -#include "Parallel.h" -#include "Post.h" -#include "Weno.h" -#include "ZoneState.h" -#include "global.h" -#include -#include -#include -#include -#include -#include -#include -using json = nlohmann::json; - -Solver::Solver() -{ -} - -Solver::~Solver() -{ - Parallel::Finalize(); -} - -void Solver::Init() -{ - Parallel::Init(); - - if ( Parallel::IsServer() ) - { - std::ifstream f( "../linearconvection.json" ); - json data = json::parse( f ); - std::cout << "data=" << data.dump( 4 ) << std::endl; - Global::istart = data[ "istart" ]; - if ( Global::istart == 1 ) - { - Read_iter(); - } - - std::string equation = data[ "equation" ]; - if ( equation == "heat" ) - { - Global::governing_equation = GoverningEquation::Heat; - Global::nequ = 1; - } - else if ( equation == "linearconvection" ) - { - Global::governing_equation = GoverningEquation::LinearConvection; - Global::nequ = 1; - } - else if ( equation == "burgers" ) - { - Global::governing_equation = GoverningEquation::Burgers; - Global::nequ = 1; - } - else - { - Global::governing_equation = GoverningEquation::Euler; - Global::nequ = 3; - } - Global::iconservation = data[ "iconservation" ]; - Global::iviscous = data[ "iviscous" ]; - Global::nsave = data[ "nsave" ]; - Global::idump_initial_field = data[ "idump_initial_field" ]; - Global::ifinite_volume = data[ "ifinite_volume" ]; - Global::total_time = data[ "total_time" ]; - Global::dt = data[ "dt" ]; - std::cout << "Global::total_time = " << Global::total_time << "\n"; - std::cout << "Global::dt = " << Global::dt << "\n"; - - json &s = data[ "scheme" ]; - - std::cout << "s=" << s.dump( 4 ) << std::endl; - Global::scheme.read( s ); - - if ( Global::scheme.reconstruction == to_int( BasicScheme::ENO ) || - Global::scheme.reconstruction == to_int( BasicScheme::WENO ) || - Global::scheme.reconstruction == to_int( BasicScheme::CRWENO ) - ) - { - Global::nghost = 3; - } - else - { - Global::nghost = 1; - } - - this->gridfile = data[ "grid" ]; - } - HXBcastData( &Global::istart, 1, Parallel::serverid ); - HXBcastData( &Global::governing_equation, 1, Parallel::serverid ); - HXBcastData( &Global::iconservation, 1, Parallel::serverid ); - HXBcastData( &Global::iviscous, 1, Parallel::serverid ); - HXBcastData( &Global::nsave, 1, Parallel::serverid ); - HXBcastData( &Global::idump_initial_field, 1, Parallel::serverid ); - HXBcastData( &Global::ifinite_volume, 1, Parallel::serverid ); - HXBcastData( &Global::total_time, 1, Parallel::serverid ); - HXBcastData( &Global::dt, 1, Parallel::serverid ); - HXBcastData( &Global::scheme, 1, Parallel::serverid ); - HXBcastData( &Global::nghost, 1, Parallel::serverid ); - HXBcastData( &Global::nequ, 1, Parallel::serverid ); - HXBcastString( this->gridfile, Parallel::serverid ); - - PrintPidHeader(); - std::cout << "Global::istart = " << static_cast( Global::istart ) << "\n"; - PrintPidHeader(); - std::cout << "Global::governing_equation = " << static_cast( Global::governing_equation ) << "\n"; - PrintPidHeader(); - std::cout << "Global::iconservation = " << Global::iconservation << "\n"; - PrintPidHeader(); - std::cout << "Global::iviscous = " << Global::iviscous << "\n"; - PrintPidHeader(); - std::cout << "Global::nsave = " << Global::nsave << "\n"; - PrintPidHeader(); - std::cout << "Global::idump_initial_field = " << Global::idump_initial_field << "\n"; - PrintPidHeader(); - std::cout << "Global::ifinite_volume = " << Global::ifinite_volume << "\n"; - PrintPidHeader(); - std::cout << "Global::total_time = " << Global::total_time << "\n"; - PrintPidHeader(); - std::cout << "Global::dt = " << Global::dt << "\n"; - PrintPidHeader(); - std::cout << "Global::scheme.inviscid = " << Global::scheme.inviscid << "\n"; - PrintPidHeader(); - std::cout << "Global::scheme.viscous = " << Global::scheme.viscous << "\n"; - PrintPidHeader(); - std::cout << "Global::scheme.time_scheme = " << Global::scheme.time_scheme << "\n"; - PrintPidHeader(); - std::cout << "Global::scheme.reconstruction = " << Global::scheme.reconstruction << "\n"; - PrintPidHeader(); - std::cout << "Global::nghost = " << Global::nghost << "\n"; - PrintPidHeader(); - std::cout << "this->gridfile = " << this->gridfile << "\n"; - } - -void Solver::Read_iter() -{ - std::ifstream f( "iter.json" ); - json data = json::parse( f ); - - Global::iter_start = data[ "iter" ]; -} - -void Solver::Dump_iter() -{ - //std::print( "Global::iter={}", Global::iter + 1 ); - json j; - // add a number that is stored as double (note the implicit conversion of j to an object) - j["iter"] = Global::iter + 1; - - // JSONдļ - std::ofstream file("iter.json"); - if (file.is_open()) { - file << j.dump( 4 ); // 4ʾʽ - file.close(); - std::cout << "JSONдiter.jsonļ" << std::endl; - } else { - std::cerr << "޷ļ" << std::endl; - } -} - -void Solver::Run() -{ - this->Init(); - this->ReadGrid(); - this->InitTopo(); - this->InitFields(); - this->SolveFields(); - this->PostProcess(); -} - -void Solver::ReadGrid() -{ - ReadCgnsGridBaseZone( this->gridfile ); - ReadCgnsGrid( this->gridfile ); -} - -void Solver::CreateField() -{ - Field * field = nullptr; - if ( Global::governing_equation == GoverningEquation::Heat ) - { - field = new HeatField(); - } - else if ( Global::governing_equation == GoverningEquation::LinearConvection ) - { - field = new ConvectionField(); - } - else if ( Global::governing_equation == GoverningEquation::Burgers ) - { - field = new BurgersField(); - } - else - { - field = new EulerField(); - } - Global::fields.push_back( field ); -} - -void Solver::InitFields() -{ - std::cout << "Parallel::pid = " << Parallel::pid << " "; - std::cout << "Solver::InitFields() ZoneState::nZones = " << ZoneState::nZones << "\n"; - for ( int iZone = 0; iZone < LocalZone::nZones; ++ iZone ) - { - CreateField(); - } - - InitFieldCommon(); - - if ( Global::istart == 0 ) - { - InitFieldAsRestart(); - } - else - { - ReadFlowField(); - } - - this->Boundary(); - this->UpdateOldField(); -} - -void Solver::InitFieldAsRestart() -{ - for ( int iZone = 0; iZone < LocalZone::nZones; ++ iZone ) - { - Grid * grid = Global::grids[ iZone ]; - Field * field = Global::fields[ iZone ]; - field->InitFieldAsRestart( grid ); - } -} - -void Solver::ReadFlowField() -{ - std::string filename = "field_final.csv"; - std::fstream file; - if ( Parallel::pid == Parallel::serverid ) - { - file.open( filename.c_str(), std::fstream::in ); - } - for ( int iZone = 0; iZone < ZoneState::nZones; ++ iZone ) - { - int send_pid = ZoneState::pids[ iZone ]; - int recv_pid = Parallel::serverid; - - if ( Parallel::pid == send_pid ) - { - int local_zoneid = ZoneState::g2lzoneids[ iZone ]; - - Grid * grid = Global::grids[ local_zoneid ]; - Field * field = Global::fields[ local_zoneid ]; - field->ReadFlowField( file, grid ); - } - - //HXSendRecvString( Global::file_string, send_pid, Parallel::serverid ); - - //if ( Parallel::pid == Parallel::serverid ) - //{ - // total_string += Global::file_string; - //} - } - if ( Parallel::pid == Parallel::serverid ) - { - file.close(); - } -} - -void Solver::InitFieldCommon() -{ - for ( int iZone = 0; iZone < LocalZone::nZones; ++ iZone ) - { - Grid * grid = Global::grids[ iZone ]; - grid->zoneIndex = iZone; - Field * field = Global::fields[ iZone ]; - field->InitFieldCommon( grid ); - } -} - -void Solver::DumpInitialFields() -{ - this->DumpField(); -} - -void Solver::TimeIntegral() -{ - BasicScheme time_scheme = to_BasicScheme( Global::scheme.time_scheme ); - switch ( time_scheme ) { - case BasicScheme::RK1: - this->RungeKutta( 1 ); - break; - case BasicScheme::RK2: - this->RungeKutta( 2 ); - break; - case BasicScheme::RK3: - this->RungeKutta( 3 ); - break; - default: - this->CrankNicolsonSeries(); - } -} - -void Solver::SolveFields() -{ - if ( Global::idump_initial_field == 1 ) - { - this->DumpInitialFields(); - } - - for ( int it = Global::iter_start; it < Global::nt; ++ it ) - { - Global::iter = it; - this->TimeIntegral(); - - if ( ( Global::iter + 1 ) % Global::nsave == 0 ) - { - std::print( "it = {} nt = {}\n", Global::iter + 1, Global::nt ); - this->DumpField(); - } - } -} - -void Solver::FTCS() -{ - for ( int iZone = 0; iZone < LocalZone::nZones; ++ iZone ) - { - Field * field = Global::fields[ iZone ]; - Zone * zone = Global::zones[ iZone ]; - zone->zoneIndex = iZone; - field->FTCS( zone ); - } - this->Boundary(); - this->UpdateOldField(); -} - -void Solver::CrankNicolsonSeries() -{ - for ( int iZone = 0; iZone < LocalZone::nZones; ++ iZone ) - { - Field * field = Global::fields[ iZone ]; - Zone * zone = Global::zones[ iZone ]; - zone->zoneIndex = iZone; - field->CrankNicolsonSeries( zone ); - } - this->Boundary(); - this->UpdateOldField(); -} - -void Solver::ICP() -{ - for ( int iZone = 0; iZone < LocalZone::nZones; ++ iZone ) - { - Field * field = Global::fields[ iZone ]; - Zone * zone = Global::zones[ iZone ]; - zone->zoneIndex = iZone; - field->ICP( zone ); - } - this->Boundary(); - this->UpdateOldField(); -} - -void Solver::RungeKutta( int nStage ) -{ - for ( int istage = 0; istage < nStage; ++ istage ) - { - this->RungeKutta( nStage, istage ); - } - this->UpdateOldField(); -} - -void Solver::RungeKutta( int nStage, int istage ) -{ - for ( int iZone = 0; iZone < LocalZone::nZones; ++ iZone ) - { - Field * field = Global::fields[ iZone ]; - Zone * zone = Global::zones[ iZone ]; - zone->zoneIndex = iZone; - field->RungeKutta( zone, nStage, istage ); - } - this->Boundary(); -} - -void Solver::Boundary() -{ - for ( int iZone = 0; iZone < LocalZone::nZones; ++ iZone ) - { - Field * field = Global::fields[ iZone ]; - Zone * zone = Global::zones[ iZone ]; - field->PhysicalBoundary( zone ); - } - ExchangeInterfaceField(); - for ( int iZone = 0; iZone < LocalZone::nZones; ++ iZone ) - { - Field * field = Global::fields[ iZone ]; - Zone * zone = Global::zones[ iZone ]; - field->InterfaceBoundary( zone ); - } -} - -void Solver::UpdateOldField() -{ - for ( int iZone = 0; iZone < LocalZone::nZones; ++ iZone ) - { - Field * field = Global::fields[ iZone ]; - Zone * zone = Global::zones[ iZone ]; - field->UpdateOldField(); - } -} - -void Solver::UploadInterfaceField() -{ - for ( int iZone = 0; iZone < LocalZone::nZones; ++ iZone ) - { - Interface * interface = Global::interfaces[ iZone ]; - - Field * field = Global::fields[ iZone ]; - - int nsend_zones = interface->send_to_zones.size(); - for ( int iSend = 0; iSend < nsend_zones; ++ iSend ) - { - int zone_to_send = interface->send_to_zones[ iSend ]; - std::vector & donorfaces_for_send = interface->donorfaces_for_send[ iSend ]; - std::vector & donorijk_for_send = interface->donorijk_for_send[ iSend ]; - std::vector & donordata_for_send = interface->donordata_for_send[ iSend ]; - - int nInterFaces = donorfaces_for_send.size(); - int index_dim = 1; - int ngsize = Global::nghost + 1 - Global::ifinite_volume; - for ( int iFace = 0; iFace < nInterFaces; ++ iFace ) - { - int ijkpos = index_dim * iFace * ngsize; - int data_pos = iFace * ngsize * Global::nequ; - - for ( int ig = Global::ifinite_volume; ig <= Global::nghost; ++ ig ) - { - int iig = ig - Global::ifinite_volume; - int id_cell = donorijk_for_send[ ijkpos + iig ] - 1; - for ( int iequ = 0; iequ < Global::nequ; ++ iequ ) - { - Vec1d & u = field->u.vec( iequ ); - donordata_for_send[ data_pos ++ ] = u[ id_cell ]; - } - } - } - } - } -} - -void Solver::UpdateInterfaceField() -{ - for ( int iZone = 0; iZone < ZoneState::nZones; ++ iZone ) - { - int ndonor_zones = Global::interfaceTopo.linkmap[ iZone ].size(); - for ( int iNei = 0; iNei < ndonor_zones; ++ iNei ) - { - int donor_zone = Global::interfaceTopo.linkmap[ iZone ][ iNei ]; - int send_pid = ZoneState::pids[ iZone ]; - int recv_pid = ZoneState::pids[ donor_zone ]; - int nsend = -1; - std::vector donordata; - if ( Parallel::pid != send_pid && Parallel::pid != recv_pid ) continue; - if ( Parallel::pid == send_pid ) - { - int local_zoneid = ZoneState::g2lzoneids[ iZone ]; - Interface * interface = Global::interfaces[ local_zoneid ]; - donordata = interface->donordata_for_send[ iNei ]; - nsend = donordata.size(); - } - HXSendRecvData( &nsend, 1, send_pid, recv_pid ); - - if ( Parallel::pid == recv_pid ) - { - donordata.resize( nsend ); - } - HXSendRecvData( donordata.data(), donordata.size(), send_pid, recv_pid ); - - if ( Parallel::pid == recv_pid ) - { - int local_donor_zoneid = ZoneState::g2lzoneids[ donor_zone ]; - Interface * donor_interface = Global::interfaces[ local_donor_zoneid ]; - int nSize = donor_interface->neighbor_donor_zones.size(); - int ipos = -1; - for ( int i = 0; i < nSize; ++ i ) - { - int nei_zone = donor_interface->neighbor_donor_zones[ i ]; - if ( nei_zone == iZone ) - { - ipos = i; - break; - } - } - - std::vector & neighbor_donorfaces = donor_interface->neighbor_donorfaces[ ipos ]; - std::vector & sub_local_faceids = donor_interface->sub_local_faceids[ ipos ]; - for ( int i = 0; i < neighbor_donorfaces.size(); ++ i ) - { - int local_faceid = sub_local_faceids[ i ]; - - int index_dim = 1; - int ngsize = Global::nghost + 1 - Global::ifinite_volume; - int ijkpos = index_dim * local_faceid * ngsize; - int data_pos = local_faceid * ngsize * Global::nequ; - int donor_data_pos = i * ngsize * Global::nequ; - - for ( int ig = Global::ifinite_volume; ig <= Global::nghost; ++ ig ) - { - for ( int iequ = 0; iequ < Global::nequ; ++ iequ ) - { - double donor_value = donordata[ donor_data_pos ++ ]; - donor_interface->data_recv[ data_pos ++ ] = donor_value; - } - } - } - } - } - } -} - -void Solver::DownloadInterfaceField() -{ - for ( int iZone = 0; iZone < LocalZone::nZones; ++ iZone ) - { - Interface * interface = Global::interfaces[ iZone ]; - Field * field = Global::fields[ iZone ]; - - int nInterFaces = interface->zoneList.size(); - - int index_dim = 1; - for ( int iFace = 0; iFace < nInterFaces; ++ iFace ) - { - int ngsize = Global::nghost + 1 - Global::ifinite_volume; - int ijkpos = index_dim * iFace * ngsize; - int data_pos = iFace * ngsize * Global::nequ; - for ( int ig = Global::ifinite_volume; ig <= Global::nghost; ++ ig ) - { - int ig_cell = interface->ijk_ghosts[ ijkpos ++ ] - 1; - if ( ig == 0 ) - { - for ( int iequ = 0; iequ < Global::nequ; ++ iequ ) - { - Vec1d & u = field->u.vec( iequ ); - double donor_value = interface->data_recv[ data_pos ++ ]; - double valueb = 0.5 * ( u[ ig_cell ] + donor_value ); - u[ ig_cell ] = valueb; - } - } - else - { - for ( int iequ = 0; iequ < Global::nequ; ++ iequ ) - { - Vec1d & u = field->u.vec( iequ ); - double donor_value = interface->data_recv[ data_pos ++ ]; - u[ ig_cell ] = donor_value; - } - } - } - } - } -} - -void Solver::ExchangeInterfaceField() -{ - this->UploadInterfaceField(); - this->UpdateInterfaceField(); - this->DownloadInterfaceField(); -} - -void Solver::DumpField() -{ - std::string filename = std::format( "field_final{}.csv", Global::iter+1 ); - this->DumpField( filename ); -} - -void Solver::DumpField( const std::string & filename ) -{ - std::string total_string = {}; - std::fstream file; - if ( Parallel::pid == Parallel::serverid ) - { - file.open( filename.c_str(), std::fstream::out ); - } - for ( int iZone = 0; iZone < ZoneState::nZones; ++ iZone ) - { - int send_pid = ZoneState::pids[ iZone ]; - int recv_pid = Parallel::serverid; - - Global::file_string = {}; - - if ( Parallel::pid == send_pid ) - { - int local_zoneid = ZoneState::g2lzoneids[ iZone ]; - - Grid * grid = Global::grids[ local_zoneid ]; - Field * field = Global::fields[ local_zoneid ]; - field->DumpField( grid ); - } - - HXSendRecvString( Global::file_string, send_pid, Parallel::serverid ); - - if ( Parallel::pid == Parallel::serverid ) - { - total_string += Global::file_string; - } - } - if ( Parallel::pid == Parallel::serverid ) - { - std::format_to( std::ostream_iterator( file ), "{}", total_string ); - file.close(); - } -} - -void Solver::PostProcess() -{ - std::string filename = "field_final.csv"; - this->DumpField( filename ); - this->Dump_iter(); -} - -void Solver::PrintField( std::vector &f ) -{ - int icount = 0; - for ( int i = 0; i < f.size(); ++ i ) - { - std::cout << std::setprecision(15) << f[ i ] << " "; - icount ++; - if ( icount % 5 == 0 ) - { - std::cout << "\n"; - } - } - std::cout << "\n"; - std::cout << "\n"; -} - -void Solver::InitTopo() -{ - std::cout << "Parallel::pid = " << Parallel::pid << " "; - std::cout << "Solver::InitTopo() " << "\n"; - - Global::donor_zone_sets.resize( LocalZone::nZones ); - Global::donor_zones.resize( LocalZone::nZones ); - for ( int iZone = 0; iZone < LocalZone::nZones; ++ iZone ) - { - int global_zoneid = LocalZone::global_zoneids[ iZone ]; - std::cout << "Parallel::pid = " << Parallel::pid << " "; - std::cout << "iZone = " << iZone << " global_zoneid = " << global_zoneid << "\n"; - - Interface * interface = new Interface(); - interface->zoneid = global_zoneid; - Global::interfaces.push_back( interface ); - } - - for ( int iZone = 0; iZone < LocalZone::nZones; ++ iZone ) - { - Zone * zone = Global::zones[ iZone ]; - Interface * interface = Global::interfaces[ iZone ]; - - int nbc1to1s = zone->bc1to1s.size(); - std::cout << "Parallel::pid = " << Parallel::pid << " "; - std::cout << "nbc1to1s = " << nbc1to1s << "\n"; - - for ( int ibc1to1 = 0; ibc1to1 < nbc1to1s; ++ ibc1to1 ) - { - ZoneBc1To1 * bc1to1 = zone->bc1to1s[ ibc1to1 ]; - int zoneid = bc1to1->zoneid; - int donor_zoneid = bc1to1->donor_zoneid; - std::cout << "Parallel::pid = " << Parallel::pid << " "; - std::cout << "zoneid = " << zoneid << " donor_zoneid = " << donor_zoneid << "\n"; - - Region region; - region.SetRegion( bc1to1->pnts ); - - Region donor_region; - donor_region.SetRegion( bc1to1->donor_pnts ); - - Transform transform; - transform.begin1 = region.start; - transform.begin2 = donor_region.start; - transform.transform = bc1to1->transform; - transform.Init(); - - interface->CalcInterface( &transform, region.start, region.end, donor_zoneid ); - } - int nInterfaces = interface->zoneList.size(); - int ngsize = Global::nghost + 1 - Global::ifinite_volume; - int nData = nInterfaces * ngsize * Global::nequ; - interface->data_recv.resize( nData ); - interface->data_send.resize( nData ); - } - - for ( int iProc = 0; iProc < Parallel::nProc; ++ iProc ) - { - int nSize = -1; - if ( iProc == Parallel::pid ) - { - nSize = Global::facePairList.size(); - } - HXBcastData( &nSize, 1, iProc ); - std::cout << "Parallel::pid = " << Parallel::pid << " "; - std::cout << "nSize = " << nSize << "\n"; - std::vector tmp; - if ( iProc == Parallel::pid ) - { - tmp = Global::facePairList; - } - else - { - tmp.resize( nSize ); - } - - HXBcastData( tmp.data(), tmp.size(), iProc ); - Global::AddFacePairList( Global::mpi_facePairList, tmp ); - } - - for ( int i = 0; i < Global::mpi_facePairList.size(); ++ i ) - { - FacePair &facePair = Global::mpi_facePairList[ i ]; - Global::InsertFacePairMap( facePair ); - std::cout << "Parallel::pid = " << Parallel::pid << " "; - facePair.Print(); - } - - for ( int iZone = 0; iZone < LocalZone::nZones; ++ iZone ) - { - Zone * zone = Global::zones[ iZone ]; - - Interface * interface = Global::interfaces[ iZone ]; - int nInterfaces = interface->local_faceids.size(); - for ( int iInterface = 0; iInterface < nInterfaces; ++ iInterface ) - { - int local_faceid = interface->local_faceids[ iInterface ]; - int proc_global_faceid = interface->proc_global_faceids[ iInterface ]; - FacePair & facePair = Global::facePairList[ proc_global_faceid ]; - int global_faceid = Global::InsertFacePairMap( facePair ); - interface->global_faceids.push_back( global_faceid ); - interface->global_local_face_map.insert( std::make_pair( global_faceid, local_faceid ) ); - } - } - - for ( int iZone = 0; iZone < LocalZone::nZones; ++ iZone ) - { - Interface * interface = Global::interfaces[ iZone ]; - int nInterFaces = interface->zoneList.size(); - std::set &donor_zoneSet = Global::donor_zone_sets[ iZone ]; - for ( int iFace = 0; iFace < nInterFaces; ++ iFace ) - { - int donor_zoneid = interface->zoneList[ iFace ]; - donor_zoneSet.insert( donor_zoneid ); - } - - std::vector &donor_zones = Global::donor_zones[ iZone ]; - for ( std::set::iterator iter = donor_zoneSet.begin(); iter != donor_zoneSet.end(); ++ iter ) - { - donor_zones.push_back( *iter ); - } - - interface->neighbor_donor_zones = donor_zones; - - std::unordered_map donor_zonelocal; - - for ( int idonor = 0; idonor < donor_zones.size(); ++ idonor ) - { - int donor_zone = donor_zones[ idonor ]; - donor_zonelocal.insert( std::make_pair( donor_zone, idonor ) ); - } - int ndonors = donor_zones.size(); - std::vector> & neighbor_donorfaces = interface->neighbor_donorfaces; - neighbor_donorfaces.resize( ndonors ); - - std::vector> & sub_local_faceids = interface->sub_local_faceids; - sub_local_faceids.resize( ndonors ); - - for ( int iFace = 0; iFace < nInterFaces; ++ iFace ) - { - int donor_zoneid = interface->zoneList[ iFace ]; - int ineighbor = donor_zonelocal[ donor_zoneid ]; - std::vector &donorfaces = neighbor_donorfaces[ ineighbor ]; - int global_faceid = interface->global_faceids[ iFace ]; - donorfaces.push_back( global_faceid ); - int local_faceid = interface->local_faceids[ iFace ]; - - std::vector & sub_local_faces = sub_local_faceids[ ineighbor ]; - sub_local_faces.push_back( local_faceid ); - } - } - - Global::interfaceTopo.InitNeighborInfo(); - Global::interfaceTopo.SwapNeighborInfo(); -} \ No newline at end of file diff --git a/example/1d-linear-convection/eno3/cpp/01/Solver.h b/example/1d-linear-convection/eno3/cpp/01/Solver.h deleted file mode 100644 index ce995f68..00000000 --- a/example/1d-linear-convection/eno3/cpp/01/Solver.h +++ /dev/null @@ -1,50 +0,0 @@ -#pragma once -#include -#include "Global.h" -#include "Grid.h" - -double compute_l2norm( int ni, std::vector & r ); -double compute_max_error( int ni, std::vector & u_error ); - -class Solver -{ -public: - Solver(); - ~Solver(); -public: - std::string gridfile; -public: - void Init(); - void Run(); - void ReadGrid(); - void InitFields(); - void InitFieldCommon(); - void InitFieldAsRestart(); - void ReadFlowField(); - void CreateField(); - void InitTopo(); - void SolveFields(); - void TimeIntegral(); - void DumpInitialFields(); - void Read_iter(); - void Dump_iter(); -public: - void Boundary(); - void UpdateOldField(); - void UploadInterfaceField(); - void UpdateInterfaceField(); - void DownloadInterfaceField(); - void ExchangeInterfaceField(); - void PrintField( std::vector & f ); -public: - void PostProcess(); - void DumpField(); - void DumpField( const std::string & filename ); -public: - void FTCS(); - void CrankNicolsonSeries(); - void ICP(); -public: - void RungeKutta( int nStage ); - void RungeKutta( int nStage, int istage ); -}; diff --git a/example/1d-linear-convection/eno3/cpp/01/Vec1d.cpp b/example/1d-linear-convection/eno3/cpp/01/Vec1d.cpp deleted file mode 100644 index 6f2fefb5..00000000 --- a/example/1d-linear-convection/eno3/cpp/01/Vec1d.cpp +++ /dev/null @@ -1,10 +0,0 @@ -#include "Vec1d.h" - -void VecWrap::Allocate( int nEqu, int ist, int ied, double value ) -{ - this->data.resize( nEqu ); - for ( int m = 0; m < nEqu; ++ m ) - { - this->data[ m ].Allocate( ist, ied, value ); - } -} diff --git a/example/1d-linear-convection/eno3/cpp/01/Vec1d.h b/example/1d-linear-convection/eno3/cpp/01/Vec1d.h deleted file mode 100644 index 82f65d17..00000000 --- a/example/1d-linear-convection/eno3/cpp/01/Vec1d.h +++ /dev/null @@ -1,72 +0,0 @@ -#pragma once -#include - -class Vec1d -{ -public: - std::vector data; - int ist = 0; - int ied; -public: - void Allocate( int ist, int ied, double value = 0 ) - { - int nelement = ied - ist + 1; - this->data.resize( nelement, value ); - this->ist = ist; - this->ied = ied; - } - std::size_t size() - { - return this->data.size(); - } - - double operator [] ( int i ) const - { - return data[ i - ist ]; - } - - double & operator [] ( int i ) - { - return data[ i - ist ]; - } - - Vec1d & operator = ( const Vec1d & rhs ) - { - if ( this == & rhs ) return * this; - this->data = rhs.data; - this->ist = rhs.ist; - this->ied = rhs.ied; - return * this; - } - - Vec1d & operator = ( const double value ) - { - for ( int i = 0; i < data.size(); ++ i ) - { - data[ i ] = value; - } - return * this; - } -}; - -class VecWrap -{ -public: - std::vector data; - void Allocate( int nEqu, int ist, int ied, double value = 0 ); - Vec1d & vec( int m = 0 ) { return data[ m ]; }; - VecWrap & operator = ( const double value ) - { - for ( int m = 0; m < data.size(); ++ m ) - { - data[ m ] = value; - } - return * this; - } - int get_nequ() const { return data.size(); } - - Vec1d & operator [] ( int m ) - { - return data[ m ]; - } -}; \ No newline at end of file diff --git a/example/1d-linear-convection/eno3/cpp/01/Weno.cpp b/example/1d-linear-convection/eno3/cpp/01/Weno.cpp deleted file mode 100644 index 2a6402d0..00000000 --- a/example/1d-linear-convection/eno3/cpp/01/Weno.cpp +++ /dev/null @@ -1,399 +0,0 @@ -#include "Weno.h" -#include "hxmath.h" -#include -#include -#include -#include -#include - -double wcL3( double v1, double v2, double v3 ) -{ - double eps = 1.0e-6; - - // smoothness indicators - double beta1 = SQR( v2 - v1 ); - double beta2 = SQR( v3 - v2 ); - - double d1 = 2.0 / 3.0; - double d2 = 1.0 / 3.0; - - // computing nonlinear weights w1, w2, w3 - double c1 = d1 / ( SQR( beta1 + eps ) ); - double c2 = d2 / ( SQR( beta2 + eps ) ); - - double w1 = c1 / ( c1 + c2 ); - double w2 = c2 / ( c1 + c2 ); - - // candiate stencils - double q1 = - v1 / 2.0 + 3.0 / 2.0 * v2; - double q2 = v2 / 2.0 + v3 / 2.0; - - // reconstructed value at interface - double f = ( w1 * q1 + w2 * q2 ); - - return f; -} - -double wcR3( double v1, double v2, double v3 ) -{ - // reconstructed value at interface - double f = 0.0; - - return f; -} - -double wcL( double v1, double v2, double v3, double v4, double v5 ) -{ - double eps = 1.0e-6; - - // smoothness indicators - double s1 = ( 13.0 / 12.0 ) * SQR( v1 - 2.0 * v2 + v3 ) + 0.25 * SQR( v1 - 4.0 * v2 + 3.0 * v3 ); - double s2 = ( 13.0 / 12.0 ) * SQR( v2 - 2.0 * v3 + v4 ) + 0.25 * SQR( v2 - v4 ); - double s3 = ( 13.0 / 12.0 ) * SQR( v3 - 2.0 * v4 + v5 ) + 0.25 * SQR( 3.0 * v3 - 4.0 * v4 + v5 ); - - // computing nonlinear weights w1, w2, w3 - double c1 = 1.0e-1 / ( SQR( eps + s1 ) ); - double c2 = 6.0e-1 / ( SQR( eps + s2 ) ); - double c3 = 3.0e-1 / ( SQR( eps + s3 ) ); - - double w1 = c1 / ( c1 + c2 + c3 ); - double w2 = c2 / ( c1 + c2 + c3 ); - double w3 = c3 / ( c1 + c2 + c3 ); - - // candiate stencils - double q1 = v1 / 3.0 - 7.0 / 6.0 * v2 + 11.0 / 6.0 * v3; - double q2 = -v2 / 6.0 + 5.0 / 6.0 * v3 + v4 / 3.0; - double q3 = v3 / 3.0 + 5.0 / 6.0 * v4 - v5 / 6.0; - - // reconstructed value at interface - double f = ( w1 * q1 + w2 * q2 + w3 * q3 ); - - return f; -} - -double wcR( double v1, double v2, double v3, double v4, double v5 ) -{ - double eps = 1.0e-6; - - // smoothness indicators - double s1 = ( 13.0 / 12.0 ) * SQR( v1 - 2.0 * v2 + v3 ) + 0.25 * SQR( v1 - 4.0 * v2 + 3.0 * v3 ); - double s2 = ( 13.0 / 12.0 ) * SQR( v2 - 2.0 * v3 + v4 ) + 0.25 * SQR( v2 - v4 ); - double s3 = ( 13.0 / 12.0 ) * SQR( v3 - 2.0 * v4 + v5 ) + 0.25 * SQR( 3.0 * v3 - 4.0 * v4 + v5 ); - - // computing nonlinear weights w1, w2, w3 - double c1 = 3.0e-1 / SQR( eps + s1 ); - double c2 = 6.0e-1 / SQR( eps + s2 ); - double c3 = 1.0e-1 / SQR( eps + s3 ); - - double w1 = c1 / ( c1 + c2 + c3 ); - double w2 = c2 / ( c1 + c2 + c3 ); - double w3 = c3 / ( c1 + c2 + c3 ); - - // candiate stencils; - double q1 = -v1 / 6.0 + 5.0 / 6.0 * v2 + v3 / 3.0; - double q2 = v2 / 3.0 + 5.0 / 6.0 * v3 - v4 / 6.0; - double q3 = 11.0 / 6.0 * v3 - 7.0 / 6.0 * v4 + v5 / 3.0; - - // reconstructed value at interface - double f = ( w1 * q1 + w2 * q2 + w3 * q3 ); - - return f; -} - -//----------------------------------------------------------------------------- -// WENO reconstruction for upwind direction (positive; left to right) -// u(i): solution values at finite difference grid nodes i = 1,...,N+1 -// f(j): reconstructed values at nodes j = i+1/2; j = 1,...,N -//----------------------------------------------------------------------------- -void wenoL( int N, Vec1d & u, Vec1d & f ) -{ - for ( int i = 0; i <= N; ++ i ) - { - int ii = i - 1; - double v1 = u[ ii - 2 ]; - double v2 = u[ ii - 1 ]; - double v3 = u[ ii ]; - double v4 = u[ ii + 1 ]; - double v5 = u[ ii + 2 ]; - f[ i ] = wcL( v1, v2, v3, v4, v5 ); - if ( std::isnan( f[ i ] ) ) - { - int kkk = 1; - } - } -} - -//----------------------------------------------------------------------------- -// CRWENO reconstruction for downwind direction (negative; right to left) -// u(i): solution values at finite difference grid nodes i = 1,...,N+1 -// f(j): reconstructed values at nodes j = i-1/2; j = 2,...,N+1 -//----------------------------------------------------------------------------- -void wenoR( int N, Vec1d & u, Vec1d & f ) -{ - for ( int i = 0; i <= N; ++ i ) - { - int ii = i - 1; - double v1 = u[ ii - 1 ]; - double v2 = u[ ii ]; - double v3 = u[ ii + 1 ]; - double v4 = u[ ii + 2 ]; - double v5 = u[ ii + 3 ]; - f[ i ] = wcR( v1, v2, v3, v4, v5 ); - } -} - -void Upwind1L( int N, Vec1d & u, Vec1d & f ) -{ - for ( int i = 0; i <= N; ++ i ) - { - int ii = i - 1; - double v3 = u[ ii ]; - f[ i ] = v3; - } -} - -void Upwind1R( int N, Vec1d & u, Vec1d & f ) -{ - for ( int i = 0; i <= N; ++ i ) - { - int ii = i - 1; - double v3 = u[ ii + 1 ]; - f[ i ] = v3; - } -} - -void crabL( double w1, double w2, double w3, - double & a1, double & a2, double & a3, - double & b1, double & b2, double & b3 ) -{ - a1 = ( 2.0 * w1 + w2 ) / 3.0; - a2 = ( w1 + 2.0 * w2 + 2.0 * w3 ) / 3.0; - a3 = w3 / 3.0; - - b1 = w1 / 6.0; - b2 = ( 5.0 * w1 + 5.0 * w2 + w3 ) / 6.0; - b3 = ( w2 + 5.0 * w3 ) / 6.0; -} - -void crabR( double w1, double w2, double w3, - double & a1, double & a2, double & a3, - double & b1, double & b2, double & b3 ) -{ - a1 = w1 / 3.0; - a2 = ( w3 + 2.0 * w2 + 2.0 * w1 ) / 3.0; - a3 = ( 2.0 * w3 + w2 ) / 3.0; - - b1 = ( w2 + 5.0 * w1 ) / 6.0; - b2 = ( 5.0 * w3 + 5.0 * w2 + w1 ) / 6.0; - b3 = w3 / 6.0; -} - -void crwcL( double v1, double v2, double v3, double v4, double v5, - double & a1, double & a2, double & a3, - double & b1, double & b2, double & b3 ) -{ - double eps = 1.0e-6; - - // smoothness indicators - double s1 = ( 13.0 / 12.0 ) * SQR( v1 - 2.0 * v2 + v3 ) + 0.25 * SQR( v1 - 4.0 * v2 + 3.0 * v3 ); - double s2 = ( 13.0 / 12.0 ) * SQR( v2 - 2.0 * v3 + v4 ) + 0.25 * SQR( v2 - v4 ); - double s3 = ( 13.0 / 12.0 ) * SQR( v3 - 2.0 * v4 + v5 ) + 0.25 * SQR( 3.0 * v3 - 4.0 * v4 + v5 ); - - // computing nonlinear weights w1, w2, w3 - double c1 = 2.0e-1 / ( SQR( eps + s1 ) ); - double c2 = 5.0e-1 / ( SQR( eps + s2 ) ); - double c3 = 3.0e-1 / ( SQR( eps + s3 ) ); - - double w1 = c1 / ( c1 + c2 + c3 ); - double w2 = c2 / ( c1 + c2 + c3 ); - double w3 = c3 / ( c1 + c2 + c3 ); - - crabL( w1, w2, w3, a1, a2, a3, b1, b2, b3 ); -} - -void crwcR( double v1, double v2, double v3, double v4, double v5, - double & a1, double & a2, double & a3, - double & b1, double & b2, double & b3 ) -{ - double eps = 1.0e-6; - - // smoothness indicators - double s1 = ( 13.0 / 12.0 ) * SQR( v1 - 2.0 * v2 + v3 ) + 0.25 * SQR( v1 - 4.0 * v2 + 3.0 * v3 ); - double s2 = ( 13.0 / 12.0 ) * SQR( v2 - 2.0 * v3 + v4 ) + 0.25 * SQR( v2 - v4 ); - double s3 = ( 13.0 / 12.0 ) * SQR( v3 - 2.0 * v4 + v5 ) + 0.25 * SQR( 3.0 * v3 - 4.0 * v4 + v5 ); - - // computing nonlinear weights w1, w2, w3 - double c1 = 3.0e-1 / SQR( eps + s1 ); - double c2 = 5.0e-1 / SQR( eps + s2 ); - double c3 = 2.0e-1 / SQR( eps + s3 ); - - double w1 = c1 / ( c1 + c2 + c3 ); - double w2 = c2 / ( c1 + c2 + c3 ); - double w3 = c3 / ( c1 + c2 + c3 ); - - crabR( w1, w2, w3, a1, a2, a3, b1, b2, b3 ); -} - -void crwenoL( int ni, Vec1d & u, Vec1d & f ) -{ - std::vector a( ni + 1 ); - std::vector b( ni + 1 ); - std::vector c( ni + 1 ); - std::vector r( ni + 1 ); - std::vector y( ni + 1 ); - - int i, ii; - double v1, v2, v3, v4, v5; - double a1, a2, a3, b1, b2, b3; - - int ist = -1; - - i = -1; - ii = i - ist; - crabL( 0, 0, 1, a1, a2, a3, b1, b2, b3 ); - a[ ii ] = a1; - b[ ii ] = a2; - c[ ii ] = a3; - r[ ii ] = b1 * u[ i - 1 ] + b2 * u[ i ] + b3 * u[ i + 1 ]; - - for ( int i = 0; i < ni - 1; ++ i ) - { - ii = i - ist; - v1 = u[ i - 2 ]; - v2 = u[ i - 1 ]; - v3 = u[ i ]; - v4 = u[ i + 1 ]; - v5 = u[ i + 2 ]; - crwcL( v1, v2, v3, v4, v5, a1, a2, a3, b1, b2, b3 ); - a[ ii ] = a1; - b[ ii ] = a2; - c[ ii ] = a3; - r[ ii ] = b1 * u[ i - 1 ] + b2 * u[ i ] + b3 * u[ i + 1 ]; - } - - i = ni - 1; - ii = i - ist; - crabL( 1, 0, 0, a1, a2, a3, b1, b2, b3 ); - a[ ii ] = a1; - b[ ii ] = a2; - c[ ii ] = a3; - r[ ii ] = b1 * u[ i - 1 ] + b2 * u[ i ] + b3 * u[ i + 1 ]; - - thomas_algorithm( a, b, c, r, y ); - - for ( int i = 0; i < ni + 1; ++ i ) - { - f[ i ] = y[ i ]; - } - -} - -void crwenoR( int ni, Vec1d & u, Vec1d & f ) -{ - std::vector a( ni + 1 ); - std::vector b( ni + 1 ); - std::vector c( ni + 1 ); - std::vector r( ni + 1 ); - std::vector y( ni + 1 ); - - int i, ii; - double v1, v2, v3, v4, v5; - double a1, a2, a3, b1, b2, b3; - - int ist = -1; - - i = -1; - ii = i - ist; - crabR( 0, 0, 1, a1, a2, a3, b1, b2, b3 ); - a[ ii ] = a1; - b[ ii ] = a2; - c[ ii ] = a3; - r[ ii ] = b1 * u[ i ] + b2 * u[ i + 1 ] + b3 * u[ i + 2 ]; - - for ( int i = 0; i < ni - 1; ++ i ) - { - ii = i - ist; - v1 = u[ i - 1 ]; - v2 = u[ i ]; - v3 = u[ i + 1 ]; - v4 = u[ i + 2 ]; - v5 = u[ i + 3 ]; - - crwcR( v1, v2, v3, v4, v5, a1, a2, a3, b1, b2, b3 ); - - a[ ii ] = a1; - b[ ii ] = a2; - c[ ii ] = a3; - r[ ii ] = b1 * u[ i ] + b2 * u[ i + 1 ] + b3 * u[ i + 2 ]; - } - - i = ni - 1; - ii = i - ist; - crabR( 1, 0, 0, a1, a2, a3, b1, b2, b3 ); - a[ ii ] = a1; - b[ ii ] = a2; - c[ ii ] = a3; - r[ ii ] = b1 * u[ i ] + b2 * u[ i + 1 ] + b3 * u[ i + 2 ]; - - thomas_algorithm( a, b, c, r, y ); - - for ( int i = 0; i < ni + 1; ++ i ) - { - f[ i ] = y[ i ]; - } -} - - -void crwenoL( int ni, VecWrap & u, VecWrap & f ) -{ - int nequ = u.get_nequ(); - for ( int m = 0; m < nequ; ++ m ) - { - crwenoL( ni, u.vec( m ), f.vec( m ) ); - } -} - -void crwenoR( int ni, VecWrap & u, VecWrap & f ) -{ - int nequ = u.get_nequ(); - for ( int m = 0; m < nequ; ++ m ) - { - crwenoR( ni, u.vec( m ), f.vec( m ) ); - } -} - -void wenoL( int ni, VecWrap & u, VecWrap & f ) -{ - int nequ = u.get_nequ(); - for ( int m = 0; m < nequ; ++ m ) - { - wenoL( ni, u.vec( m ), f.vec( m ) ); - } -} - -void wenoR( int ni, VecWrap & u, VecWrap & f ) -{ - int nequ = u.get_nequ(); - for ( int m = 0; m < nequ; ++ m ) - { - wenoR( ni, u.vec( m ), f.vec( m ) ); - } -} - -void Upwind1L( int ni, VecWrap & u, VecWrap & f ) -{ - int nequ = u.get_nequ(); - for ( int m = 0; m < nequ; ++ m ) - { - Upwind1L( ni, u.vec( m ), f.vec( m ) ); - } -} - -void Upwind1R( int ni, VecWrap & u, VecWrap & f ) -{ - int nequ = u.get_nequ(); - for ( int m = 0; m < nequ; ++ m ) - { - Upwind1R( ni, u.vec( m ), f.vec( m ) ); - } -} \ No newline at end of file diff --git a/example/1d-linear-convection/eno3/cpp/01/Weno.h b/example/1d-linear-convection/eno3/cpp/01/Weno.h deleted file mode 100644 index 6f376907..00000000 --- a/example/1d-linear-convection/eno3/cpp/01/Weno.h +++ /dev/null @@ -1,36 +0,0 @@ -#pragma once -#include "Vec1d.h" - -double wcL( double v1, double v2, double v3, double v4, double v5 ); -double wcR( double v1, double v2, double v3, double v4, double v5 ); -void wenoL( int N, Vec1d & u, Vec1d & f ); -void wenoR( int N, Vec1d & u, Vec1d & f ); - -void Upwind1L( int N, Vec1d & u, Vec1d & f ); -void Upwind1R( int N, Vec1d & u, Vec1d & f ); - -void crabL( double w1, double w2, double w3, - double & a1, double & a2, double & a3, - double & b1, double & b2, double & b3 ); -void crabR( double w1, double w2, double w3, - double & a1, double & a2, double & a3, - double & b1, double & b2, double & b3 ); -void crwcL( double v1, double v2, double v3, double v4, double v5, - double & a1, double & a2, double & a3, - double & b1, double & b2, double & b3 ); -void crwcR( double v1, double v2, double v3, double v4, double v5, - double & a1, double & a2, double & a3, - double & b1, double & b2, double & b3 ); - -void crwenoL( int ni, Vec1d & u, Vec1d & f ); -void crwenoR( int ni, Vec1d & u, Vec1d & f ); - -void crwenoL( int ni, VecWrap & u, VecWrap & f ); -void crwenoR( int ni, VecWrap & u, VecWrap & f ); - -void wenoL( int ni, VecWrap & u, VecWrap & f ); -void wenoR( int ni, VecWrap & u, VecWrap & f ); - -void Upwind1L( int ni, VecWrap & u, VecWrap & f ); -void Upwind1R( int ni, VecWrap & u, VecWrap & f ); - diff --git a/example/1d-linear-convection/eno3/cpp/01/ZoneState.cpp b/example/1d-linear-convection/eno3/cpp/01/ZoneState.cpp deleted file mode 100644 index ff810849..00000000 --- a/example/1d-linear-convection/eno3/cpp/01/ZoneState.cpp +++ /dev/null @@ -1,20 +0,0 @@ -#include "ZoneState.h" -#include "Parallel.h" - -int ZoneState::nZones = 0; -std::vector ZoneState::pids; -std::vector ZoneState::g2lzoneids; - -bool ZoneState::IsValid( int zoneid ) -{ - return ZoneState::pids[ zoneid ] == Parallel::pid; -} - -int ZoneState::GetProcID( int zoneid ) -{ - return ZoneState::pids[ zoneid ]; -} - -int LocalZone::nZones = 0; -std::vector LocalZone::global_zoneids; - diff --git a/example/1d-linear-convection/eno3/cpp/01/ZoneState.h b/example/1d-linear-convection/eno3/cpp/01/ZoneState.h deleted file mode 100644 index 1096d632..00000000 --- a/example/1d-linear-convection/eno3/cpp/01/ZoneState.h +++ /dev/null @@ -1,21 +0,0 @@ -#pragma once -#include - -class ZoneState -{ -public: - static int nZones; - static int zone_id; - static std::vector pids; - static std::vector g2lzoneids; //global zone id to local zone id -public: - static bool IsValid( int zoneid ); - static int GetProcID( int zoneid ); -}; - -class LocalZone -{ -public: - static int nZones; - static std::vector global_zoneids; -}; \ No newline at end of file diff --git a/example/1d-linear-convection/eno3/cpp/01/burgers.json b/example/1d-linear-convection/eno3/cpp/01/burgers.json deleted file mode 100644 index 1034215d..00000000 --- a/example/1d-linear-convection/eno3/cpp/01/burgers.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "total_time" : 0.25, - "equation" : "burgers", - "iconservation" : 0, - "ifinite_volume" : 1, - "iviscous" : 0, - "nsave" : 250, - "idump_initial_field" : 1, - "scheme" : - { - "inviscid" : "lax", - "reconstruction" : "weno5", - "viscous" : "center", - "time" : "rk3" - }, - "grid" : "../burgers1d1blocksv1.cgns" -} \ No newline at end of file diff --git a/example/1d-linear-convection/eno3/cpp/01/burgers_ftcs.json b/example/1d-linear-convection/eno3/cpp/01/burgers_ftcs.json deleted file mode 100644 index 9619dfe6..00000000 --- a/example/1d-linear-convection/eno3/cpp/01/burgers_ftcs.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "total_time" : 0.25, - "equation" : "burgers", - "iconservation" : 0, - "iviscous" : 0, - "nsave" : 250, - "idump_initial_field" : 1, - "scheme" : - { - "inviscid" : "ftcs", - "viscous" : "ftcs", - "time" : "ftcs" - }, - "grid" : "../burgers1d1blocksv1.cgns" -} \ No newline at end of file diff --git a/example/1d-linear-convection/eno3/cpp/01/burgers_plot.py b/example/1d-linear-convection/eno3/cpp/01/burgers_plot.py deleted file mode 100644 index 0882aff1..00000000 --- a/example/1d-linear-convection/eno3/cpp/01/burgers_plot.py +++ /dev/null @@ -1,64 +0,0 @@ -import numpy as np -import matplotlib.pyplot as plt -import csv -import sys - -nvar = len(sys.argv) -print('nvar=',nvar) -print('sys.argv=',sys.argv) - -scheme = 'LaxFriedrichs' -if nvar >= 2: - scheme = sys.argv[1] - print('scheme=',scheme) - -with open('field_final0.csv', newline='') as csvfile: - readCSV = csv.reader(csvfile, delimiter= ' ') - icount = 0 - for row in readCSV: - icount += 1 - -ni = icount -print("ni=",ni) - -ns = 10 - -u = np.zeros( (ni, ns + 1 ) ) -x = np.zeros( (ni) ) - -for j in range(ns+1): - filename = 'field_final'+str((j)*250)+'.csv' - print('filename=',filename) - with open(filename, newline='') as csvfile: - readCSV = csv.reader(csvfile, delimiter= ' ') - i = 0 - for row in readCSV: - x[i] = float(row[0]) - u[i][j] = float(row[1]) - i += 1 - -print("u.shape=",u.shape) -n1 = u.shape[0] -n2 = u.shape[1] -print(f"n1={n1},n2={n2}") -#exit() -#x = np.linspace(0,1, num=ni) - -#sort -sorted_indices = np.argsort(x) -xt=x[sorted_indices] - -for k in range(ns+1): - ut = u[sorted_indices,k] - u[:,k] = ut[:] -tm = 0.25 - -titlename = "Inviscid Burgers Equation: WENO5+ " + scheme + " Scheme" -plt.figure("OneFLOW-CFD Solver", figsize=(6, 4), dpi=100) -for k in range(0, ns+1): - plt.plot(xt, u[:,k], linewidth=1.0, label="t="+format(tm*k/ns, ".4f")) -plt.xlabel("$x$") -plt.ylabel("$u$") -plt.title(titlename) -plt.legend(loc='upper right', fontsize='6') -plt.show() \ No newline at end of file diff --git a/example/1d-linear-convection/eno3/cpp/01/cfd.json b/example/1d-linear-convection/eno3/cpp/01/cfd.json deleted file mode 100644 index 8007b6dd..00000000 --- a/example/1d-linear-convection/eno3/cpp/01/cfd.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "total_time" : 1.0, - "equation" : "burgers", - "iviscous" : 0, - "scheme" : - { - "inviscid" : "weno5", - "viscous" : "center", - "time" : "rk1" - }, - "grid" : "../heat1d1blocks.cgns" -} \ No newline at end of file diff --git a/example/1d-linear-convection/eno3/cpp/01/heat.json b/example/1d-linear-convection/eno3/cpp/01/heat.json deleted file mode 100644 index 0febea40..00000000 --- a/example/1d-linear-convection/eno3/cpp/01/heat.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "total_time" : 1.0, - "equation" : "heat", - "iconservation" : 0, - "ifinite_volume" : 0, - "iviscous" : 0, - "nsave" : 400, - "idump_initial_field" : 1, - "scheme" : - { - "inviscid" : "lax", - "reconstruction" : "weno5", - "viscous" : "center", - "time" : "rk1" - }, - "grid" : "../heat1d2blocks.cgns" -} \ No newline at end of file diff --git a/example/1d-linear-convection/eno3/cpp/01/heat_plot.py b/example/1d-linear-convection/eno3/cpp/01/heat_plot.py deleted file mode 100644 index 2f62d1a2..00000000 --- a/example/1d-linear-convection/eno3/cpp/01/heat_plot.py +++ /dev/null @@ -1,116 +0,0 @@ -import numpy as np -import matplotlib.pyplot as plt -import csv -import sys - -#-----------------------------------------------------------------------------# -# Compute L-2 norm for a vector -#-----------------------------------------------------------------------------# -def compute_l2norm(nx,r): - rms = 0.0 - for i in range(1, nx): - rms += r[i] * r[i] - rms = np.sqrt( rms / ( ( nx - 1 ) ) ) - return rms - -def compute_max_error( nx, u_error ): - val_max = -1; - ipos = -1; - for i in range(1, nx): - if ( val_max < np.abs( u_error[ i ] ) ): - ipos = i; - val_max = np.abs( u_error[ i ] ) - print( "ipos = ", ipos ) - return val_max; - - -nt = 400 -t = 1.0 - -filename = 'field_final'+str(nt)+'.csv' - -nvar = len(sys.argv) -print('nvar=',nvar) -print('sys.argv=',sys.argv) - -labelname = "FTCS solution" -if nvar >= 2: - scheme = sys.argv[1] - print('scheme=',scheme) - labelname = scheme + ' solution' - -print("labelname=",labelname) - -with open(filename, newline='') as csvfile: - readCSV = csv.reader(csvfile, delimiter= ' ') - icount = 0 - for row in readCSV: - icount += 1 - -ni = icount -print("ni=",ni) - -x = np.zeros( (ni) ) -u = np.zeros( (ni) ) -ue= np.zeros( (ni) ) - -with open(filename, newline='') as csvfile: - readCSV = csv.reader(csvfile, delimiter= ' ') - i = 0 - for row in readCSV: - x[i] = float(row[0]) - u[i] = float(row[1]) - i += 1 -#sort -sorted_indices = np.argsort(x) -xt=x[sorted_indices] -ut=u[sorted_indices] -x=xt -u=ut - -for i in range(ni): - ue[i] = - np.exp(-t) * np.sin( np.pi * x[i] ) # theory solution - -uerror = u - ue - -nx = ni - 1 - -my_max_error = compute_max_error( nx, uerror ) - -rms_error = compute_l2norm(nx,uerror) -max_error = np.max( np.abs(uerror) ) - -#print("my_max_error = {0:.15f}".format(my_max_error)) -print("Error details: "); -print("L-2 Norm = {0}" .format(str(rms_error))); -print("Maximum Norm = {0}".format(str(max_error))); - -# create output file for L2-norm -output = open("output.txt", "w"); -output.write("Error details: \n"); -output.write("L-2 Norm = {0}\n" .format(str(rms_error))); -output.write("Maximum Norm = {0}\n".format(str(max_error))); -output.close() - -plt.figure("OneFLOW-CFD Solver", figsize=(10, 4), dpi=100) -plt.subplot(1, 2, 1) -plt.plot(x, ue, "k-", linewidth=1.0, label="Exact solution") -#plt.scatter(x, u, facecolor="none", edgecolor="blue", s=20, linewidths=0.5, label="ICP solution") -plt.scatter(x, u, facecolor="none", edgecolor="blue", s=20, linewidths=0.5, label=labelname) -plt.xlabel("$x$") -plt.ylabel("$u$") -plt.title("Solution field") -plt.legend() -plt.tight_layout() - -plt.subplot(1, 2, 2) -plt.scatter(x, np.abs(uerror), facecolor="none", edgecolor="green", s=20, linewidths=0.5) -plt.ylabel(r"$\epsilon$") -plt.xlabel("$x$") -plt.title("Discretization error") -plt.tight_layout() -plt.ticklabel_format(axis='y', style='sci', scilimits=(-4,-4)) - -plt.show(); - - diff --git a/example/1d-linear-convection/eno3/cpp/01/heaticp.json b/example/1d-linear-convection/eno3/cpp/01/heaticp.json deleted file mode 100644 index 965d3f22..00000000 --- a/example/1d-linear-convection/eno3/cpp/01/heaticp.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "total_time" : 1.0, - "equation" : "heat", - "iconservation" : "0", - "iviscous" : 0, - "scheme" : - { - "inviscid" : "weno5", - "viscous" : "center", - "time" : "icp" - }, - "grid" : "../heat1d1blocks.cgns" -} \ No newline at end of file diff --git a/example/1d-linear-convection/eno3/cpp/01/hxmath.cpp b/example/1d-linear-convection/eno3/cpp/01/hxmath.cpp deleted file mode 100644 index c1b08977..00000000 --- a/example/1d-linear-convection/eno3/cpp/01/hxmath.cpp +++ /dev/null @@ -1,30 +0,0 @@ -#include "hxmath.h" - -void thomas_algorithm( const std::vector & a, - const std::vector & b, - const std::vector & c, - const std::vector & d, - std::vector & x ) -{ - size_t N = d.size(); - - std::vector c_star( N, 0.0 ); - std::vector d_star( N, 0.0 ); - - c_star[ 0 ] = c[ 0 ] / b[ 0 ]; - d_star[ 0 ] = d[ 0 ] / b[ 0 ]; - - for ( int i = 1; i < N; ++ i ) - { - double coef = 1.0 / ( b[ i ] - a[ i ] * c_star[ i - 1 ] ); - c_star[ i ] = c[ i ] * coef; - d_star[ i ] = ( d[ i ] - a[ i ] * d_star[ i - 1 ] ) * coef; - } - - x[ N - 1 ] = d_star[ N - 1 ]; - - for ( int i = N - 2; i >= 0; -- i ) - { - x[ i ] = d_star[ i ] - c_star[ i ] * x[ i + 1 ]; - } -} \ No newline at end of file diff --git a/example/1d-linear-convection/eno3/cpp/01/hxmath.h b/example/1d-linear-convection/eno3/cpp/01/hxmath.h deleted file mode 100644 index 2c942e2a..00000000 --- a/example/1d-linear-convection/eno3/cpp/01/hxmath.h +++ /dev/null @@ -1,16 +0,0 @@ -#pragma once -#include -#include "vec1d.h" - -template -auto SQR(Args... args) { - return (... + (args * args)); -} - -void thomas_algorithm( const std::vector & a, - const std::vector & b, - const std::vector & c, - const std::vector & d, - std::vector & x ); - -using RhsPtr = void(*)(int, double, Vec1d &, Vec1d &); diff --git a/example/1d-linear-convection/eno3/cpp/01/linearconvection.json b/example/1d-linear-convection/eno3/cpp/01/linearconvection.json deleted file mode 100644 index 3ecf618c..00000000 --- a/example/1d-linear-convection/eno3/cpp/01/linearconvection.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "istart" : 0, - "total_time" : 0.025, - "dt" : 0.025, - "equation" : "linearconvection", - "iconservation" : 0, - "ifinite_volume" : 1, - "iviscous" : 0, - "nsave" : 100, - "idump_initial_field" : 1, - "scheme" : - { - "inviscid" : "eno3", - "reconstruction" : "eno3", - "viscous" : "center", - "time" : "rk1" - }, - "grid" : "../linearconvection1d.cgns" -} \ No newline at end of file diff --git a/example/1d-linear-convection/eno3/cpp/01/linearconvection1d.cgns b/example/1d-linear-convection/eno3/cpp/01/linearconvection1d.cgns deleted file mode 100644 index 9bd4494619d6bc5b5cb79dc5fc262b23eacc09e6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10746 zcmeHNeQZ-z6u)iPQnupCKsOOs2SY(VH--vMR`$WRY%nYvK_h|Ux>2*WvnwzpaT@A7JEjoMTz!_O5Yw z7Q0Iw*e8gXxEvibi0&2k)sBiD{cUcy*8)8)?lOxcY@xFvSd3|0(D2?3RbqG@4!@|F z|M+75TS?O5lY$oxzhgC;(R`j7jV2bSL{w*D8Z*}`Uo>wL8r3VU{wtr_%17E;Ph> z-oDa$N?y%Lel-Iupb_mu&67aQNdi2}9G+^Y+hs|ak&-rp>$*o9G>Y%4X>B6K|AI=+ z#ibe&LGh$#lVwe5*_?GkD_hYSxwUprTPpA2p9&AB{-K^t*8vZ2HHd-d;rPlPo|U_J zX`yqq$L`sHrs`oK5j4i?#Z4bQ8%aNcXi??VW2A$YVdBADd~V>7&_vN{<9ZJo=SOBj zZ0;ry6DG3s7O~O`gOQ%*Dn}Mu8Z*rnq07X05Gkv$msc|g8Db(9DXfsNVA@=8zEj>$ zqWpdm%ny^&jb@sWmPEhocq5Ci<@cqqq=yYa$Df@%vB}B~0RKR4E3R+s0{cB22g@aR z5;Y_QM?7zX`#Ki?s1o(iO<iyiwX zO(wMw-9tYH8eO&CY6hD^IBeh_XxV}=xnRF71|PD*+ry73f}T`NAP=Ph&^KbcO{lOhwm=UGmE+&T+mfrXf;5?cw^?KI6>|N_|ln$Qa>gY$$S;30x6Pqnu z8_*8UYgSHd$ikrrr|SUHUx*VTt%5M+#{U1;_WOaD$Nkes3TpX_ei8pBY4$ z*}wnsJNF(?Kq}$!9-6v<6fn_p)~A`aqvd^)VE!d%rsrcWPF29@crX<8j|m#~0~GfA z#dD1+Oq9*D_5~h~eS_aPLMWLi%nogfc!!>pTGu8YshB@f(H=`w6ki!U<%DKsX)!GA zKHs)69gX8BLz)s^0z%896?`SG2h#UASIa*%-}>#)c4Y{wed1NpDu^G@v7 zg?!z}*NuEvk?$JvT}Qqf$ae$zZX(|;i@G%%!r zAq@;^U;t@AA@`Fxewquf`gp7Bu2X*bK)F5DBcU`($tnEg^n^W3um1vi9)1L5a}Irdy=@I44gGBtY5ES9qCvc z`?Dw*b~?hS%UYAK!Zw*%+%B~wAwX5yCi0V$f~~LD$=4$z{PhSP0x_a}oSg6qOviaL zvvO*@9($F$f_uf_IXr2M|Er&8<3|x#yR;vQ_ierY`_S(n%+SC!X3m6i%9Ht$M+Em& z>di!`w&UaY8pt2;Pt9yQDIs23CK*#N z4KN-z?N8#DwW|PoxY!=%I56_qe*SyyM0v0e#dfs4ApMW+I}t-Ahbp%zBAt*EnsCx} zAn|NM>^;EP-i@dxq|2VTCfkx%NJ#H1wi{8(%<-nHD&RhdV>?9$q60U!TgTj0`kRML PY~PA+eD`hq^1J^43|weL diff --git a/example/1d-linear-convection/eno3/cpp/01/linearconvectionBAK.json b/example/1d-linear-convection/eno3/cpp/01/linearconvectionBAK.json deleted file mode 100644 index ceb082b6..00000000 --- a/example/1d-linear-convection/eno3/cpp/01/linearconvectionBAK.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "istart" : 0, - "total_time" : 0.625, - "dt" : 0.025, - "equation" : "linearconvection", - "iconservation" : 0, - "ifinite_volume" : 1, - "iviscous" : 0, - "nsave" : 100, - "idump_initial_field" : 1, - "scheme" : - { - "inviscid" : "eno3", - "reconstruction" : "eno3", - "viscous" : "center", - "time" : "rk1" - }, - "grid" : "../linearconvection1d.cgns" -} \ No newline at end of file diff --git a/example/1d-linear-convection/eno3/cpp/01/main.cpp b/example/1d-linear-convection/eno3/cpp/01/main.cpp deleted file mode 100644 index fcce6376..00000000 --- a/example/1d-linear-convection/eno3/cpp/01/main.cpp +++ /dev/null @@ -1,8 +0,0 @@ -#include "Solver.h" - -int main( int argc, char ** argv ) -{ - Solver solver; - solver.Run(); - return 0; -} diff --git a/example/1d-linear-convection/eno3/cpp/01/plot.py b/example/1d-linear-convection/eno3/cpp/01/plot.py deleted file mode 100644 index 41a173a6..00000000 --- a/example/1d-linear-convection/eno3/cpp/01/plot.py +++ /dev/null @@ -1,58 +0,0 @@ -import numpy as np -import matplotlib.pyplot as plt -import csv - -x_list = [] -ue_list = [] -un_list = [] -uerror_list = [] - -with open('field_final.csv', newline='') as csvfile: - readCSV = csv.reader(csvfile, delimiter= ' ') - icount = 0 - for row in readCSV: - #print(row) - #print(row[0]) - #print(row[0], row[1], row[2], row[3]) - if ( icount != 0 ) : - x_list.append(row[0]) - ue_list.append(row[1]) - un_list.append(row[2]) - uerror_list.append(row[3]) - icount += 1 - -ni = icount - 1 -print("ni=",ni) - -x = np.zeros( ni ) -ue = np.zeros( ni ) -un = np.zeros( ni ) -uerror = np.zeros( ni ) - -for i in range(0, ni): - x[i] = float(x_list[i]) - ue[i] = float(ue_list[i]) - un[i] = float(un_list[i]) - uerror[i] = float(uerror_list[i]) - -plt.figure("OneFLOW-CFD Solver", figsize=(10, 4), dpi=100) -plt.subplot(1, 2, 1) -plt.plot(x, ue, "k-", linewidth=1.0, label="Exact solution") -plt.scatter(x, un, facecolor="none", edgecolor="blue", s=20, linewidths=0.5, label="ICP solution") -plt.xlabel("$x$") -plt.ylabel("$u$") -plt.title("Solution field") -plt.legend() -plt.tight_layout() - -plt.subplot(1, 2, 2) -plt.scatter(x, np.abs(uerror), facecolor="none", edgecolor="green", s=20, linewidths=0.5) -plt.ylabel(r"$\epsilon$") -plt.xlabel("$x$") -plt.title("Discretization error") -plt.tight_layout() -plt.ticklabel_format(axis='y', style='sci', scilimits=(-4,-4)) - -plt.show(); - - diff --git a/example/1d-linear-convection/eno3/cpp/01/plotting2.jl b/example/1d-linear-convection/eno3/cpp/01/plotting2.jl deleted file mode 100644 index c74255b2..00000000 --- a/example/1d-linear-convection/eno3/cpp/01/plotting2.jl +++ /dev/null @@ -1,49 +0,0 @@ -using CSV -using DataFrames -using PyPlot -rc("font", family="Arial", size=16.0) - - -final_field = CSV.read("field_final.csv", DataFrame)#, datarow = 2, type=Float64) - -x = convert(Array,final_field[:,1]) - -u_e = convert(Array,final_field[:,2]) -u_n = convert(Array,final_field[:,3]) -u_error = convert(Array,final_field[:,4]) - -u = Array{Float64}(undef, length(u_e), 2) -u[:,1] = u_e -u[:,2] = u_n - -for i = 1:Int64(length(u_error)) - u_error[i] = abs(u_error[i]) -end - -fig = figure("FTCS", figsize=(14,6)); -ax1 = fig[:add_subplot](1,2,1); -ax2 = fig[:add_subplot](1,2,2); - -ax1.plot(x, u_e, lw=4, ls = "-", color="b", label="Exact solution") -ax1.plot(x, u_n, lw=4, ls = "--", color="r", label="FTCS solution") -ax1.set_xlabel("\$x\$") -ax1.set_ylabel("\$u\$") -ax1.set_title("Solution field") -ax1.set_xlim(-1,1) -ax1.legend(fontsize=14, loc=0) - -ax2.plot(x, u_error, marker = "o", markeredgecolor="k", - markersize=8, color="g", lw=4) -ax2.set_xlabel("\$x\$") -ax2.set_ylabel("\$ϵ\$") -ax2.set_title("Discretization error") -ax2.set_xlim(-1,1) -#ax2.legend(fontsize=14, loc=0) - -#plt[:subplot](ax1); -#plt[:subplot](ax2); - -fig.tight_layout() -fig.savefig("ftcs.pdf") - -show() diff --git a/example/1d-linear-convection/eno3/cpp/01/sod.json b/example/1d-linear-convection/eno3/cpp/01/sod.json deleted file mode 100644 index 638176c8..00000000 --- a/example/1d-linear-convection/eno3/cpp/01/sod.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "istart" : 0, - "total_time" : 0.20, - "dt" : 0.0001, - "equation" : "euler", - "iconservation" : 1, - "ifinite_volume" : 1, - "iviscous" : 0, - "nsave" : 200, - "idump_initial_field" : 1, - "scheme" : - { - "inviscid" : "lax", - "reconstruction" : "weno5", - "viscous" : "center", - "time" : "rk3" - }, - "grid" : "../sodshocktube1d4blocks.cgns" -} \ No newline at end of file diff --git a/example/1d-linear-convection/eno3/cpp/01/sod_plot.py b/example/1d-linear-convection/eno3/cpp/01/sod_plot.py deleted file mode 100644 index 2fda5d73..00000000 --- a/example/1d-linear-convection/eno3/cpp/01/sod_plot.py +++ /dev/null @@ -1,173 +0,0 @@ -import numpy as np -import matplotlib.pyplot as plt -import csv -import sys - -class MyPlot: - def __init__( self ): - self.x = [] - self.r = [] - self.u = [] - self.m = [] - self.p = [] - self.ReadData() - - def AddData( self, xm, rm, um, mm, pm ): - self.x.append( xm ) - self.r.append( rm ) - self.u.append( um ) - self.m.append( mm ) - self.p.append( pm ) - - def ReadData( self ): - with open('../sod_theory.plt', 'r') as f: - for index, line in enumerate(f): - words = line.strip().split() - self.x.append( float(words[0]) ) - self.r.append( float(words[1]) ) - self.u.append( float(words[2]) ) - self.m.append( float(words[3]) ) - self.p.append( float(words[4]) ) - self.ComputeEnergy() - - def ComputeEnergy( self ): - num = len(self.x) - self.e = np.zeros( num ) - print("self.e.len=", len(self.e)) - gama = 1.4 - for i in range(0, num ): - um = self.u[i] - rm = self.r[i] - pm = self.p[i] - self.e[i] = (1.0/(gama-1.0))* pm/rm + 0.5 * ( um * um ) - - def PlotTheory( self ): - plt.figure("Exact solution for the Sod's shock-tube problem", figsize=(10, 8), dpi=100) - plt.subplot(2, 2, 1) - plt.plot(self.x, self.r, linewidth=1.0, label="density") - plt.xlabel("$x$") - plt.ylabel(r"$\rho$") - plt.legend() - - plt.subplot(2, 2, 2) - plt.plot(self.x, self.u, linewidth=1.0, label="velocity") - plt.xlabel("$x$") - plt.ylabel(r"$u$") - plt.legend() - - plt.subplot(2, 2, 3) - plt.plot(self.x, self.m, linewidth=1.0, label="mach number") - plt.xlabel("$x$") - plt.ylabel(r"$m$") - plt.legend() - - plt.subplot(2, 2, 4) - plt.plot(self.x, self.p, linewidth=1.0, label="pressure") - plt.xlabel("$x$") - plt.ylabel(r"$p$") - plt.legend() - - plt.tight_layout() - - plt.show() - - def PlotCompare( self, x, q, title ): - numPoints = len( q[:,0] ) - print("numPoints=",numPoints) - - rr = np.zeros( numPoints ) - uu = np.zeros( numPoints ) - pp = np.zeros( numPoints ) - ee = np.zeros( numPoints ) - - gama = 1.4 - for i in range( 0, numPoints ): - rho = q[ i, 0 ] - rhou = q[ i, 1 ] - rhoe = q[ i, 2 ] - rr[i] = rho - uu[i] = rhou / rho - ee[i] = rhoe / rho - pp[i] = ( gama - 1.0 ) * ( rhoe - 0.5 * rho * ( uu[i] * uu[i] ) ) - - sizes = 4 - #plt.figure("Sod's shock-tube problem+Rusanov Scheme+WENO-5 reconstruction", figsize=(10, 8), dpi=100) - plt.figure(title, figsize=(10, 8), dpi=100) - plt.subplot(2, 2, 1) - plt.plot(self.x, self.r, color='black', linewidth=1.0, label="theory") - plt.scatter(x, rr, marker= "o", s=sizes, facecolors='none', edgecolors='blue', label="OneFLOW-CFD" ) - - plt.xlabel("$x$") - plt.ylabel(r"$\rho$") - plt.legend() - - plt.subplot(2, 2, 2) - plt.plot(self.x, self.u, color='black', linewidth=1.0, label="theory") - plt.scatter(x, uu, marker= "o", s=sizes, facecolors='none', edgecolors='red', label="OneFLOW-CFD" ) - plt.xlabel("$x$") - plt.ylabel(r"$u$") - plt.legend() - - plt.subplot(2, 2, 3) - plt.plot(self.x, self.e, color='black', linewidth=1.0, label="theory") - plt.scatter(x, ee, marker= "o", s=sizes, facecolors='none', edgecolors='green', label="OneFLOW-CFD" ) - plt.xlabel("$x$") - plt.ylabel(r"$E$") - plt.legend() - - plt.subplot(2, 2, 4) - plt.plot(self.x, self.p, color='black', linewidth=1.0, label="theory") - plt.scatter(x, pp, marker= "o", s=sizes, facecolors='none', edgecolors='orange', label="OneFLOW-CFD" ) - plt.xlabel("$x$") - plt.ylabel(r"$p$") - plt.legend() - - plt.tight_layout() - - plt.show() - -nvar = len(sys.argv) -print('nvar=',nvar) -print('sys.argv=',sys.argv) - -scheme = 'Rusanov' -nt = 2000 -if nvar >= 2: - scheme = sys.argv[1] - print('scheme=',scheme) - -if nvar >= 3: - mt = sys.argv[2] - nt = int(mt) - print('nt=',nt) - -with open('field_final0.csv', newline='') as csvfile: - readCSV = csv.reader(csvfile, delimiter= ' ') - icount = 0 - for row in readCSV: - icount += 1 - -ni = icount -print("ni=",ni) - -nm = 3 - -q = np.zeros( (ni, nm ) ) -x = np.zeros( (ni) ) - - -filename = 'field_final'+str(nt)+'.csv' - -with open(filename, newline='') as csvfile: - readCSV = csv.reader(csvfile, delimiter= ' ') - i = 0 - for row in readCSV: - x[i] = float(row[0]) - q[i][0] = float(row[1]) - q[i][1] = float(row[2]) - q[i][2] = float(row[3]) - i += 1 - -title = "Sod's shock-tube problem+ " + scheme + " Scheme+WENO-5 reconstruction" -mplot = MyPlot() -mplot.PlotCompare(x, q, title) diff --git a/example/1d-linear-convection/eno3/cpp/01/sod_sort.py b/example/1d-linear-convection/eno3/cpp/01/sod_sort.py deleted file mode 100644 index bc46ba61..00000000 --- a/example/1d-linear-convection/eno3/cpp/01/sod_sort.py +++ /dev/null @@ -1,68 +0,0 @@ -import numpy as np -import csv -import sys -import os - -nvar = len(sys.argv) -print('nvar=',nvar) -print('sys.argv=',sys.argv) - -nt = 2000 -if nvar >= 2: - mt = sys.argv[1] - nt = int(mt) - print('nt=',nt) - -with open('field_final0.csv', newline='') as csvfile: - readCSV = csv.reader(csvfile, delimiter= ' ') - icount = 0 - for row in readCSV: - icount += 1 - -ni = icount -print("ni=",ni) - -nm = 3 -q = np.zeros( (ni, nm+1) ) -x = np.zeros( (ni) ) - -filename = 'field_final'+str(nt)+'.csv' - -with open(filename, newline='') as csvfile: - readCSV = csv.reader(csvfile, delimiter= ' ') - i = 0 - for row in readCSV: - x[i] = float(row[0]) - q[i][0] = float(row[1]) - q[i][1] = float(row[2]) - q[i][2] = float(row[3]) - q[i][3] = float(row[4]) - i += 1 - -#sort -sorted_indices = np.argsort(x) -xs=x[sorted_indices] -qs=q[sorted_indices,:] - -data = [] - -for i in range(ni): - ll = [] - ll.append("{:.25f}".format(xs[i])) - ll.append("{:.25f}".format(qs[i,0])) - ll.append("{:.25f}".format(qs[i,1])) - ll.append("{:.25f}".format(qs[i,2])) - ll.append("{:.25f}".format(qs[i,3])) - data.append(ll) - -basename = os.path.basename(filename) -file_name, _ = os.path.splitext(basename) - -outfilename = file_name + '.bak' - -print("outfilename=",outfilename) - -with open(outfilename, 'w', newline='', encoding='utf-8') as csvfile: - writer = csv.writer(csvfile, delimiter=' ') - writer.writerows(data) - diff --git a/example/1d-linear-convection/eno3/cpp/01/sod_sort_on_xcoor.py b/example/1d-linear-convection/eno3/cpp/01/sod_sort_on_xcoor.py deleted file mode 100644 index b56f80b5..00000000 --- a/example/1d-linear-convection/eno3/cpp/01/sod_sort_on_xcoor.py +++ /dev/null @@ -1,85 +0,0 @@ -import numpy as np -import csv -import sys -import os - -def get_sorted_indices(arr1, arr2): - # 创建一个字典来存储原始数组的索引 - index_dict = {value: index for index, value in enumerate(arr1)} - # 使用字典来构建 index_map - index_map = [index_dict[item] for item in arr2] - return index_map - -nvar = len(sys.argv) -print('nvar=',nvar) -print('sys.argv=',sys.argv) - -nt = 2000 -if nvar >= 2: - mt = sys.argv[1] - nt = int(mt) - print('nt=',nt) - -filename_src = 'field_final'+str(nt)+'.csv' -filename_tgt = 'field_final_x_tgt.csv' -print("filename_src=",filename_src) -print("filename_tgt=",filename_tgt) - -with open(filename_src, newline='') as csvfile: - readCSV = csv.reader(csvfile, delimiter= ' ') - icount = 0 - for row in readCSV: - icount += 1 - -ni = icount -print("ni=",ni) - -nm = 3 -q = np.zeros( (ni, nm ) ) -x = np.zeros( (ni) ) -xt = np.zeros( (ni) ) - -with open(filename_src, newline='') as csvfile: - readCSV = csv.reader(csvfile, delimiter= ' ') - i = 0 - for row in readCSV: - x[i] = float(row[0]) - q[i][0] = float(row[1]) - q[i][1] = float(row[2]) - q[i][2] = float(row[3]) - i += 1 - -with open(filename_tgt, newline='') as csvfile: - readCSV = csv.reader(csvfile, delimiter= ' ') - i = 0 - for row in readCSV: - xt[i] = float(row[0]) - i += 1 - -#exit() - -#sort -sorted_indices = get_sorted_indices(x, xt) -qt=q[sorted_indices,:] - -data = [] - -for i in range(ni): - ll = [] - ll.append("{:.25f}".format(xt[i])) - ll.append("{:.25f}".format(qt[i,0])) - ll.append("{:.25f}".format(qt[i,1])) - ll.append("{:.25f}".format(qt[i,2])) - data.append(ll) - -basename = os.path.basename(filename_src) -file_name, _ = os.path.splitext(basename) - -outfilename = file_name + '.tgt' - -print("outfilename=",outfilename) - -with open(outfilename, 'w', newline='', encoding='utf-8') as csvfile: - writer = csv.writer(csvfile, delimiter=' ') - writer.writerows(data) - diff --git a/example/1d-linear-convection/eno3/cpp/01/sod_theory.plt b/example/1d-linear-convection/eno3/cpp/01/sod_theory.plt deleted file mode 100644 index 017b2a23..00000000 --- a/example/1d-linear-convection/eno3/cpp/01/sod_theory.plt +++ /dev/null @@ -1,29 +0,0 @@ -0.0 1.0 0.0 0.0 1.0 -0.26335680867601535 1.0 0.0 0.0 1.0 -0.27347447203688646 0.9648750586208616 0.042156930670296286 0.035884818144028864 0.9511729968287278 -0.28359213539775757 0.9307441341034813 0.08431386134059257 0.07228844784905321 0.9044039093345754 -0.2937097987586287 0.8975859779771813 0.12647079201088884 0.1092222222653988 0.8596199444877537 -0.3038274621194998 0.8653796467623747 0.16862772268118514 0.1466978070530514 0.8167503838854002 -0.3139451254803709 0.8341044997658321 0.21078465335148144 0.1847272126663733 0.7757265390861141 -0.324062788841242 0.8037401968759483 0.2529415840217777 0.22332280718751102 0.7364817075902278 -0.3341804522021131 0.7742666963580094 0.295098514692074 0.2624973297373015 0.6989511294611133 -0.34429811556298423 0.7456642526494588 0.3372554453623703 0.30226390449422186 0.6630719445828217 -0.35441577892385534 0.717913414155165 0.37941237603266653 0.34263605535379293 0.628783150549354 -0.36453344228472645 0.6909950210426873 0.4215693067029629 0.3836277212628337 0.5960255611808599 -0.37465110564559756 0.6648902030375431 0.46372623737325913 0.4252532722650894 0.5647417656620655 -0.38476876900646867 0.6395803772184753 0.5058831680435554 0.46752752629703953 0.5348760882982245 -0.3948864323673398 0.6150472458127165 0.5480400987138516 0.5104657667751211 0.5063745488838924 -0.4050040957282109 0.5912727939912592 0.590197029384148 0.5540837610182198 0.47918482367982607 -0.415121759089082 0.5682392876641204 0.6323539600544442 0.5983977795520808 0.4532562069932973 -0.4252394224499531 0.5459292712756086 0.6745108907247406 0.6434246163452886 0.4285395733571278 -0.4353570858108242 0.5243255655995911 0.7166678213950368 0.6891816100296887 0.4049873403027381 -0.44547474917169533 0.50341126553476 0.7588247520653331 0.7356866661615835 0.38255343172251066 -0.45559241253256644 0.48316973789989986 0.8009816827356294 0.782958280583741 0.36119324181676515 -0.4657100758934376 0.4635846192291532 0.843138613405926 0.8310155639522582 0.3408635996206424 -0.47582773925430866 0.4446398135672895 0.885295544076222 0.879878267496601 0.321522734106199 -0.48594540261517977 0.4263194902649682 0.9274524747465183 0.9295668100857784 0.3031302398550031 -0.6854904949493037 0.4263194902649682 0.9274524747465183 0.9295668100857784 0.3031302398550031 -0.6854904949493037 0.2655737448562897 0.9274524747465183 0.7336781473651145 0.3031302398550031 -0.8504311802684247 0.2655737448562897 0.9274524747465183 0.7336781473651145 0.3031302398550031 -0.8504311802684247 0.125 0.0 0.0 0.1 -1.0 0.125 0.0 0.0 0.1 diff --git a/example/1d-linear-convection/lax/python/01/lax.py b/example/1d-linear-convection/lax/python/01/lax.py new file mode 100644 index 00000000..04221071 --- /dev/null +++ b/example/1d-linear-convection/lax/python/01/lax.py @@ -0,0 +1,77 @@ +import numpy as np +import matplotlib.pyplot as plt + +# 参数设置 +a = 1.0 # 对流速度 +L = 1.0 # 计算域长度 +T = 0.4 # 总时间 +nx = 101 # 空间网格数 +dx = L / (nx - 1) # 空间步长 +cfl = 0.8 # CFL 数 +dt = cfl * dx / a # 时间步长 +nt = int(T / dt) + 1 # 时间步数 + +# 空间和时间网格 +x = np.linspace(0, L, nx) +t = np.linspace(0, T, nt) + +# 初始条件 +def initial_condition(x): + u0 = np.zeros_like(x) + for i in range(len(x)): + if 0.1 <= x[i] <= 0.3: + u0[i] = 1.0 + return u0 + +# 理论解 +def analytical_solution(x, t, a): + # 初始条件沿 x - at 平移 + x_shifted = x - a * t + return initial_condition((x_shifted + L) % L) # 周期边界条件 + +# Lax-Friedrichs 方法 +def lax_friedrichs(u0, nx, nt, dx, dt, a): + u = u0.copy() + u_new = np.zeros_like(u) + + for n in range(nt): + for i in range(1, nx-1): + # Lax-Friedrichs 通量 + f_left = 0.5 * (a * u[i] + a * u[i-1]) - 0.5 * (dx / dt) * (u[i] - u[i-1]) + f_right = 0.5 * (a * u[i+1] + a * u[i]) - 0.5 * (dx / dt) * (u[i+1] - u[i]) + # 更新 u + u_new[i] = u[i] - (dt / dx) * (f_right - f_left) + + # 边界条件(周期性) + u_new[0] = u_new[-2] + u_new[-1] = u_new[1] + + # 更新时间步 + u = u_new.copy() + + return u + +# 计算初始条件 +u0 = initial_condition(x) + +# 计算数值解 +u_numerical = lax_friedrichs(u0, nx, nt, dx, dt, a) + +# 计算理论解 +u_analytical = analytical_solution(x, T, a) + +# 可视化 +plt.figure(figsize=(10, 6)) +plt.plot(x, u_numerical, 'b-', label='Numerical (Lax-Friedrichs)') +plt.plot(x, u_analytical, 'r--', label='Analytical') +plt.xlabel('x') +plt.ylabel('u') +plt.title(f'1D Convection Equation at t = {T:.2f}') +plt.legend() +plt.grid(True) +plt.show() + +# 计算误差 +error = np.abs(u_numerical - u_analytical) +print(f"最大误差: {np.max(error):.6f}") +print(f"L2 范数误差: {np.sqrt(np.sum(error**2) * dx):.6f}") \ No newline at end of file diff --git a/example/1d-linear-convection/lax/python/01a/lax.py b/example/1d-linear-convection/lax/python/01a/lax.py new file mode 100644 index 00000000..f5b1dba7 --- /dev/null +++ b/example/1d-linear-convection/lax/python/01a/lax.py @@ -0,0 +1,87 @@ +import numpy as np +import matplotlib.pyplot as plt + +# 参数设置 +a = 1.0 # 对流速度 +L = 2.0 # 计算域长度 +nx = 41 # 空间网格数 +#nt = 25 +nt = 1 +dx = L / (nx - 1) # 空间步长 +dt = .025 +T = (nt-1)*dt +cfl = 0.1 # CFL 数 + +print(f'T={T}') +print(f'dt={dt}') +print(f'a*dt/dx={a*dt/dx}') +#dt = cfl * dx / a # 时间步长 +#nt = int(T / dt) + 1 # 时间步数 + +# 空间和时间网格 +x = np.linspace(0, L, nx) +t = np.linspace(0, T, nt) + +# 初始条件 +def initial_condition(x): + u0 = np.zeros_like(x) + for i in range(len(x)): + if 0.5 <= x[i] <= 1.0: + u0[i] = 2.0 + else: + u0[i] = 1.0 + return u0 + +# 理论解 +def analytical_solution(x, t, a): + # 初始条件沿 x - at 平移 + x_shifted = x - a * t + return initial_condition((x_shifted + L) % L) # 周期边界条件 + +# Lax-Friedrichs 方法 +def lax_friedrichs(u0, nx, nt, dx, dt, a): + u = u0.copy() + u_new = np.zeros_like(u) + + for n in range(nt): + for i in range(1, nx-1): + # Lax-Friedrichs 通量 + f_left = 0.5 * (a * u[i] + a * u[i-1]) - 0.5 * (dx / dt) * (u[i] - u[i-1]) + f_right = 0.5 * (a * u[i+1] + a * u[i]) - 0.5 * (dx / dt) * (u[i+1] - u[i]) + # 更新 u + u_new[i] = u[i] - (dt / dx) * (f_right - f_left) + + # 边界条件(周期性) + u_new[0] = u_new[-2] + u_new[-1] = u_new[1] + + # 更新时间步 + u = u_new.copy() + + return u + +# 计算初始条件 +u0 = initial_condition(x) + +# 计算数值解 +u_numerical = lax_friedrichs(u0, nx, nt, dx, dt, a) + +# 计算理论解 +u_analytical = analytical_solution(x, T, a) + +# 可视化 +plt.figure(figsize=(10, 6)) +#plt.plot(x, u_numerical, 'b-', label='Numerical (Lax-Friedrichs)') +plt.scatter(x, u_numerical, facecolor="none", edgecolor="blue", s=20, linewidths=0.5, label='Numerical (Lax-Friedrichs)') +plt.plot(x, u_analytical, 'r--', label='Analytical') +plt.xlabel('x') +plt.ylabel('u') +plt.title(f'1D Convection Equation at t = {T:.2f}') +plt.legend() +plt.grid(True) +plt.show() + +# 计算误差 +error = np.abs(u_numerical - u_analytical) +print(f"最大误差: {np.max(error):.6f}") +print(f"L2 范数误差: {np.sqrt(np.sum(error**2) * dx):.6f}") \ No newline at end of file diff --git a/example/1d-linear-convection/lax/python/02/lax.py b/example/1d-linear-convection/lax/python/02/lax.py new file mode 100644 index 00000000..bd2f810d --- /dev/null +++ b/example/1d-linear-convection/lax/python/02/lax.py @@ -0,0 +1,44 @@ +import numpy as np +import matplotlib.pyplot as plt + +N = 100 +t_min = 0 +t_max = 1 +k = (t_max-t_min)/N +x_min = 0 +x_max = 1 +a = 1 +h = (x_max-x_min)/N +alpha = a*k/(2*h) +x = np.arange(x_min, x_max+2*h, h) +u_0 = np.exp(-225*(x-0.3)**2) +u_0[np.where((x>=0.6) & (x <= 0.8))] = 1.0 +u_lf = u_0.copy() +u_cs = u_0.copy() +u_num1 = u_0.copy() +u_num2 = u_0.copy() +t = 10000 + +plt.clf() + +for j in range(N): + u_num1[j] = (u_lf[j+1]+u_lf[j-1])/2 - alpha*(u_lf[j+1]-u_lf[j-1]) + u_num2[j] = u_cs[j] - alpha*(u_cs[j+1]-u_cs[j-1]) +u_lf = u_num1.copy() +u_cs = u_num2.copy() + +u_ex = np.exp(-225*(x-0.3-(a*t)%t)**2) +u_ex[np.where((x>=0.6) & (x <= 0.8))] = 1.0 + +u_ex=u_ex%len(u_ex) +u_lf=u_lf%len(u_lf) +u_cs=u_cs%len(u_cs) + +plt.plot(x, u_ex, 'r-', label="Exact solution", fillstyle='none') +plt.plot(x, u_lf, 'o', label="Lax-Friedrichs", fillstyle='none') +plt.plot(x, u_cs, '^', label="Central scheme", fillstyle='none') +plt.axis((0, 1, -.5, 1.5)) +plt.legend(loc='lower right') +plt.suptitle("t = %1d" % (t)) + +plt.show() \ No newline at end of file diff --git a/example/1d-linear-convection/lax/python/02a/lax.py b/example/1d-linear-convection/lax/python/02a/lax.py new file mode 100644 index 00000000..ab99c31e --- /dev/null +++ b/example/1d-linear-convection/lax/python/02a/lax.py @@ -0,0 +1,45 @@ +import numpy as np +import matplotlib.pyplot as plt + +N = 100 +t_min = 0 +t_max = 1 +k = (t_max-t_min)/N +x_min = 0 +x_max = 1 +a = 1 +h = (x_max-x_min)/N +alpha = a*k/(2*h) +x = np.arange(x_min, x_max+2*h, h) +print(f'{x=}') +u_0 = np.zeros_like(x) +u_0[np.where((x>=0.6) & (x <= 0.8))] = 1.0 +u_lf = u_0.copy() +u_cs = u_0.copy() +u_num1 = u_0.copy() +u_num2 = u_0.copy() +t = 10000 + +plt.clf() + +for j in range(N): + u_num1[j] = (u_lf[j+1]+u_lf[j-1])/2 - alpha*(u_lf[j+1]-u_lf[j-1]) + u_num2[j] = u_cs[j] - alpha*(u_cs[j+1]-u_cs[j-1]) +u_lf = u_num1.copy() +u_cs = u_num2.copy() + +u_ex = np.zeros_like(x) +u_ex[np.where((x>=0.6) & (x <= 0.8))] = 1.0 + +u_ex=u_ex%len(u_ex) +u_lf=u_lf%len(u_lf) +u_cs=u_cs%len(u_cs) + +plt.plot(x, u_ex, 'r-', label="Exact solution", fillstyle='none') +plt.plot(x, u_lf, 'o', label="Lax-Friedrichs", fillstyle='none') +plt.plot(x, u_cs, '^', label="Central scheme", fillstyle='none') +plt.axis((0, 1, -.5, 1.5)) +plt.legend(loc='lower right') +plt.suptitle("t = %1d" % (t)) + +plt.show() \ No newline at end of file diff --git a/example/1d-linear-convection/lax/python/02b/lax.py b/example/1d-linear-convection/lax/python/02b/lax.py new file mode 100644 index 00000000..b903a7c6 --- /dev/null +++ b/example/1d-linear-convection/lax/python/02b/lax.py @@ -0,0 +1,46 @@ +import numpy as np +import matplotlib.pyplot as plt + +N = 41 +t_min = 0 +t_max = 1 +k = (t_max-t_min)/N +x_min = 0 +x_max = 1 +a = 1 +h = (x_max-x_min)/N +alpha = a*k/(2*h) +x = np.arange(x_min, x_max+2*h, h) +print(f'{x=}') +u_0 = np.zeros_like(x) +u_0[np.where((x>=0.6) & (x <= 0.8))] = 1.0 +u_lf = u_0.copy() +u_cs = u_0.copy() +u_num1 = u_0.copy() +u_num2 = u_0.copy() +t = 10000 + +plt.clf() + +for i in range(10): + for j in range(N): + u_num1[j] = (u_lf[j+1]+u_lf[j-1])/2 - alpha*(u_lf[j+1]-u_lf[j-1]) + u_num2[j] = u_cs[j] - alpha*(u_cs[j+1]-u_cs[j-1]) + u_lf = u_num1.copy() + u_cs = u_num2.copy() + +u_ex = np.zeros_like(x) +u_ex[np.where((x>=0.6) & (x <= 0.8))] = 1.0 + +u_ex=u_ex%len(u_ex) +u_lf=u_lf%len(u_lf) +u_cs=u_cs%len(u_cs) + +plt.plot(x, u_ex, 'r-', label="Exact solution", fillstyle='none') +plt.plot(x, u_lf, 'o', label="Lax-Friedrichs", fillstyle='none') +plt.plot(x, u_cs, '^', label="Central scheme", fillstyle='none') +plt.axis((0, 1, -.5, 1.5)) +plt.legend(loc='lower right') +plt.suptitle("t = %1d" % (t)) + +plt.show() \ No newline at end of file diff --git a/example/1d-linear-convection/lax/python/03/lax.py b/example/1d-linear-convection/lax/python/03/lax.py new file mode 100644 index 00000000..b0c7c756 --- /dev/null +++ b/example/1d-linear-convection/lax/python/03/lax.py @@ -0,0 +1,33 @@ +# LIBRARY +# vector manipulation +import numpy as np +# math functions +import math + +# THIS IS FOR PLOTTING +import matplotlib.pyplot as plt # side-stepping mpl backend +import warnings +warnings.filterwarnings("ignore") + +N=20 +Nt=10 +h=2*np.pi/N +k=1/Nt +r=k/(h*h) +time_steps=10 +time=np.arange(0,(time_steps+.5)*k,k) +x=np.arange(0,2*np.pi+h/2,h) + + +X, Y = np.meshgrid(x, time) + +fig = plt.figure() +plt.plot(X,Y,'ro'); +plt.plot(x,0*x,'bo',label='Initial Condition'); +plt.xlim((-h,2*np.pi+h)) +plt.ylim((-k,max(time)+k)) +plt.xlabel('x') +plt.ylabel('time (ms)') +plt.legend(loc='center left', bbox_to_anchor=(1, 0.5)) +plt.title(r'Discrete Grid $\Omega_h$ ',fontsize=24,y=1.08) +plt.show(); diff --git a/example/1d-linear-convection/lax/python/03a/lax.py b/example/1d-linear-convection/lax/python/03a/lax.py new file mode 100644 index 00000000..bca60033 --- /dev/null +++ b/example/1d-linear-convection/lax/python/03a/lax.py @@ -0,0 +1,45 @@ +# LIBRARY +# vector manipulation +import numpy as np +# math functions +import math + +# THIS IS FOR PLOTTING +import matplotlib.pyplot as plt # side-stepping mpl backend +import warnings +warnings.filterwarnings("ignore") + +N=20 +Nt=10 +h=2*np.pi/N +k=1/Nt +r=k/(h*h) +time_steps=10 +time=np.arange(0,(time_steps+.5)*k,k) +x=np.arange(0,2*np.pi+h/2,h) + + +w=np.zeros((N+1,time_steps+1)) +b=np.zeros(N-1) +# Initial Condition +for i in range (0,N+1): + w[i,0]=1-np.cos(x[i]) + + +fig = plt.figure(figsize=(8,4)) +plt.plot(x,w[:,0],'o:',label='Initial Condition') +plt.xlim([-0.1,max(x)+h]) +plt.title('Intitial Condition',fontsize=24) +plt.xlabel('x') +plt.ylabel('w') +plt.legend(loc='best') +plt.show() +ipos = np.zeros(N+1) +ineg = np.zeros(N+1) +for i in range(0,N+1): + ineg[i] = i-1 + ipos[i] = i+1 + + +ipos[N] = 0 +ineg[0] = N diff --git a/example/1d-linear-convection/lax/python/03b/lax.py b/example/1d-linear-convection/lax/python/03b/lax.py new file mode 100644 index 00000000..bcec7c50 --- /dev/null +++ b/example/1d-linear-convection/lax/python/03b/lax.py @@ -0,0 +1,61 @@ +# LIBRARY +# vector manipulation +import numpy as np +# math functions +import math + +# THIS IS FOR PLOTTING +import matplotlib.pyplot as plt # side-stepping mpl backend +import warnings +warnings.filterwarnings("ignore") + +N=20 +Nt=10 +h=2*np.pi/N +k=1/Nt +r=k/(h*h) +time_steps=10 +time=np.arange(0,(time_steps+.5)*k,k) +x=np.arange(0,2*np.pi+h/2,h) + + +w=np.zeros((N+1,time_steps+1)) +b=np.zeros(N-1) +# Initial Condition +for i in range (0,N+1): + w[i,0]=1-np.cos(x[i]) + +ipos = np.zeros(N+1) +ineg = np.zeros(N+1) +for i in range(0,N+1): + ineg[i] = i-1 + ipos[i] = i+1 + + +ipos[N] = 0 +ineg[0] = N + +lamba=k/h +for j in range(0,time_steps): + for i in range (0,N+1): + w[i,j+1]=(w[int(ipos[i]),j]+w[int(ineg[i]),j])/2-lamba/2*(w[int(ipos[i]),j]-w[int(ineg[i]),j]) + +fig = plt.figure(figsize=(12,6)) + +plt.subplot(121) +for j in range (1,time_steps+1): + plt.plot(x,w[:,j],'o:') +plt.xlabel('x') +plt.ylabel('w') + +plt.subplot(122) +plt.imshow(w.transpose(), aspect='auto') +plt.xticks(np.arange(len(x)), np.round(x,3),rotation=45) +plt.yticks(np.arange(len(time)), np.round(time,2)) +plt.xlabel('x') +plt.ylabel('time') +clb=plt.colorbar() +clb.set_label('Temperature (w)') +plt.suptitle('Numerical Solution of the Wave Equation'%(np.round(r,3)),fontsize=24,y=1.08) +fig.tight_layout() +plt.show() \ No newline at end of file diff --git a/example/1d-linear-convection/lax/python/03c/lax.py b/example/1d-linear-convection/lax/python/03c/lax.py new file mode 100644 index 00000000..c5c89813 --- /dev/null +++ b/example/1d-linear-convection/lax/python/03c/lax.py @@ -0,0 +1,46 @@ +# LIBRARY +# vector manipulation +import numpy as np +# math functions +import math + +# THIS IS FOR PLOTTING +import matplotlib.pyplot as plt # side-stepping mpl backend +import warnings +warnings.filterwarnings("ignore") + +N=20 +Nt=10 +h=2*np.pi/N +k=1/Nt +r=k/(h*h) +time_steps=10 +time=np.arange(0,(time_steps+.5)*k,k) +x=np.arange(0,2*np.pi+h/2,h) + +w=np.zeros((N+1,time_steps+1)) +b=np.zeros(N-1) +# Initial Condition +for i in range (0,N+1): + w[i,0]=1-np.cos(x[i]) + +ipos = np.zeros(N+1) +ineg = np.zeros(N+1) +for i in range(0,N+1): + ineg[i] = i-1 + ipos[i] = i+1 +ipos[N] = 0 +ineg[0] = N + +lamba=k/h +for j in range(0,time_steps): + for i in range (0,N+1): + w[i,j+1]=(w[int(ipos[i]),j]+w[int(ineg[i]),j])/2-lamba/2*(w[int(ipos[i]),j]-w[int(ineg[i]),j]) + +fig = plt.figure(figsize=(12,6)) +plt.plot(x,w[:,Nt-1],'o:') +plt.xlabel('x') +plt.ylabel('w') + +fig.tight_layout() +plt.show() \ No newline at end of file diff --git a/example/1d-linear-convection/lax/python/03d/lax.py b/example/1d-linear-convection/lax/python/03d/lax.py new file mode 100644 index 00000000..1fd5c32a --- /dev/null +++ b/example/1d-linear-convection/lax/python/03d/lax.py @@ -0,0 +1,50 @@ +# LIBRARY +# vector manipulation +import numpy as np +# math functions +import math + +# THIS IS FOR PLOTTING +import matplotlib.pyplot as plt # side-stepping mpl backend +import warnings +warnings.filterwarnings("ignore") + +#N=20 +N=100 +Nt=1000 +h=2.0/N +k=1/Nt +time_steps=Nt +time=np.arange(0,(time_steps+.5)*k,k) +x=np.arange(0,2+h/2,h) + +w=np.zeros((N+1,time_steps+1)) +b=np.zeros(N-1) +# Initial Condition +for i in range (0,N+1): + #w[i,0]=1-np.cos(x[i]) + if( (x[i]>=0.6) and (x[i] <= 0.8) ): + w[i,0]=1.0 + else: + w[i,0]=0.0 + +ipos = np.zeros(N+1) +ineg = np.zeros(N+1) +for i in range(0,N+1): + ineg[i] = i-1 + ipos[i] = i+1 +ipos[N] = 0 +ineg[0] = N + +lamba=k/h +for j in range(0,time_steps): + for i in range (0,N+1): + w[i,j+1]=(w[int(ipos[i]),j]+w[int(ineg[i]),j])/2-lamba/2*(w[int(ipos[i]),j]-w[int(ineg[i]),j]) + +fig = plt.figure(figsize=(12,6)) +plt.plot(x,w[:,Nt-1],'o:') +plt.xlabel('x') +plt.ylabel('w') + +fig.tight_layout() +plt.show() \ No newline at end of file diff --git a/example/1d-linear-convection/rusanov/python/01/rusanov.py b/example/1d-linear-convection/rusanov/python/01/rusanov.py new file mode 100644 index 00000000..8013491e --- /dev/null +++ b/example/1d-linear-convection/rusanov/python/01/rusanov.py @@ -0,0 +1,71 @@ +import numpy as np +import matplotlib.pyplot as plt + +# 参数设置 +a = 1.0 # 对流速度 +nx = 100 # 空间网格点数 +dx = 1.0 / nx # 空间步长 +dt = 0.005 # 时间步长(满足 CFL 条件) +t_max = 0.2 # 总模拟时间 +nt = int(t_max / dt) # 时间步数 + +# 初始化网格和初值 +x = np.linspace(0, 1, nx+1) # 空间网格(包括边界) +u = np.zeros(nx+1) # 数值解 +u_exact = np.zeros(nx+1) # 理论解 + +# 设置初始条件(方波) +for i in range(nx+1): + if 0.2 <= x[i] <= 0.4: + u[i] = 1.0 + else: + u[i] = 0.0 + +# 复制初始条件作为理论解的参考 +u_initial = u.copy() + +# Rusanov flux 函数 +def rusanov_flux(u_L, u_R, a): + F_L = a * u_L # 左状态通量 + F_R = a * u_R # 右状态通量 + alpha = abs(a) # 最大波速 + flux = 0.5 * (F_L + F_R) - 0.5 * alpha * (u_R - u_L) + return flux + +# 时间推进 +u_new = np.zeros(nx+1) +for n in range(nt): + # 计算每个单元边界的通量 + #for i in range(nx): + for i in range(1, nx-1): + f_left = rusanov_flux(u[i-1], u[i], a) + f_right = rusanov_flux(u[i], u[i+1], a) + # 更新 u + u_new[i] = u[i] - (dt / dx) * (f_right - f_left) + + # 更新边界条件(周期性边界) + u_new[0] = u_new[nx] + u_new[nx] = u_new[0] + + # 更新 u + u = u_new.copy() + +# 计算理论解(初始条件平移) +for i in range(nx+1): + x_shifted = (x[i] - a * t_max) % 1.0 # 周期性平移 + u_exact[i] = u_initial[int(x_shifted / dx)] + +# 绘图 +plt.figure(figsize=(10, 6)) +plt.plot(x, u, 'b-', label='Numerical Solution (Rusanov)') +plt.plot(x, u_exact, 'r--', label='Exact Solution') +plt.xlabel('x') +plt.ylabel('u') +plt.title(f'1D Linear Convection Equation at t = {t_max}') +plt.legend() +plt.grid(True) +plt.show() + +# 计算 L2 误差 +error = np.sqrt(np.sum((u - u_exact)**2) * dx) +print(f"L2 Error: {error:.6f}") \ No newline at end of file diff --git a/example/1d-linear-convection/rusanov/python/02/rusanov.py b/example/1d-linear-convection/rusanov/python/02/rusanov.py new file mode 100644 index 00000000..76ff3df8 --- /dev/null +++ b/example/1d-linear-convection/rusanov/python/02/rusanov.py @@ -0,0 +1,78 @@ +import numpy as np +import matplotlib.pyplot as plt + +# Rusanov flux 函数 +def rusanov_flux(u_L, u_R, a): + F_L = a * u_L # 左状态通量 + F_R = a * u_R # 右状态通量 + alpha = abs(a) # 最大波速 + flux = 0.5 * (F_L + F_R) - 0.5 * alpha * (u_R - u_L) + return flux + +# 初始条件 +def initial_condition(x): + u0 = np.zeros_like(x) + for i in range(len(x)): + if 0.5 <= x[i] <= 1.0: + u0[i] = 2.0 + else: + u0[i] = 1.0 + return u0 + +# 理论解 +def analytical_solution(x, t, a): + # 初始条件沿 x - at 平移 + x_shifted = x - a * t + return initial_condition((x_shifted + L) % L) # 周期边界条件 + +# rusanov 方法 +def rusanov(u0, nx, nt, dx, dt, c): + un = u.copy() + u_new = np.zeros_like(u) + + for n in range(nt): + for i in range(1, nx-1): + f_left = rusanov_flux(un[i-1], un[i], c) + f_right = rusanov_flux(un[i], un[i+1], c) + # 更新 u + u[i] = un[i] - (dt / dx) * (f_right - f_left) + + # 边界条件(周期性) + u[0] = u[-2] + u[-1] = u[1] + + # 更新时间步 + un = u.copy() + + return u + +nx = 41 # try changing this number from 41 to 81 and Run All ... what happens? +L = 2 +dx = L / (nx-1) +nt = 25 #nt is the number of timesteps we want to calculate +dt = .025 #dt is the amount of time each timestep covers (delta t) +c = 1 #assume wavespeed of c = 1 + +T = dt * nt +x = np.linspace(0, 2, nx) + +# 计算初始条件 +u = initial_condition(x) + +# 计算数值解 +u_numerical = rusanov(u, nx, nt, dx, dt, c) + +# 计算理论解 +u_analytical = analytical_solution(x, T, c) + +# 可视化 +plt.figure(figsize=(10, 6)) +plt.scatter(x, u_numerical, facecolor="none", edgecolor="blue", s=20, linewidths=0.5, label='Numerical (Rusanov)') +plt.plot(x, u_analytical, 'r--', label='Analytical') +plt.xlabel('x') +plt.ylabel('u') +plt.title(f'1D Convection Equation at t = {T:.2f}') +plt.legend() +plt.tight_layout() +#plt.grid(True) +plt.show() \ No newline at end of file diff --git a/example/1d-linear-convection/rusanov/python/02a/rusanov.py b/example/1d-linear-convection/rusanov/python/02a/rusanov.py new file mode 100644 index 00000000..8cbd1282 --- /dev/null +++ b/example/1d-linear-convection/rusanov/python/02a/rusanov.py @@ -0,0 +1,83 @@ +import numpy as np +import matplotlib.pyplot as plt + +# Rusanov flux 函数 +def rusanov_flux(u_L, u_R, a): + F_L = a * u_L # 左状态通量 + F_R = a * u_R # 右状态通量 + alpha = abs(a) # 最大波速 + flux = 0.5 * (F_L + F_R) - 0.5 * alpha * (u_R - u_L) + return flux + +# 初始条件 +def initial_condition(x): + u0 = np.zeros_like(x) + for i in range(len(x)): + if 0.5 <= x[i] <= 1.0: + u0[i] = 2.0 + else: + u0[i] = 1.0 + return u0 + +# 理论解 +def analytical_solution(x, t, a): + # 初始条件沿 x - at 平移 + x_shifted = x - a * t + return initial_condition((x_shifted + L) % L) # 周期边界条件 + +# rusanov 方法 +def rusanov(u0, nx, nt, dx, dt, c): + un = u.copy() + u_new = np.zeros_like(u) + + uL = np.zeros_like(u) + uR = np.zeros_like(u) + + for n in range(nt): + for i in range(0, nx-1): + uL[i] = un[i] + uR[i] = un[i+1] + for i in range(1, nx-1): + f_left = rusanov_flux(uL[i-1], uR[i-1], c) + f_right = rusanov_flux(uL[i], uR[i], c) + # 更新 u + u[i] = un[i] - (dt / dx) * (f_right - f_left) + # 边界条件(周期性) + u[0] = u[-2] + u[-1] = u[1] + + # 更新时间步 + un = u.copy() + + return u + +nx = 41 # try changing this number from 41 to 81 and Run All ... what happens? +L = 2 +dx = L / (nx-1) +nt = 25 #nt is the number of timesteps we want to calculate +dt = .025 #dt is the amount of time each timestep covers (delta t) +c = 1 #assume wavespeed of c = 1 + +T = dt * nt +x = np.linspace(0, 2, nx) + +# 计算初始条件 +u = initial_condition(x) + +# 计算数值解 +u_numerical = rusanov(u, nx, nt, dx, dt, c) + +# 计算理论解 +u_analytical = analytical_solution(x, T, c) + +# 可视化 +plt.figure(figsize=(10, 6)) +plt.scatter(x, u_numerical, facecolor="none", edgecolor="blue", s=20, linewidths=0.5, label='Numerical (Rusanov)') +plt.plot(x, u_analytical, 'r--', label='Analytical') +plt.xlabel('x') +plt.ylabel('u') +plt.title(f'1D Convection Equation at t = {T:.2f}') +plt.legend() +plt.tight_layout() +#plt.grid(True) +plt.show() \ No newline at end of file diff --git a/example/1d-linear-convection/rusanov/python/02b/rusanov.py b/example/1d-linear-convection/rusanov/python/02b/rusanov.py new file mode 100644 index 00000000..14778a35 --- /dev/null +++ b/example/1d-linear-convection/rusanov/python/02b/rusanov.py @@ -0,0 +1,84 @@ +import numpy as np +import matplotlib.pyplot as plt + +# Rusanov flux 函数 +def rusanov_flux(u_L, u_R, a): + F_L = a * u_L # 左状态通量 + F_R = a * u_R # 右状态通量 + alpha = abs(a) # 最大波速 + flux = 0.5 * (F_L + F_R) - 0.5 * alpha * (u_R - u_L) + return flux + +# 初始条件 +def initial_condition(x): + u0 = np.zeros_like(x) + for i in range(len(x)): + if 0.5 <= x[i] <= 1.0: + u0[i] = 2.0 + else: + u0[i] = 1.0 + return u0 + +# 理论解 +def analytical_solution(x, t, a): + # 初始条件沿 x - at 平移 + x_shifted = x - a * t + return initial_condition((x_shifted + L) % L) # 周期边界条件 + +# rusanov 方法 +def rusanov(u0, nx, nt, dx, dt, c): + un = u.copy() + u_new = np.zeros_like(u) + + uL = np.zeros_like(u) + uR = np.zeros_like(u) + + for n in range(nt): + for i in range(0, nx-1): + uL[i] = un[i] + uR[i] = un[i+1] + for i in range(1, nx-1): + f_left = rusanov_flux(uL[i-1], uR[i-1], c) + f_right = rusanov_flux(uL[i], uR[i], c) + # 更新 u + u[i] = un[i] - (dt / dx) * (f_right - f_left) + # 边界条件(周期性) + u[0] = u[-2] + u[-1] = u[1] + + # 更新时间步 + un = u.copy() + + return u + +nxc = 40 +nx = nxc + 1 +L = 2 +dx = L / (nxc) +nt = 25 #nt is the number of timesteps we want to calculate +dt = .025 #dt is the amount of time each timestep covers (delta t) +c = 1 #assume wavespeed of c = 1 + +T = dt * nt +x = np.linspace(0, 2, nxc + 1) + +# 计算初始条件 +u = initial_condition(x) + +# 计算数值解 +u_numerical = rusanov(u, nx, nt, dx, dt, c) + +# 计算理论解 +u_analytical = analytical_solution(x, T, c) + +# 可视化 +plt.figure(figsize=(10, 6)) +plt.scatter(x, u_numerical, facecolor="none", edgecolor="blue", s=20, linewidths=0.5, label='Numerical (Rusanov)') +plt.plot(x, u_analytical, 'r--', label='Analytical') +plt.xlabel('x') +plt.ylabel('u') +plt.title(f'1D Convection Equation at t = {T:.2f}') +plt.legend() +plt.tight_layout() +#plt.grid(True) +plt.show() \ No newline at end of file diff --git a/example/1d-linear-convection/rusanov/python/02c/rusanov.py b/example/1d-linear-convection/rusanov/python/02c/rusanov.py new file mode 100644 index 00000000..6dd58fa6 --- /dev/null +++ b/example/1d-linear-convection/rusanov/python/02c/rusanov.py @@ -0,0 +1,84 @@ +import numpy as np +import matplotlib.pyplot as plt + +# Rusanov flux 函数 +def rusanov_flux(u_L, u_R, a): + F_L = a * u_L # 左状态通量 + F_R = a * u_R # 右状态通量 + alpha = abs(a) # 最大波速 + flux = 0.5 * (F_L + F_R) - 0.5 * alpha * (u_R - u_L) + return flux + +# 初始条件 +def initial_condition(x): + u0 = np.zeros_like(x) + for i in range(len(x)): + if 0.5 <= x[i] <= 1.0: + u0[i] = 2.0 + else: + u0[i] = 1.0 + return u0 + +# 理论解 +def analytical_solution(x, t, a): + # 初始条件沿 x - at 平移 + x_shifted = x - a * t + return initial_condition((x_shifted + L) % L) # 周期边界条件 + +# rusanov 方法 +def rusanov(u0, nxc, nt, dx, dt, c): + un = u.copy() + u_new = np.zeros_like(u) + + uL = np.zeros_like(u) + uR = np.zeros_like(u) + + for n in range(nt): + for i in range(0, nxc): + uL[i] = un[i] + uR[i] = un[i+1] + for i in range(1, nxc): + f_left = rusanov_flux(uL[i-1], uR[i-1], c) + f_right = rusanov_flux(uL[i], uR[i], c) + # 更新 u + u[i] = un[i] - (dt / dx) * (f_right - f_left) + # 边界条件(周期性) + u[0] = u[-2] + u[-1] = u[1] + + # 更新时间步 + un = u.copy() + + return u + +nxc = 40 +nx = nxc + 1 +L = 2 +dx = L / (nxc) +nt = 25 #nt is the number of timesteps we want to calculate +dt = .025 #dt is the amount of time each timestep covers (delta t) +c = 1 #assume wavespeed of c = 1 + +T = dt * nt +x = np.linspace(0, 2, nxc + 1) + +# 计算初始条件 +u = initial_condition(x) + +# 计算数值解 +u_numerical = rusanov(u, nxc, nt, dx, dt, c) + +# 计算理论解 +u_analytical = analytical_solution(x, T, c) + +# 可视化 +plt.figure(figsize=(10, 6)) +plt.scatter(x, u_numerical, facecolor="none", edgecolor="blue", s=20, linewidths=0.5, label='Numerical (Rusanov)') +plt.plot(x, u_analytical, 'r--', label='Analytical') +plt.xlabel('x') +plt.ylabel('u') +plt.title(f'1D Convection Equation at t = {T:.2f}') +plt.legend() +plt.tight_layout() +#plt.grid(True) +plt.show() \ No newline at end of file diff --git a/example/1d-linear-convection/rusanov/python/02d/rusanov.py b/example/1d-linear-convection/rusanov/python/02d/rusanov.py new file mode 100644 index 00000000..58e12d17 --- /dev/null +++ b/example/1d-linear-convection/rusanov/python/02d/rusanov.py @@ -0,0 +1,103 @@ +import numpy as np +import matplotlib.pyplot as plt + +# Rusanov flux 函数 +def rusanov_flux(u_L, u_R, a): + F_L = a * u_L # 左状态通量 + F_R = a * u_R # 右状态通量 + alpha = abs(a) # 最大波速 + flux = 0.5 * (F_L + F_R) - 0.5 * alpha * (u_R - u_L) + return flux + +# 初始条件 +def initial_condition(x): + u0 = np.zeros_like(x) + for i in range(len(x)): + if 0.5 <= x[i] <= 1.0: + u0[i] = 2.0 + else: + u0[i] = 1.0 + return u0 + +def init_mesh(nxc,x,xcc): + xstart = 0.0 + xend = 2.0 + dx = (xend - xstart) / nxc + + for i in range(0, nxc+1): + x[i] = xstart + i * dx + + for i in range(0, nxc): + xcc[i] = 0.5 * (x[i] + x[i + 1]) + +# 理论解 +def analytical_solution(x, t, a): + # 初始条件沿 x - at 平移 + x_shifted = x - a * t + return initial_condition((x_shifted + L) % L) # 周期边界条件 + +# rusanov 方法 +def rusanov(u, nxc, nt, dx, dt, c): + un = u.copy() + + uL = np.zeros_like(u) + uR = np.zeros_like(u) + + for n in range(nt): + for i in range(0, nxc-1): + uL[i] = un[i] + uR[i] = un[i+1] + for i in range(1, nxc-1): + f_left = rusanov_flux(uL[i-1], uR[i-1], c) + f_right = rusanov_flux(uL[i], uR[i], c) + # 更新 u + u[i] = un[i] - (dt / dx) * (f_right - f_left) + # 边界条件(周期性) + u[0] = u[-2] + u[-1] = u[1] + + # 更新时间步 + un = u.copy() + + return u + +nxc = 40 +nx = nxc + 1 +L = 2 +dx = L / (nxc) +nt = 25 #nt is the number of timesteps we want to calculate +dt = .025 #dt is the amount of time each timestep covers (delta t) +c = 1 #assume wavespeed of c = 1 + +T = dt * nt + +x = np.zeros(nxc+1) +xcc = np.zeros(nxc) + +init_mesh(nxc,x,xcc) +#x = np.linspace(0, 2, nxc + 1) +print(f'{x=}') +print(f'{xcc=}') + + +# 计算初始条件 +#u = initial_condition(x) +u = initial_condition(xcc) + +# 计算数值解 +u_numerical = rusanov(u, nxc, nt, dx, dt, c) + +# 计算理论解 +u_analytical = analytical_solution(xcc, T, c) + +# 可视化 +plt.figure(figsize=(10, 6)) +plt.scatter(xcc, u_numerical, facecolor="none", edgecolor="blue", s=20, linewidths=0.5, label='Numerical (Rusanov)') +plt.plot(xcc, u_analytical, 'r--', label='Analytical') +plt.xlabel('x') +plt.ylabel('u') +plt.title(f'1D Convection Equation at t = {T:.2f}') +plt.legend() +plt.tight_layout() +#plt.grid(True) +plt.show() \ No newline at end of file diff --git a/example/1d-linear-convection/rusanov/python/02e/rusanov.py b/example/1d-linear-convection/rusanov/python/02e/rusanov.py new file mode 100644 index 00000000..ec9268fe --- /dev/null +++ b/example/1d-linear-convection/rusanov/python/02e/rusanov.py @@ -0,0 +1,98 @@ +import numpy as np +import matplotlib.pyplot as plt + +# Rusanov flux 函数 +def rusanov_flux(u_L, u_R, a): + F_L = a * u_L # 左状态通量 + F_R = a * u_R # 右状态通量 + alpha = abs(a) # 最大波速 + flux = 0.5 * (F_L + F_R) - 0.5 * alpha * (u_R - u_L) + return flux + +# 初始条件 +def initial_condition(x): + u0 = np.zeros_like(x) + for i in range(len(x)): + if 0.5 <= x[i] <= 1.0: + u0[i] = 2.0 + else: + u0[i] = 1.0 + return u0 + +def init_mesh(nxc,x,xcc): + xstart = 0.0 + xend = 2.0 + dx = (xend - xstart) / nxc + + for i in range(0, nxc+1): + x[i] = xstart + i * dx + + for i in range(0, nxc): + xcc[i] = 0.5 * (x[i] + x[i + 1]) + +# 理论解 +def analytical_solution(x, t, a): + # 初始条件沿 x - at 平移 + x_shifted = x - a * t + return initial_condition((x_shifted + L) % L) # 周期边界条件 + +# rusanov 方法 +def rusanov(u, nxc, nt, dx, dt, c): + un = u.copy() + + uL = np.zeros_like(u) + uR = np.zeros_like(u) + + for n in range(nt): + for i in range(0, nxc-1): + uL[i] = un[i] + uR[i] = un[i+1] + for i in range(1, nxc-1): + f_left = rusanov_flux(uL[i-1], uR[i-1], c) + f_right = rusanov_flux(uL[i], uR[i], c) + # 更新 u + u[i] = un[i] - (dt / dx) * (f_right - f_left) + # 边界条件(周期性) + u[0] = u[-2] + u[-1] = u[1] + + # 更新时间步 + un = u.copy() + + return u + +nxc = 40 +nx = nxc + 1 +L = 2 +dx = L / (nxc) +nt = 25 #nt is the number of timesteps we want to calculate +dt = .025 #dt is the amount of time each timestep covers (delta t) +c = 1 #assume wavespeed of c = 1 + +T = dt * nt + +x = np.zeros(nxc+1) +xcc = np.zeros(nxc) + +init_mesh(nxc,x,xcc) + +# 计算初始条件 +u = initial_condition(xcc) + +# 计算数值解 +u_numerical = rusanov(u, nxc, nt, dx, dt, c) + +# 计算理论解 +u_analytical = analytical_solution(xcc, T, c) + +# 可视化 +plt.figure(figsize=(10, 6)) +plt.scatter(xcc, u_numerical, facecolor="none", edgecolor="blue", s=20, linewidths=0.5, label='Numerical (Rusanov)') +plt.plot(xcc, u_analytical, 'r--', label='Analytical') +plt.xlabel('x') +plt.ylabel('u') +plt.title(f'1D Convection Equation at t = {T:.2f}') +plt.legend() +plt.tight_layout() +#plt.grid(True) +plt.show() \ No newline at end of file diff --git a/example/1d-linear-convection/weno3/python/01/weno.py b/example/1d-linear-convection/weno3/python/01/weno.py new file mode 100644 index 00000000..3dadaf90 --- /dev/null +++ b/example/1d-linear-convection/weno3/python/01/weno.py @@ -0,0 +1,372 @@ +import numpy as np +import matplotlib.pyplot as plt + +# 初始条件 +def initial_condition(x): + u0 = np.zeros_like(x) + for i in range(len(x)): + if 0.5 <= x[i] <= 1.0: + u0[i] = 2.0 + else: + u0[i] = 1.0 + return u0 + +# 理论解 +def analytical_solution(x, t, a, L): + # 初始条件沿 x - at 平移 + x_shifted = x - a * t + return initial_condition((x_shifted + L) % L) # 周期边界条件 + +def residual(q, eno): + reconstruction(q, eno) + inviscid_flux(eno.up1_2m, eno.up1_2p, eno.flux, eno) + for i in range(eno.nx): + eno.res[i] = -(eno.flux[i + 1] - eno.flux[i]) / eno.mesh.dx + +def reconstruction(q, eno): + # Choose the stencil by ENO method + eno.dd[0, 0:eno.ntcell-1] = q[0:eno.ntcell-1] + + for m in range(1, eno.iorder): + for j in range(0, eno.ntcell-1): + eno.dd[m, j] = eno.dd[m-1, j+1] - eno.dd[m-1, j] + + for i in range(eno.nx + 1): + eno.il[i] = i - 1 + for m in range(1, eno.iorder): + if abs(eno.dd[m, eno.il[i]-1+eno.ishift]) <= abs(eno.dd[m, eno.il[i]+eno.ishift]): + eno.il[i] -= 1 + + for i in range(eno.nx + 1): + eno.ir[i] = i + for m in range(1, eno.iorder): + if abs(eno.dd[m, eno.ir[i]-1+eno.ishift]) <= abs(eno.dd[m, eno.ir[i]+eno.ishift]): + eno.ir[i] -= 1 + + # Reconstruction u(j+1/2) + for i in range(eno.nx + 1): + k1 = eno.il[i] + k2 = eno.ir[i] + l1 = i - k1 + l2 = i - k2 + eno.up1_2m[i] = 0 + eno.up1_2p[i] = 0 + for m in range(eno.iorder): + eno.up1_2m[i] += q[k1 + eno.ishift + m] * eno.coef[l1, m] + eno.up1_2p[i] += q[k2 + eno.ishift + m] * eno.coef[l2, m] + +fluxnames = [ + 'Rusanov', + 'Engquist-Osher', +] + +def inviscid_flux(up1_2m, up1_2p, flux, eno): + if eno.solver.iflux == 0: + rusanov_flux(up1_2m, up1_2p, flux, eno) + else: + engquist_osher_flux(up1_2m, up1_2p, flux, eno) + +def engquist_osher_flux(up1_2m, up1_2p, flux, eno): + for i in range(eno.nx + 1): + u_L = up1_2m[i] + u_R = up1_2p[i] + + cp = 0.5 * ( eno.solver.c + abs(eno.solver.c) ) + cm = 0.5 * ( eno.solver.c - abs(eno.solver.c) ) + + flux[i] = cp * u_L + cm * u_R + +def rusanov_flux(up1_2m, up1_2p, flux, eno): + for i in range(eno.nx + 1): + u_L = up1_2m[i] + u_R = up1_2p[i] + F_L = eno.solver.c * u_L # 左状态通量 + F_R = eno.solver.c * u_R # 右状态通量 + alpha = abs(eno.solver.c) # 最大波速 + flux[i] = 0.5 * (F_L + F_R) - 0.5 * alpha * (u_R - u_L) + + +def boundary(u, eno): + for i in range(-eno.ighost, 1): + u[eno.ist - 1 + i] = u[eno.ied + i] + for i in range(1, eno.ighost + 2): + u[eno.ied + i] = u[eno.ist - 1 + i] + +def update_oldfield(qn, q): + qn[:] = q[:] + +def init_coef( iorder, coef ): + if iorder == 1: + coef[0] = [1.0] + coef[1] = [1.0] + elif iorder == 2: + coef[0] = [3.0/2.0, -1.0/2.0] + coef[1] = [1.0/2.0, 1.0/2.0] + coef[2] = [-1.0/2.0, 3.0/2.0] + elif iorder == 3: + coef[0] = [ 11.0/6.0, -7.0/6.0, 1.0/3.0 ] + coef[1] = [ 1.0/3.0, 5.0/6.0, -1.0/6.0 ] + coef[2] = [ -1.0/6.0, 5.0/6.0, 1.0/3.0 ] + coef[3] = [ 1.0/3.0, -7.0/6.0, 11.0/6.0 ] + elif iorder == 4: + coef[0] = [ 25.0/12.0, -23.0/12.0, 13.0/12.0, -1.0/4.0 ] + coef[1] = [ 1.0/4.0, 13.0/12.0, -5.0/12.0, 1.0/12.0 ] + coef[2] = [ -1.0/12.0, 7.0/12.0, 7.0/12.0, -1.0/12.0 ] + coef[3] = [ 1.0/12.0, -5.0/12.0, 13.0/12.0, 1.0/4.0 ] + coef[4] = [ -1.0/4.0, 13.0/12.0, -23.0/12.0, 25.0/12.0 ] + elif iorder == 5: + coef[0] = [ 137.0/60.0, -163.0/60.0, 137.0/60.0, -21.0/20.0, 1.0/5.0 ] + coef[1] = [ 1.0/5.0, 77.0/60.0, -43.0/60.0, 17.0/60.0, -1.0/20.0 ] + coef[2] = [ -1.0/20.0, 9.0/20.0, 47.0/60.0, -13.0/60.0, 1.0/30.0 ] + coef[3] = [ 1.0/30.0, -13.0/60.0, 47.0/60.0, 9.0/20.0, -1.0/20.0 ] + coef[4] = [ -1.0/20.0, 17.0/60.0, -43.0/60.0, 77.0/60.0, 1.0/5.0 ] + coef[5] = [ 1.0/5.0, -21.0/20.0, 137.0/60.0, -163.0/60.0, 137.0/60.0 ] + elif iorder == 6: + coef[0] = [ 49.0/20.0, -71.0/20.0, 79.0/20.0, -163.0/60.0, 31.0/30.0, -1.0/6.0 ] + coef[1] = [ 1.0/6.0, 29.0/20.0, -21.0/20.0, 37.0/60.0, -13.0/60.0, 1.0/30.0 ] + coef[2] = [ -1.0/30.0, 11.0/30.0, 19.0/20.0, -23.0/60.0, 7.0/60.0, -1.0/60.0 ] + coef[3] = [ 1.0/60.0, -2.0/15.0, 37.0/60.0, 37.0/60.0, -2.0/15.0, 1.0/60.0 ] + coef[4] = [ -1.0/60.0, 7.0/60.0, -23.0/60.0, 19.0/20.0, 11.0/30.0, -1.0/30.0 ] + coef[5] = [ 1.0/30.0, -13.0/60.0, 37.0/60.0, -21.0/20.0, 29.0/20.0, 1.0/6.0 ] + coef[6] = [ -1.0/6.0, 31.0/30.0, -163.0/60.0, 79.0/20.0, -71.0/20.0, 49.0/20.0 ] + elif iorder == 7: + coef[0] = [ 363.0/140.0, -617.0/140.0, 853.0/140.0, -2341.0/420.0, 667.0/210.0, -43.0/42.0, 1.0/7.0 ] + coef[1] = [ 1.0/7.0, 223.0/140.0, -197.0/140.0, 153.0/140.0, -241.0/420.0, 37.0/210.0, -1.0/42.0 ] + coef[2] = [ -1.0/42.0, 13.0/42.0, 153.0/140.0, -241.0/420.0, 109.0/420.0, -31.0/420.0, 1.0/105.0 ] + coef[3] = [ 1.0/105.0, -19.0/210.0, 107.0/210.0, 319.0/420.0, -101.0/420.0, 5.0/84.0, -1.0/140.0 ] + coef[4] = [ -1.0/140.0, 5.0/84.0, -101.0/420.0, 319.0/420.0, 107.0/210.0, -19.0/210.0, 1.0/105.0 ] + coef[5] = [ 1.0/105.0, -31.0/420.0, 109.0/420.0, -241.0/420.0, 153.0/140.0, 13.0/42.0, -1.0/42.0 ] + coef[6] = [ -1.0/42.0, 37.0/210.0, -241.0/420.0, 153.0/140.0, -197.0/140.0, 223.0/140.0, 1.0/7.0 ] + coef[7] = [ 1.0/7.0, -43.0/42.0, 667.0/210.0, -2341.0/420.0, 853.0/140.0, -617.0/140.0, 363.0/140.0 ] + +def init_field(eno): + for i in range(eno.ist, eno.ied + 1): + j = i - eno.ist + if 0.5 <= eno.mesh.xcc[j] <= 1.0: + eno.u[i] = 2.0 + else: + eno.u[i] = 1.0 + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def runge_kutta(eno): + rk = eno.solver.rk + if rk == 1: + runge_kutta_1(eno) + elif rk == 2: + runge_kutta_2(eno) + else: + runge_kutta_3(eno) + +def runge_kutta_1(eno): + dt = eno.solver.dt + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = eno.u[j] + dt * eno.res[i] + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def runge_kutta_2(eno): + dt = eno.solver.dt + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = eno.u[j] + dt * eno.res[i] + boundary(eno.u, eno) + + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = 0.5 * eno.un[j] + 0.5 * eno.u[j] + 0.5 * dt * eno.res[i] + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def runge_kutta_3(eno): + dt = eno.solver.dt + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = eno.u[j] + dt * eno.res[i] + boundary(eno.u, eno) + + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = 0.75 * eno.un[j] + 0.25 * eno.u[j] + 0.25 * dt * eno.res[i] + boundary(eno.u, eno) + + residual(eno.u, eno) + c1, c2, c3 = 1.0/3.0, 2.0/3.0, 2.0/3.0 + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = c1 * eno.un[j] + c2 * eno.u[j] + c3 * dt * eno.res[i] + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def get_ordinal_numbers(order): + if order == 1: + return 'st' + elif order == 2: + return 'nd' + elif order == 3: + return 'rd' + else: + return 'th' + +def visualize(eno): + with open('solution.plt', 'w') as f: + for i in range(eno.ist, eno.ied + 1): + j = i - eno.ist + f.write(f"{eno.mesh.xcc[j]:20.10e}{eno.u[i]:20.10e}\n") + + # 可视化 + u_numerical = np.copy(eno.u[eno.ist:eno.ied+1]) + print(f'u_numerical.size={u_numerical.size}') + print(f'eno.mesh.xcc.size={eno.mesh.xcc.size}') + #计算理论解 + u_analytical = analytical_solution(eno.mesh.xcc, eno.solver.T, eno.solver.c, eno.mesh.L) + print(f'u_analytical.size={u_analytical.size}') + plt.figure("OneFLOW-CFD Solver", figsize=(10, 6)) + plt.scatter(eno.mesh.xcc, u_numerical, facecolor="none", edgecolor="blue", s=20, linewidths=0.5, label=f'Numerical (Rusanov)') + plt.plot(eno.mesh.xcc, u_analytical, 'r--', label='Analytical') + plt.xlabel('x') + plt.ylabel('u') + ordinal1 = get_ordinal_numbers(eno.iorder) + ordinal2 = get_ordinal_numbers(eno.solver.rk) + plt.title(f'1D Convection Equation at t = {eno.solver.T:.3f} using {eno.iorder}{ordinal1}-order WENO and {eno.solver.rk}{ordinal2}-order Runge-Kutta methods') + plt.legend() + plt.grid(True, color='gray', linestyle='--', linewidth=0.5, alpha=0.7) + plt.tight_layout() + plt.show() + +class Mesh: + def __init__(self): + self.nx = 40 + self.L = 2.0 + self.x = np.zeros(self.nx + 1) + self.xcc = np.zeros(self.nx) + self.init_mesh() + def init_mesh(self): + xstart = 0.0 + xend = self.L + self.dx = (xend - xstart) / self.nx + + for i in range(0, self.nx+1): + self.x[i] = xstart + i * self.dx + + for i in range(0, self.nx): + self.xcc[i] = 0.5 * (self.x[i] + self.x[i + 1]) + +class Solver: + def __init__(self): + self.iflux = 0 + self.rk = 1 + self.c = 1.0 + self.T = 0.625 + self.dt = .0025 + +class Eno: + def __init__(self, solver, mesh, iorder): + self.solver = solver + self.mesh = mesh + self.nx = mesh.nx + self.iorder = iorder + self.ighost = iorder + self.ishift = self.ighost + 1 + self.ist = 0 + self.ishift + self.ied = self.nx - 1 + self.ishift + self.ntcell = self.nx + 2 * self.ishift + self.isize = iorder * (iorder + 1) + + self.il = np.zeros(self.nx + 1, dtype=int) + self.ir = np.zeros(self.nx + 1, dtype=int) + self.coef = np.zeros((iorder + 1, iorder)) + self.dd = np.zeros((iorder, self.ntcell)) + self.up1_2m = np.zeros(self.nx + 1) + self.up1_2p = np.zeros(self.nx + 1) + self.flux = np.zeros(self.nx + 1) + self.res = np.zeros(self.nx) + + # Field module variables + self.u = np.zeros(self.ntcell) + self.un = np.zeros(self.ntcell) + +def RunEno(solver, mesh, iorder): + eno = Eno(solver, mesh, iorder) + init_coef(eno.iorder, eno.coef) + init_field(eno) + + simu_time = solver.T + t = 0.0 + dt = solver.dt + while t < simu_time: + runge_kutta(eno) + if t + dt > simu_time: + dt = simu_time - t + t += dt + #print(f'T={t:.3f},runge_kutta{solver.rk},ENO{eno.iorder},{fluxnames[solver.iflux]} FLUX') + #visualize(eno) + return np.copy(eno.u[eno.ist:eno.ied+1]) + +def RunWeno(solver, mesh, iorder): + eno = Eno(solver, mesh, iorder) + init_coef(eno.iorder, eno.coef) + init_field(eno) + + simu_time = solver.T + t = 0.0 + dt = solver.dt + while t < simu_time: + runge_kutta(eno) + if t + dt > simu_time: + dt = simu_time - t + t += dt + #print(f'T={t:.3f},runge_kutta{solver.rk},ENO{eno.iorder},{fluxnames[solver.iflux]} FLUX') + visualize(eno) + return np.copy(eno.u[eno.ist:eno.ied+1]) + +def performEnoOrderAnalysis(): + iorder_max = 7 + mesh = Mesh() + solver = Solver() + #计算理论解 + u_analytical = analytical_solution(mesh.xcc, solver.T, solver.c, mesh.L) + + u_list = [] + for iorder in range(1, iorder_max+1): + u = RunEno(solver, mesh, iorder) + u_list.append(u) + + plot_eno_OrderAnalysis(solver, mesh.xcc, u_list, u_analytical) + +def performEnoTimestepAnalysis(): + mesh = Mesh() + solver = Solver() + #计算理论解 + u_analytical = analytical_solution(mesh.xcc, solver.T, solver.c, mesh.L) + + u_list = [] + dt_list = [] + solver.dt = 0.025/4 + #solver.dt = 0.025/16 + n = 12 + solver.rk = 3 + iorder = 7 + for i in range(0, n): + u = RunEno(solver, mesh, iorder) + u_list.append(u) + dt_list.append(solver.dt) + print(f'i={i+1},N={n},T={solver.T:.3f},dt={solver.dt},nt={int(solver.T/solver.dt)},runge_kutta{solver.rk},ENO{iorder},{fluxnames[solver.iflux]} FLUX') + solver.dt /= 2 + + plot_eno_TimestepAnalysis(solver, mesh.xcc, u_list, u_analytical, dt_list, iorder) + +def main(): + mesh = Mesh() + solver = Solver() + iorder = 3 + RunWeno(solver, mesh, iorder) + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/example/1d-linear-convection/weno3/python/01/weno3.py b/example/1d-linear-convection/weno3/python/01/weno3.py deleted file mode 100644 index da81ef74..00000000 --- a/example/1d-linear-convection/weno3/python/01/weno3.py +++ /dev/null @@ -1,68 +0,0 @@ -import numpy as np -import matplotlib.pyplot as plt - -# 定义求解区域的网格和时间步长 -nx = 100 # 网格数 -L = 1 # 区域长度 -dx = L / nx # 网格步长 -dt = 0.01 # 时间步长 -nt = 10 # 时间步数 -a = 1 # 对流速度 - -# 定义线性对流方程的初始条件和边界条件 -x = np.linspace(0, L, nx) -u0 = np.sin(2 * np.pi * x) # 初始条件 -u = u0.copy() -u_bc = np.concatenate((u[-3:], u, u[:3])) # 周期边界条件 - -# 定义WENO方法的参数 -epsilon = 1e-6 # 避免分母为0 -p = 2 # 权重参数 - -# 循环求解线性对流方程 -for n in range(nt): - # 计算每个子模板的光滑度指标 - beta_0 = (u_bc[2:nx+2] - u_bc[1:nx+1])**2 - beta_1 = (u_bc[3:nx+3] - u_bc[2:nx+2])**2 - beta_3 = (1/3) * ((u_bc[1:nx+1] - 2*u_bc[2:nx+2] + u_bc[3:nx+3]) / dx)**2 + \ - (1/4) * ((u_bc[3:nx+3] - u_bc[1:nx+1]) / dx)**2 - - # 计算权重 - d_0 = 1/3 - d_1 = 2/3 - d_3 = 1/3 - alpha_0 = d_0 / (beta_0 + epsilon)**p - alpha_1 = d_1 / (beta_1 + epsilon)**p - alpha_3 = d_3 / (beta_3 + epsilon)**p - w_0 = alpha_0 / (alpha_0 + alpha_1 + alpha_3) - w_1 = alpha_1 / (alpha_0 + alpha_1 + alpha_3) - w_3 = alpha_3 / (alpha_0 + alpha_1 + alpha_3) - - # 计算重构值 - f_0 = -0.5 * u_bc[1:nx+1] + 1.5 * u_bc[2:nx+2] - f_1 = 0.5 * u_bc[2:nx+2] + 0.5 * u_bc[3:nx+3] - f_3 = (-1/6) * u_bc[1:nx+1] + (5/6) * u_bc[2:nx+2] + (1/3) * u_bc[3:nx+3] - f_weno = w_0 * f_0 + w_1 * f_1 + w_3 * f_3 - - # 更新解 - u = u - dt / dx * (f_weno - np.roll(f_weno, 1)) - - # 更新边界条件 - u_bc = np.concatenate((u[-3:], u, u[:3])) - -# 计算理论解 -t = nt * dt -u_exact = np.sin(2 * np.pi * (x - a * t)) -print("at=",a * t) -print("u0=",u0) -print("u_exact=",u_exact) - -# 绘制结果 -#plt.plot(x, u, label='WENO Solution') -plt.plot(x, u_exact, label='Exact Solution', linestyle='--') -plt.plot(x, u0, label='init Solution', linestyle='--') -plt.legend() -plt.title('Comparison of WENO Solution and Exact Solution') -plt.xlabel('x') -plt.ylabel('u') -plt.show() \ No newline at end of file diff --git a/example/1d-linear-convection/weno3/python/01a/weno.py b/example/1d-linear-convection/weno3/python/01a/weno.py new file mode 100644 index 00000000..17750de2 --- /dev/null +++ b/example/1d-linear-convection/weno3/python/01a/weno.py @@ -0,0 +1,492 @@ +import numpy as np +import matplotlib.pyplot as plt + +# 初始条件 +def initial_condition(x): + u0 = np.zeros_like(x) + for i in range(len(x)): + if 0.5 <= x[i] <= 1.0: + u0[i] = 2.0 + else: + u0[i] = 1.0 + return u0 + +# 理论解 +def analytical_solution(x, t, a, L): + # 初始条件沿 x - at 平移 + x_shifted = x - a * t + return initial_condition((x_shifted + L) % L) # 周期边界条件 + +def residual(q, eno): + #reconstruction(q, eno) + WenoReconstruction(q, eno) + inviscid_flux(eno.up1_2m, eno.up1_2p, eno.flux, eno) + for i in range(eno.nx): + eno.res[i] = -(eno.flux[i + 1] - eno.flux[i]) / eno.mesh.dx + +def reconstruction(q, eno): + # Choose the stencil by ENO method + eno.dd[0, 0:eno.ntcell-1] = q[0:eno.ntcell-1] + + for m in range(1, eno.iorder): + for j in range(0, eno.ntcell-1): + eno.dd[m, j] = eno.dd[m-1, j+1] - eno.dd[m-1, j] + + for i in range(eno.nx + 1): + eno.il[i] = i - 1 + for m in range(1, eno.iorder): + if abs(eno.dd[m, eno.il[i]-1+eno.ishift]) <= abs(eno.dd[m, eno.il[i]+eno.ishift]): + eno.il[i] -= 1 + + for i in range(eno.nx + 1): + eno.ir[i] = i + for m in range(1, eno.iorder): + if abs(eno.dd[m, eno.ir[i]-1+eno.ishift]) <= abs(eno.dd[m, eno.ir[i]+eno.ishift]): + eno.ir[i] -= 1 + + # Reconstruction u(j+1/2) + for i in range(eno.nx + 1): + k1 = eno.il[i] + k2 = eno.ir[i] + l1 = i - k1 + l2 = i - k2 + eno.up1_2m[i] = 0 + eno.up1_2p[i] = 0 + for m in range(eno.iorder): + eno.up1_2m[i] += q[k1 + eno.ishift + m] * eno.coef[l1, m] + eno.up1_2p[i] += q[k2 + eno.ishift + m] * eno.coef[l2, m] + +#---------------------------------------------------------------------------# +#nonlinear weights for upwind direction +#---------------------------------------------------------------------------# +def wc3L(v1,v2,v3): + eps = 1.0e-6 + + # smoothness indicators + s0 = (v3-v2)**2 + s1 = (v2-v1)**2 + + # computing nonlinear weights w1,w2 + d0 = 2.0/3.0 + d1 = 1.0/3.0 + + c0 = d0 / ( (eps+s0)**2 ) + c1 = d1 / ( (eps+s1)**2 ) + + w0 = c0 / ( c0 + c1 ) + w1 = c1 / ( c0 + c1 ) + + # candiate stencils + q0 = 0.5 * v2 + 0.5 * v3 + q1 = -0.5 * v1 + 1.5 * v2 + + # reconstructed value at interface + f = ( w0*q0 + w1*q1 ) + + return f + +#---------------------------------------------------------------------------# +#nonlinear weights for downwind direction +#---------------------------------------------------------------------------# +def wc3R(v1,v2,v3): + eps = 1.0e-6 + + # smoothness indicators + s0 = (v2-v1)**2 + s1 = (v3-v2)**2 + + # computing nonlinear weights w1,w2 + d0 = 2.0/3.0 + d1 = 1.0/3.0 + + c0 = d0 / ( (eps+s0)**2 ) + c1 = d1 / ( (eps+s1)**2 ) + + w0 = c0 / ( c0 + c1 ) + w1 = c1 / ( c0 + c1 ) + + # candiate stencils + q0 = 0.5 * v1 + 0.5 * v2 + q1 = 1.5 * v2 - 0.5 * v3 + + # reconstructed value at interface + f = ( w0*q0 + w1*q1 ) + + return f + + +def weno3L_periodic(eno,u,f): + #i:ist-1,ist,...,ied + #j:0,1,...,nx + for i in range(eno.ist - 1, eno.ied + 1): + j = i - eno.ist + 1 + v1 = u[i-1] + v2 = u[i ] + v3 = u[i+1] + f[j] = wc3L(v1,v2,v3) + +def weno3R_periodic(eno,u,f): + #i:ist,ist+1,...,ied,ied+1 + #j:0,1,...,nx + for i in range(eno.ist, eno.ied + 2): + j = i - eno.ist + v1 = u[i-1] + v2 = u[i ] + v3 = u[i+1] + f[j] = wc3R(v1,v2,v3) + + +def WenoReconstruction(q, eno): + # Reconstruction u(j+1/2) + weno3L_periodic( eno, q, eno.up1_2m ) + weno3R_periodic( eno, q, eno.up1_2p ) + #for i in range(eno.nx + 1): + # eno.up1_2m[i] = 0 + # eno.up1_2p[i] = 0 + # for m in range(eno.iorder): + # eno.up1_2m[i] += q[k1 + eno.ishift + m] * eno.coef[l1, m] + # eno.up1_2p[i] += q[k2 + eno.ishift + m] * eno.coef[l2, m] + + +fluxnames = [ + 'Rusanov', + 'Engquist-Osher', +] + +def inviscid_flux(up1_2m, up1_2p, flux, eno): + if eno.solver.iflux == 0: + rusanov_flux(up1_2m, up1_2p, flux, eno) + else: + engquist_osher_flux(up1_2m, up1_2p, flux, eno) + +def engquist_osher_flux(up1_2m, up1_2p, flux, eno): + for i in range(eno.nx + 1): + u_L = up1_2m[i] + u_R = up1_2p[i] + + cp = 0.5 * ( eno.solver.c + abs(eno.solver.c) ) + cm = 0.5 * ( eno.solver.c - abs(eno.solver.c) ) + + flux[i] = cp * u_L + cm * u_R + +def rusanov_flux(up1_2m, up1_2p, flux, eno): + for i in range(eno.nx + 1): + u_L = up1_2m[i] + u_R = up1_2p[i] + F_L = eno.solver.c * u_L # 左状态通量 + F_R = eno.solver.c * u_R # 右状态通量 + alpha = abs(eno.solver.c) # 最大波速 + flux[i] = 0.5 * (F_L + F_R) - 0.5 * alpha * (u_R - u_L) + + +def boundary(u, eno): + for i in range(-eno.ighost, 1): + u[eno.ist - 1 + i] = u[eno.ied + i] + for i in range(1, eno.ighost + 2): + u[eno.ied + i] = u[eno.ist - 1 + i] + +def update_oldfield(qn, q): + qn[:] = q[:] + +def init_coef( iorder, coef ): + if iorder == 1: + coef[0] = [1.0] + coef[1] = [1.0] + elif iorder == 2: + coef[0] = [3.0/2.0, -1.0/2.0] + coef[1] = [1.0/2.0, 1.0/2.0] + coef[2] = [-1.0/2.0, 3.0/2.0] + elif iorder == 3: + coef[0] = [ 11.0/6.0, -7.0/6.0, 1.0/3.0 ] + coef[1] = [ 1.0/3.0, 5.0/6.0, -1.0/6.0 ] + coef[2] = [ -1.0/6.0, 5.0/6.0, 1.0/3.0 ] + coef[3] = [ 1.0/3.0, -7.0/6.0, 11.0/6.0 ] + elif iorder == 4: + coef[0] = [ 25.0/12.0, -23.0/12.0, 13.0/12.0, -1.0/4.0 ] + coef[1] = [ 1.0/4.0, 13.0/12.0, -5.0/12.0, 1.0/12.0 ] + coef[2] = [ -1.0/12.0, 7.0/12.0, 7.0/12.0, -1.0/12.0 ] + coef[3] = [ 1.0/12.0, -5.0/12.0, 13.0/12.0, 1.0/4.0 ] + coef[4] = [ -1.0/4.0, 13.0/12.0, -23.0/12.0, 25.0/12.0 ] + elif iorder == 5: + coef[0] = [ 137.0/60.0, -163.0/60.0, 137.0/60.0, -21.0/20.0, 1.0/5.0 ] + coef[1] = [ 1.0/5.0, 77.0/60.0, -43.0/60.0, 17.0/60.0, -1.0/20.0 ] + coef[2] = [ -1.0/20.0, 9.0/20.0, 47.0/60.0, -13.0/60.0, 1.0/30.0 ] + coef[3] = [ 1.0/30.0, -13.0/60.0, 47.0/60.0, 9.0/20.0, -1.0/20.0 ] + coef[4] = [ -1.0/20.0, 17.0/60.0, -43.0/60.0, 77.0/60.0, 1.0/5.0 ] + coef[5] = [ 1.0/5.0, -21.0/20.0, 137.0/60.0, -163.0/60.0, 137.0/60.0 ] + elif iorder == 6: + coef[0] = [ 49.0/20.0, -71.0/20.0, 79.0/20.0, -163.0/60.0, 31.0/30.0, -1.0/6.0 ] + coef[1] = [ 1.0/6.0, 29.0/20.0, -21.0/20.0, 37.0/60.0, -13.0/60.0, 1.0/30.0 ] + coef[2] = [ -1.0/30.0, 11.0/30.0, 19.0/20.0, -23.0/60.0, 7.0/60.0, -1.0/60.0 ] + coef[3] = [ 1.0/60.0, -2.0/15.0, 37.0/60.0, 37.0/60.0, -2.0/15.0, 1.0/60.0 ] + coef[4] = [ -1.0/60.0, 7.0/60.0, -23.0/60.0, 19.0/20.0, 11.0/30.0, -1.0/30.0 ] + coef[5] = [ 1.0/30.0, -13.0/60.0, 37.0/60.0, -21.0/20.0, 29.0/20.0, 1.0/6.0 ] + coef[6] = [ -1.0/6.0, 31.0/30.0, -163.0/60.0, 79.0/20.0, -71.0/20.0, 49.0/20.0 ] + elif iorder == 7: + coef[0] = [ 363.0/140.0, -617.0/140.0, 853.0/140.0, -2341.0/420.0, 667.0/210.0, -43.0/42.0, 1.0/7.0 ] + coef[1] = [ 1.0/7.0, 223.0/140.0, -197.0/140.0, 153.0/140.0, -241.0/420.0, 37.0/210.0, -1.0/42.0 ] + coef[2] = [ -1.0/42.0, 13.0/42.0, 153.0/140.0, -241.0/420.0, 109.0/420.0, -31.0/420.0, 1.0/105.0 ] + coef[3] = [ 1.0/105.0, -19.0/210.0, 107.0/210.0, 319.0/420.0, -101.0/420.0, 5.0/84.0, -1.0/140.0 ] + coef[4] = [ -1.0/140.0, 5.0/84.0, -101.0/420.0, 319.0/420.0, 107.0/210.0, -19.0/210.0, 1.0/105.0 ] + coef[5] = [ 1.0/105.0, -31.0/420.0, 109.0/420.0, -241.0/420.0, 153.0/140.0, 13.0/42.0, -1.0/42.0 ] + coef[6] = [ -1.0/42.0, 37.0/210.0, -241.0/420.0, 153.0/140.0, -197.0/140.0, 223.0/140.0, 1.0/7.0 ] + coef[7] = [ 1.0/7.0, -43.0/42.0, 667.0/210.0, -2341.0/420.0, 853.0/140.0, -617.0/140.0, 363.0/140.0 ] + +def init_field(eno): + for i in range(eno.ist, eno.ied + 1): + j = i - eno.ist + if 0.5 <= eno.mesh.xcc[j] <= 1.0: + eno.u[i] = 2.0 + else: + eno.u[i] = 1.0 + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def runge_kutta(eno): + rk = eno.solver.rk + if rk == 1: + runge_kutta_1(eno) + elif rk == 2: + runge_kutta_2(eno) + else: + runge_kutta_3(eno) + +def runge_kutta_1(eno): + dt = eno.solver.dt + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = eno.u[j] + dt * eno.res[i] + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def runge_kutta_2(eno): + dt = eno.solver.dt + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = eno.u[j] + dt * eno.res[i] + boundary(eno.u, eno) + + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = 0.5 * eno.un[j] + 0.5 * eno.u[j] + 0.5 * dt * eno.res[i] + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def runge_kutta_3(eno): + dt = eno.solver.dt + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = eno.u[j] + dt * eno.res[i] + boundary(eno.u, eno) + + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = 0.75 * eno.un[j] + 0.25 * eno.u[j] + 0.25 * dt * eno.res[i] + boundary(eno.u, eno) + + residual(eno.u, eno) + c1, c2, c3 = 1.0/3.0, 2.0/3.0, 2.0/3.0 + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = c1 * eno.un[j] + c2 * eno.u[j] + c3 * dt * eno.res[i] + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def get_ordinal_numbers(order): + if order == 1: + return 'st' + elif order == 2: + return 'nd' + elif order == 3: + return 'rd' + else: + return 'th' + +def visualize(eno): + with open('solution.plt', 'w') as f: + for i in range(eno.ist, eno.ied + 1): + j = i - eno.ist + f.write(f"{eno.mesh.xcc[j]:20.10e}{eno.u[i]:20.10e}\n") + + # 可视化 + u_numerical = np.copy(eno.u[eno.ist:eno.ied+1]) + print(f'u_numerical.size={u_numerical.size}') + print(f'eno.mesh.xcc.size={eno.mesh.xcc.size}') + #计算理论解 + u_analytical = analytical_solution(eno.mesh.xcc, eno.solver.T, eno.solver.c, eno.mesh.L) + print(f'u_analytical.size={u_analytical.size}') + plt.figure("OneFLOW-CFD Solver", figsize=(10, 6)) + plt.scatter(eno.mesh.xcc, u_numerical, facecolor="none", edgecolor="blue", s=20, linewidths=0.5, label=f'Numerical (Rusanov)') + plt.plot(eno.mesh.xcc, u_analytical, 'r--', label='Analytical') + plt.xlabel('x') + plt.ylabel('u') + ordinal1 = get_ordinal_numbers(eno.iorder) + ordinal2 = get_ordinal_numbers(eno.solver.rk) + plt.title(f'1D Convection Equation at t = {eno.solver.T:.3f} using {eno.iorder}{ordinal1}-order WENO and {eno.solver.rk}{ordinal2}-order Runge-Kutta methods') + plt.legend() + plt.grid(True, color='gray', linestyle='--', linewidth=0.5, alpha=0.7) + plt.tight_layout() + plt.show() + +def visualizeEno(eno): + with open('solution.plt', 'w') as f: + for i in range(eno.ist, eno.ied + 1): + j = i - eno.ist + f.write(f"{eno.mesh.xcc[j]:20.10e}{eno.u[i]:20.10e}\n") + + # 可视化 + u_numerical = np.copy(eno.u[eno.ist:eno.ied+1]) + print(f'u_numerical.size={u_numerical.size}') + print(f'eno.mesh.xcc.size={eno.mesh.xcc.size}') + #计算理论解 + u_analytical = analytical_solution(eno.mesh.xcc, eno.solver.T, eno.solver.c, eno.mesh.L) + print(f'u_analytical.size={u_analytical.size}') + plt.figure("OneFLOW-CFD Solver", figsize=(10, 6)) + plt.scatter(eno.mesh.xcc, u_numerical, facecolor="none", edgecolor="blue", s=20, linewidths=0.5, label=f'Numerical (Rusanov)') + plt.plot(eno.mesh.xcc, u_analytical, 'r--', label='Analytical') + plt.xlabel('x') + plt.ylabel('u') + ordinal1 = get_ordinal_numbers(eno.iorder) + ordinal2 = get_ordinal_numbers(eno.solver.rk) + plt.title(f'1D Convection Equation at t = {eno.solver.T:.3f} using {eno.iorder}{ordinal1}-order ENO and {eno.solver.rk}{ordinal2}-order Runge-Kutta methods') + plt.legend() + plt.grid(True, color='gray', linestyle='--', linewidth=0.5, alpha=0.7) + plt.tight_layout() + plt.show() + +class Mesh: + def __init__(self): + self.nx = 40 + self.L = 2.0 + self.x = np.zeros(self.nx + 1) + self.xcc = np.zeros(self.nx) + self.init_mesh() + def init_mesh(self): + xstart = 0.0 + xend = self.L + self.dx = (xend - xstart) / self.nx + + for i in range(0, self.nx+1): + self.x[i] = xstart + i * self.dx + + for i in range(0, self.nx): + self.xcc[i] = 0.5 * (self.x[i] + self.x[i + 1]) + +class Solver: + def __init__(self): + self.iflux = 0 + self.rk = 1 + self.c = 1.0 + self.T = 0.625 + self.dt = .0025 + +class Eno: + def __init__(self, solver, mesh, iorder): + self.solver = solver + self.mesh = mesh + self.nx = mesh.nx + self.iorder = iorder + self.ighost = iorder + self.ishift = self.ighost + 1 + self.ist = 0 + self.ishift + self.ied = self.nx - 1 + self.ishift + self.ntcell = self.nx + 2 * self.ishift + self.isize = iorder * (iorder + 1) + + self.il = np.zeros(self.nx + 1, dtype=int) + self.ir = np.zeros(self.nx + 1, dtype=int) + self.coef = np.zeros((iorder + 1, iorder)) + self.dd = np.zeros((iorder, self.ntcell)) + self.up1_2m = np.zeros(self.nx + 1) + self.up1_2p = np.zeros(self.nx + 1) + self.flux = np.zeros(self.nx + 1) + self.res = np.zeros(self.nx) + + # Field module variables + self.u = np.zeros(self.ntcell) + self.un = np.zeros(self.ntcell) + +def RunEno(solver, mesh, iorder): + eno = Eno(solver, mesh, iorder) + init_coef(eno.iorder, eno.coef) + init_field(eno) + + simu_time = solver.T + t = 0.0 + dt = solver.dt + while t < simu_time: + runge_kutta(eno) + if t + dt > simu_time: + dt = simu_time - t + t += dt + print(f'T={t:.3f},runge_kutta{solver.rk},ENO{eno.iorder},{fluxnames[solver.iflux]} FLUX') + visualizeEno(eno) + return np.copy(eno.u[eno.ist:eno.ied+1]) + +def RunWeno(solver, mesh, iorder): + eno = Eno(solver, mesh, iorder) + init_coef(eno.iorder, eno.coef) + init_field(eno) + + simu_time = solver.T + t = 0.0 + dt = solver.dt + while t < simu_time: + runge_kutta(eno) + if t + dt > simu_time: + dt = simu_time - t + t += dt + print(f'T={t:.3f},runge_kutta{solver.rk},WENO{eno.iorder},{fluxnames[solver.iflux]} FLUX') + visualize(eno) + return np.copy(eno.u[eno.ist:eno.ied+1]) + +def performEnoOrderAnalysis(): + iorder_max = 7 + mesh = Mesh() + solver = Solver() + #计算理论解 + u_analytical = analytical_solution(mesh.xcc, solver.T, solver.c, mesh.L) + + u_list = [] + for iorder in range(1, iorder_max+1): + u = RunEno(solver, mesh, iorder) + u_list.append(u) + + plot_eno_OrderAnalysis(solver, mesh.xcc, u_list, u_analytical) + +def performEnoTimestepAnalysis(): + mesh = Mesh() + solver = Solver() + #计算理论解 + u_analytical = analytical_solution(mesh.xcc, solver.T, solver.c, mesh.L) + + u_list = [] + dt_list = [] + solver.dt = 0.025/4 + #solver.dt = 0.025/16 + n = 12 + solver.rk = 3 + iorder = 7 + for i in range(0, n): + u = RunEno(solver, mesh, iorder) + u_list.append(u) + dt_list.append(solver.dt) + print(f'i={i+1},N={n},T={solver.T:.3f},dt={solver.dt},nt={int(solver.T/solver.dt)},runge_kutta{solver.rk},ENO{iorder},{fluxnames[solver.iflux]} FLUX') + solver.dt /= 2 + + plot_eno_TimestepAnalysis(solver, mesh.xcc, u_list, u_analytical, dt_list, iorder) + +def main(): + mesh = Mesh() + solver = Solver() + iorder = 3 + RunWeno(solver, mesh, iorder) + RunEno(solver, mesh, iorder) + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/example/1d-linear-convection/weno3/python/01b/weno.py b/example/1d-linear-convection/weno3/python/01b/weno.py new file mode 100644 index 00000000..4f236f89 --- /dev/null +++ b/example/1d-linear-convection/weno3/python/01b/weno.py @@ -0,0 +1,570 @@ +import numpy as np +import matplotlib.pyplot as plt + +# 初始条件 +def initial_condition(x): + u0 = np.zeros_like(x) + for i in range(len(x)): + if 0.5 <= x[i] <= 1.0: + u0[i] = 2.0 + else: + u0[i] = 1.0 + return u0 + +# 理论解 +def analytical_solution(x, t, a, L): + # 初始条件沿 x - at 平移 + x_shifted = x - a * t + return initial_condition((x_shifted + L) % L) # 周期边界条件 + +def residual(q, eno): + #reconstruction(q, eno) + WenoReconstruction(q, eno) + inviscid_flux(eno.up1_2m, eno.up1_2p, eno.flux, eno) + for i in range(eno.nx): + eno.res[i] = -(eno.flux[i + 1] - eno.flux[i]) / eno.mesh.dx + +def reconstruction(q, eno): + # Choose the stencil by ENO method + eno.dd[0, 0:eno.ntcell-1] = q[0:eno.ntcell-1] + + for m in range(1, eno.iorder): + for j in range(0, eno.ntcell-1): + eno.dd[m, j] = eno.dd[m-1, j+1] - eno.dd[m-1, j] + + for i in range(eno.nx + 1): + eno.il[i] = i - 1 + for m in range(1, eno.iorder): + if abs(eno.dd[m, eno.il[i]-1+eno.ishift]) <= abs(eno.dd[m, eno.il[i]+eno.ishift]): + eno.il[i] -= 1 + + for i in range(eno.nx + 1): + eno.ir[i] = i + for m in range(1, eno.iorder): + if abs(eno.dd[m, eno.ir[i]-1+eno.ishift]) <= abs(eno.dd[m, eno.ir[i]+eno.ishift]): + eno.ir[i] -= 1 + + # Reconstruction u(j+1/2) + for i in range(eno.nx + 1): + k1 = eno.il[i] + k2 = eno.ir[i] + l1 = i - k1 + l2 = i - k2 + eno.up1_2m[i] = 0 + eno.up1_2p[i] = 0 + for m in range(eno.iorder): + eno.up1_2m[i] += q[k1 + eno.ishift + m] * eno.coef[l1, m] + eno.up1_2p[i] += q[k2 + eno.ishift + m] * eno.coef[l2, m] + +#---------------------------------------------------------------------------# +#nonlinear weights for upwind direction +#---------------------------------------------------------------------------# +def wc3L(v1,v2,v3): + eps = 1.0e-6 + + # smoothness indicators + s0 = (v3-v2)**2 + s1 = (v2-v1)**2 + + # computing nonlinear weights w1,w2 + d0 = 2.0/3.0 + d1 = 1.0/3.0 + + c0 = d0 / ( (eps+s0)**2 ) + c1 = d1 / ( (eps+s1)**2 ) + + w0 = c0 / ( c0 + c1 ) + w1 = c1 / ( c0 + c1 ) + + # candiate stencils + q0 = 0.5 * v2 + 0.5 * v3 + q1 = -0.5 * v1 + 1.5 * v2 + + # reconstructed value at interface + f = ( w0*q0 + w1*q1 ) + + return f + +#---------------------------------------------------------------------------# +#nonlinear weights for downwind direction +#---------------------------------------------------------------------------# +def wc3R(v1,v2,v3): + eps = 1.0e-6 + + # smoothness indicators + s0 = (v2-v1)**2 + s1 = (v3-v2)**2 + + # computing nonlinear weights w1,w2 + d0 = 2.0/3.0 + d1 = 1.0/3.0 + + c0 = d0 / ( (eps+s0)**2 ) + c1 = d1 / ( (eps+s1)**2 ) + + w0 = c0 / ( c0 + c1 ) + w1 = c1 / ( c0 + c1 ) + + # candiate stencils + q0 = 0.5 * v1 + 0.5 * v2 + q1 = 1.5 * v2 - 0.5 * v3 + + # reconstructed value at interface + f = ( w0*q0 + w1*q1 ) + + return f + + +def weno3L_periodic(eno,u,f): + #i:ist-1,ist,...,ied + #j:0,1,...,nx + for i in range(eno.ist - 1, eno.ied + 1): + j = i - eno.ist + 1 + v1 = u[i-1] + v2 = u[i ] + v3 = u[i+1] + f[j] = wc3L(v1,v2,v3) + +def weno3R_periodic(eno,u,f): + #i:ist,ist+1,...,ied,ied+1 + #j:0,1,...,nx + for i in range(eno.ist, eno.ied + 2): + j = i - eno.ist + v1 = u[i-1] + v2 = u[i ] + v3 = u[i+1] + f[j] = wc3R(v1,v2,v3) + + +def WenoReconstruction(q, eno): + # Reconstruction u(j+1/2) + weno3L_periodic( eno, q, eno.up1_2m ) + weno3R_periodic( eno, q, eno.up1_2p ) + #for i in range(eno.nx + 1): + # eno.up1_2m[i] = 0 + # eno.up1_2p[i] = 0 + # for m in range(eno.iorder): + # eno.up1_2m[i] += q[k1 + eno.ishift + m] * eno.coef[l1, m] + # eno.up1_2p[i] += q[k2 + eno.ishift + m] * eno.coef[l2, m] + + +fluxnames = [ + 'Rusanov', + 'Engquist-Osher', +] + +def inviscid_flux(up1_2m, up1_2p, flux, eno): + if eno.solver.iflux == 0: + rusanov_flux(up1_2m, up1_2p, flux, eno) + else: + engquist_osher_flux(up1_2m, up1_2p, flux, eno) + +def engquist_osher_flux(up1_2m, up1_2p, flux, eno): + for i in range(eno.nx + 1): + u_L = up1_2m[i] + u_R = up1_2p[i] + + cp = 0.5 * ( eno.solver.c + abs(eno.solver.c) ) + cm = 0.5 * ( eno.solver.c - abs(eno.solver.c) ) + + flux[i] = cp * u_L + cm * u_R + +def rusanov_flux(up1_2m, up1_2p, flux, eno): + for i in range(eno.nx + 1): + u_L = up1_2m[i] + u_R = up1_2p[i] + F_L = eno.solver.c * u_L # 左状态通量 + F_R = eno.solver.c * u_R # 右状态通量 + alpha = abs(eno.solver.c) # 最大波速 + flux[i] = 0.5 * (F_L + F_R) - 0.5 * alpha * (u_R - u_L) + + +def boundary(u, eno): + for i in range(-eno.ighost, 1): + u[eno.ist - 1 + i] = u[eno.ied + i] + for i in range(1, eno.ighost + 2): + u[eno.ied + i] = u[eno.ist - 1 + i] + +def update_oldfield(qn, q): + qn[:] = q[:] + +def init_coef( iorder, coef ): + if iorder == 1: + coef[0] = [1.0] + coef[1] = [1.0] + elif iorder == 2: + coef[0] = [3.0/2.0, -1.0/2.0] + coef[1] = [1.0/2.0, 1.0/2.0] + coef[2] = [-1.0/2.0, 3.0/2.0] + elif iorder == 3: + coef[0] = [ 11.0/6.0, -7.0/6.0, 1.0/3.0 ] + coef[1] = [ 1.0/3.0, 5.0/6.0, -1.0/6.0 ] + coef[2] = [ -1.0/6.0, 5.0/6.0, 1.0/3.0 ] + coef[3] = [ 1.0/3.0, -7.0/6.0, 11.0/6.0 ] + elif iorder == 4: + coef[0] = [ 25.0/12.0, -23.0/12.0, 13.0/12.0, -1.0/4.0 ] + coef[1] = [ 1.0/4.0, 13.0/12.0, -5.0/12.0, 1.0/12.0 ] + coef[2] = [ -1.0/12.0, 7.0/12.0, 7.0/12.0, -1.0/12.0 ] + coef[3] = [ 1.0/12.0, -5.0/12.0, 13.0/12.0, 1.0/4.0 ] + coef[4] = [ -1.0/4.0, 13.0/12.0, -23.0/12.0, 25.0/12.0 ] + elif iorder == 5: + coef[0] = [ 137.0/60.0, -163.0/60.0, 137.0/60.0, -21.0/20.0, 1.0/5.0 ] + coef[1] = [ 1.0/5.0, 77.0/60.0, -43.0/60.0, 17.0/60.0, -1.0/20.0 ] + coef[2] = [ -1.0/20.0, 9.0/20.0, 47.0/60.0, -13.0/60.0, 1.0/30.0 ] + coef[3] = [ 1.0/30.0, -13.0/60.0, 47.0/60.0, 9.0/20.0, -1.0/20.0 ] + coef[4] = [ -1.0/20.0, 17.0/60.0, -43.0/60.0, 77.0/60.0, 1.0/5.0 ] + coef[5] = [ 1.0/5.0, -21.0/20.0, 137.0/60.0, -163.0/60.0, 137.0/60.0 ] + elif iorder == 6: + coef[0] = [ 49.0/20.0, -71.0/20.0, 79.0/20.0, -163.0/60.0, 31.0/30.0, -1.0/6.0 ] + coef[1] = [ 1.0/6.0, 29.0/20.0, -21.0/20.0, 37.0/60.0, -13.0/60.0, 1.0/30.0 ] + coef[2] = [ -1.0/30.0, 11.0/30.0, 19.0/20.0, -23.0/60.0, 7.0/60.0, -1.0/60.0 ] + coef[3] = [ 1.0/60.0, -2.0/15.0, 37.0/60.0, 37.0/60.0, -2.0/15.0, 1.0/60.0 ] + coef[4] = [ -1.0/60.0, 7.0/60.0, -23.0/60.0, 19.0/20.0, 11.0/30.0, -1.0/30.0 ] + coef[5] = [ 1.0/30.0, -13.0/60.0, 37.0/60.0, -21.0/20.0, 29.0/20.0, 1.0/6.0 ] + coef[6] = [ -1.0/6.0, 31.0/30.0, -163.0/60.0, 79.0/20.0, -71.0/20.0, 49.0/20.0 ] + elif iorder == 7: + coef[0] = [ 363.0/140.0, -617.0/140.0, 853.0/140.0, -2341.0/420.0, 667.0/210.0, -43.0/42.0, 1.0/7.0 ] + coef[1] = [ 1.0/7.0, 223.0/140.0, -197.0/140.0, 153.0/140.0, -241.0/420.0, 37.0/210.0, -1.0/42.0 ] + coef[2] = [ -1.0/42.0, 13.0/42.0, 153.0/140.0, -241.0/420.0, 109.0/420.0, -31.0/420.0, 1.0/105.0 ] + coef[3] = [ 1.0/105.0, -19.0/210.0, 107.0/210.0, 319.0/420.0, -101.0/420.0, 5.0/84.0, -1.0/140.0 ] + coef[4] = [ -1.0/140.0, 5.0/84.0, -101.0/420.0, 319.0/420.0, 107.0/210.0, -19.0/210.0, 1.0/105.0 ] + coef[5] = [ 1.0/105.0, -31.0/420.0, 109.0/420.0, -241.0/420.0, 153.0/140.0, 13.0/42.0, -1.0/42.0 ] + coef[6] = [ -1.0/42.0, 37.0/210.0, -241.0/420.0, 153.0/140.0, -197.0/140.0, 223.0/140.0, 1.0/7.0 ] + coef[7] = [ 1.0/7.0, -43.0/42.0, 667.0/210.0, -2341.0/420.0, 853.0/140.0, -617.0/140.0, 363.0/140.0 ] + +def init_field(eno): + for i in range(eno.ist, eno.ied + 1): + j = i - eno.ist + if 0.5 <= eno.mesh.xcc[j] <= 1.0: + eno.u[i] = 2.0 + else: + eno.u[i] = 1.0 + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def runge_kutta(eno): + rk = eno.solver.rk + if rk == 1: + runge_kutta_1(eno) + elif rk == 2: + runge_kutta_2(eno) + else: + runge_kutta_3(eno) + +def runge_kutta_1(eno): + dt = eno.solver.dt + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = eno.u[j] + dt * eno.res[i] + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def runge_kutta_2(eno): + dt = eno.solver.dt + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = eno.u[j] + dt * eno.res[i] + boundary(eno.u, eno) + + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = 0.5 * eno.un[j] + 0.5 * eno.u[j] + 0.5 * dt * eno.res[i] + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def runge_kutta_3(eno): + dt = eno.solver.dt + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = eno.u[j] + dt * eno.res[i] + boundary(eno.u, eno) + + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = 0.75 * eno.un[j] + 0.25 * eno.u[j] + 0.25 * dt * eno.res[i] + boundary(eno.u, eno) + + residual(eno.u, eno) + c1, c2, c3 = 1.0/3.0, 2.0/3.0, 2.0/3.0 + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = c1 * eno.un[j] + c2 * eno.u[j] + c3 * dt * eno.res[i] + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def get_ordinal_numbers(order): + if order == 1: + return 'st' + elif order == 2: + return 'nd' + elif order == 3: + return 'rd' + else: + return 'th' + +def visualize(eno): + with open('solution.plt', 'w') as f: + for i in range(eno.ist, eno.ied + 1): + j = i - eno.ist + f.write(f"{eno.mesh.xcc[j]:20.10e}{eno.u[i]:20.10e}\n") + + # 可视化 + u_numerical = np.copy(eno.u[eno.ist:eno.ied+1]) + print(f'u_numerical.size={u_numerical.size}') + print(f'eno.mesh.xcc.size={eno.mesh.xcc.size}') + #计算理论解 + u_analytical = analytical_solution(eno.mesh.xcc, eno.solver.T, eno.solver.c, eno.mesh.L) + print(f'u_analytical.size={u_analytical.size}') + plt.figure("OneFLOW-CFD Solver", figsize=(10, 6)) + plt.scatter(eno.mesh.xcc, u_numerical, facecolor="none", edgecolor="blue", s=20, linewidths=0.5, label=f'Numerical (Rusanov)') + plt.plot(eno.mesh.xcc, u_analytical, 'r--', label='Analytical') + plt.xlabel('x') + plt.ylabel('u') + ordinal1 = get_ordinal_numbers(eno.iorder) + ordinal2 = get_ordinal_numbers(eno.solver.rk) + plt.title(f'1D Convection Equation at t = {eno.solver.T:.3f} using {eno.iorder}{ordinal1}-order WENO and {eno.solver.rk}{ordinal2}-order Runge-Kutta methods') + plt.legend() + plt.grid(True, color='gray', linestyle='--', linewidth=0.5, alpha=0.7) + plt.tight_layout() + plt.show() + +def visualizeEno(eno): + with open('solution.plt', 'w') as f: + for i in range(eno.ist, eno.ied + 1): + j = i - eno.ist + f.write(f"{eno.mesh.xcc[j]:20.10e}{eno.u[i]:20.10e}\n") + + # 可视化 + u_numerical = np.copy(eno.u[eno.ist:eno.ied+1]) + print(f'u_numerical.size={u_numerical.size}') + print(f'eno.mesh.xcc.size={eno.mesh.xcc.size}') + #计算理论解 + u_analytical = analytical_solution(eno.mesh.xcc, eno.solver.T, eno.solver.c, eno.mesh.L) + print(f'u_analytical.size={u_analytical.size}') + plt.figure("OneFLOW-CFD Solver", figsize=(10, 6)) + plt.scatter(eno.mesh.xcc, u_numerical, facecolor="none", edgecolor="blue", s=20, linewidths=0.5, label=f'Numerical (Rusanov)') + plt.plot(eno.mesh.xcc, u_analytical, 'r--', label='Analytical') + plt.xlabel('x') + plt.ylabel('u') + ordinal1 = get_ordinal_numbers(eno.iorder) + ordinal2 = get_ordinal_numbers(eno.solver.rk) + plt.title(f'1D Convection Equation at t = {eno.solver.T:.3f} using {eno.iorder}{ordinal1}-order ENO and {eno.solver.rk}{ordinal2}-order Runge-Kutta methods') + plt.legend() + plt.grid(True, color='gray', linestyle='--', linewidth=0.5, alpha=0.7) + plt.tight_layout() + plt.show() + +class Mesh: + def __init__(self): + self.nx = 40 + self.L = 2.0 + self.x = np.zeros(self.nx + 1) + self.xcc = np.zeros(self.nx) + self.init_mesh() + def init_mesh(self): + xstart = 0.0 + xend = self.L + self.dx = (xend - xstart) / self.nx + + for i in range(0, self.nx+1): + self.x[i] = xstart + i * self.dx + + for i in range(0, self.nx): + self.xcc[i] = 0.5 * (self.x[i] + self.x[i + 1]) + +class Solver: + def __init__(self): + self.iflux = 0 + self.rk = 1 + self.c = 1.0 + self.T = 0.625 + self.dt = .0025 + +class Eno: + def __init__(self, solver, mesh, iorder): + self.solver = solver + self.mesh = mesh + self.nx = mesh.nx + self.iorder = iorder + self.ighost = iorder + self.ishift = self.ighost + 1 + self.ist = 0 + self.ishift + self.ied = self.nx - 1 + self.ishift + self.ntcell = self.nx + 2 * self.ishift + self.isize = iorder * (iorder + 1) + + self.il = np.zeros(self.nx + 1, dtype=int) + self.ir = np.zeros(self.nx + 1, dtype=int) + self.coef = np.zeros((iorder + 1, iorder)) + self.dd = np.zeros((iorder, self.ntcell)) + self.up1_2m = np.zeros(self.nx + 1) + self.up1_2p = np.zeros(self.nx + 1) + self.flux = np.zeros(self.nx + 1) + self.res = np.zeros(self.nx) + + # Field module variables + self.u = np.zeros(self.ntcell) + self.un = np.zeros(self.ntcell) + +def RunEno(solver, mesh, iorder): + eno = Eno(solver, mesh, iorder) + init_coef(eno.iorder, eno.coef) + init_field(eno) + + simu_time = solver.T + t = 0.0 + dt = solver.dt + while t < simu_time: + runge_kutta(eno) + if t + dt > simu_time: + dt = simu_time - t + t += dt + print(f'T={t:.3f},runge_kutta{solver.rk},ENO{eno.iorder},{fluxnames[solver.iflux]} FLUX') + #visualizeEno(eno) + return np.copy(eno.u[eno.ist:eno.ied+1]) + +def RunWeno(solver, mesh, iorder): + eno = Eno(solver, mesh, iorder) + init_coef(eno.iorder, eno.coef) + init_field(eno) + + simu_time = solver.T + t = 0.0 + dt = solver.dt + while t < simu_time: + runge_kutta(eno) + if t + dt > simu_time: + dt = simu_time - t + t += dt + print(f'T={t:.3f},runge_kutta{solver.rk},WENO{eno.iorder},{fluxnames[solver.iflux]} FLUX') + #visualize(eno) + return np.copy(eno.u[eno.ist:eno.ied+1]) + +def performEnoOrderAnalysis(): + iorder_max = 7 + mesh = Mesh() + solver = Solver() + #计算理论解 + u_analytical = analytical_solution(mesh.xcc, solver.T, solver.c, mesh.L) + + u_list = [] + for iorder in range(1, iorder_max+1): + u = RunEno(solver, mesh, iorder) + u_list.append(u) + + plot_eno_OrderAnalysis(solver, mesh.xcc, u_list, u_analytical) + +def performEnoTimestepAnalysis(): + mesh = Mesh() + solver = Solver() + #计算理论解 + u_analytical = analytical_solution(mesh.xcc, solver.T, solver.c, mesh.L) + + u_list = [] + dt_list = [] + solver.dt = 0.025/4 + #solver.dt = 0.025/16 + n = 12 + solver.rk = 3 + iorder = 7 + for i in range(0, n): + u = RunEno(solver, mesh, iorder) + u_list.append(u) + dt_list.append(solver.dt) + print(f'i={i+1},N={n},T={solver.T:.3f},dt={solver.dt},nt={int(solver.T/solver.dt)},runge_kutta{solver.rk},ENO{iorder},{fluxnames[solver.iflux]} FLUX') + solver.dt /= 2 + + plot_eno_TimestepAnalysis(solver, mesh.xcc, u_list, u_analytical, dt_list, iorder) + +def performEnoWenoAnalysis(): + mesh = Mesh() + solver = Solver() + #计算理论解 + u_analytical = analytical_solution(mesh.xcc, solver.T, solver.c, mesh.L) + + solver.rk = 1 + solver.iorder = 3 + + u_list = [] + u = RunEno(solver, mesh, solver.iorder) + u_list.append(u) + u = RunWeno(solver, mesh, solver.iorder) + u_list.append(u) + + plot_EnoWeno_Analysis(solver, mesh.xcc, u_list, u_analytical) + +def plot_eno_OrderAnalysis(solver, xcc, u_list, u_analytical): + # 定义一个包含不同颜色、线形和标记的列表 + styles = [ + {'color': 'black', 'linestyle': '-', 'marker': 'o'}, + {'color': 'blue', 'linestyle': '--', 'marker': 's'}, + {'color': 'black', 'linestyle': '-', 'marker': '^'}, + {'color': 'blue', 'linestyle': '--', 'marker': 'v'}, + {'color': 'black', 'linestyle': '-', 'marker': '<'}, + {'color': 'blue', 'linestyle': '--', 'marker': '>'}, + {'color': 'black', 'linestyle': '-', 'marker': 'D'}, + ] + + n = len(u_list) + num_styles = len(styles) + ordinal = get_ordinal_numbers(solver.rk) + + plt.figure("OneFLOW-CFD Solver", figsize=(10, 6)) + plt.title(f'1D Convection Equation at t = {solver.T:.3f} using [1-7]th-order ENO and {solver.rk}{ordinal}-order Runge-Kutta methods') + for i in range(0, n): + lable = 'Numerical (Rusanov)ENO' + str(i+1) + style = styles[i % num_styles] + plt.plot(xcc, u_list[i], marker=style['marker'], markerfacecolor='none', linestyle=style['linestyle'], color=style['color'], \ + markersize=5, linewidth=0.5, alpha=1.0, label=f'{lable}') + plt.plot(xcc, u_analytical, 'r--', label='Analytical') + plt.xlabel('x') + plt.ylabel('u') + plt.legend() + plt.grid(True, color='gray', linestyle='--', linewidth=0.5, alpha=0.7) + plt.tight_layout() + plt.show() + +def plot_EnoWeno_Analysis(solver, xcc, u_list, u_analytical): + # 定义一个包含不同颜色、线形和标记的列表 + styles = [ + {'color': 'black', 'linestyle': '-', 'marker': 'o'}, + {'color': 'blue', 'linestyle': '--', 'marker': 's'}, + {'color': 'black', 'linestyle': '-', 'marker': '^'}, + {'color': 'blue', 'linestyle': '--', 'marker': 'v'}, + {'color': 'black', 'linestyle': '-', 'marker': '<'}, + {'color': 'blue', 'linestyle': '--', 'marker': '>'}, + {'color': 'black', 'linestyle': '-', 'marker': 'D'}, + ] + + n = len(u_list) + num_styles = len(styles) + ordinal = get_ordinal_numbers(solver.rk) + + plt.figure("OneFLOW-CFD Solver", figsize=(10, 6)) + plt.title(f'1D Convection Equation at t = {solver.T:.3f} using 3rd-order ENO&WENO and {solver.rk}{ordinal}-order Runge-Kutta methods') + for i in range(0, n): + if i == 0: + lable = 'Numerical (Rusanov)ENO3' + else: + lable = 'Numerical (Rusanov)WENO3' + style = styles[i % num_styles] + plt.plot(xcc, u_list[i], marker=style['marker'], markerfacecolor='none', linestyle=style['linestyle'], color=style['color'], \ + markersize=5, linewidth=0.5, alpha=1.0, label=f'{lable}') + plt.plot(xcc, u_analytical, 'r--', label='Analytical') + plt.xlabel('x') + plt.ylabel('u') + plt.legend() + plt.grid(True, color='gray', linestyle='--', linewidth=0.5, alpha=0.7) + plt.tight_layout() + plt.show() + +def main(): + performEnoWenoAnalysis() + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/example/1d-linear-convection/weno3/python/01c/weno.py b/example/1d-linear-convection/weno3/python/01c/weno.py new file mode 100644 index 00000000..1dc57b86 --- /dev/null +++ b/example/1d-linear-convection/weno3/python/01c/weno.py @@ -0,0 +1,581 @@ +import numpy as np +import matplotlib.pyplot as plt + +# 初始条件 +def initial_condition(x): + u0 = np.zeros_like(x) + for i in range(len(x)): + if 0.5 <= x[i] <= 1.0: + u0[i] = 2.0 + else: + u0[i] = 1.0 + return u0 + +# 理论解 +def analytical_solution(x, t, a, L): + # 初始条件沿 x - at 平移 + x_shifted = x - a * t + return initial_condition((x_shifted + L) % L) # 周期边界条件 + +def residual(q, eno): + reconstruction(q, eno) + inviscid_flux(eno.up1_2m, eno.up1_2p, eno.flux, eno) + for i in range(eno.nx): + eno.res[i] = -(eno.flux[i + 1] - eno.flux[i]) / eno.mesh.dx + +def reconstruction(q, eno): + if eno.solver.interpolation == 0: + EnoReconstruction(q, eno) + elif eno.solver.interpolation == 1: + WenoReconstruction(q, eno) + +def EnoReconstruction(q, eno): + # Choose the stencil by ENO method + eno.dd[0, 0:eno.ntcell-1] = q[0:eno.ntcell-1] + + for m in range(1, eno.iorder): + for j in range(0, eno.ntcell-1): + eno.dd[m, j] = eno.dd[m-1, j+1] - eno.dd[m-1, j] + + for i in range(eno.nx + 1): + eno.il[i] = i - 1 + for m in range(1, eno.iorder): + if abs(eno.dd[m, eno.il[i]-1+eno.ishift]) <= abs(eno.dd[m, eno.il[i]+eno.ishift]): + eno.il[i] -= 1 + + for i in range(eno.nx + 1): + eno.ir[i] = i + for m in range(1, eno.iorder): + if abs(eno.dd[m, eno.ir[i]-1+eno.ishift]) <= abs(eno.dd[m, eno.ir[i]+eno.ishift]): + eno.ir[i] -= 1 + + # Reconstruction u(j+1/2) + for i in range(eno.nx + 1): + k1 = eno.il[i] + k2 = eno.ir[i] + l1 = i - k1 + l2 = i - k2 + eno.up1_2m[i] = 0 + eno.up1_2p[i] = 0 + for m in range(eno.iorder): + eno.up1_2m[i] += q[k1 + eno.ishift + m] * eno.coef[l1, m] + eno.up1_2p[i] += q[k2 + eno.ishift + m] * eno.coef[l2, m] + +#---------------------------------------------------------------------------# +#nonlinear weights for upwind direction +#---------------------------------------------------------------------------# +def wc3L(v1,v2,v3): + eps = 1.0e-6 + + # smoothness indicators + s0 = (v3-v2)**2 + s1 = (v2-v1)**2 + + # computing nonlinear weights w1,w2 + d0 = 2.0/3.0 + d1 = 1.0/3.0 + + c0 = d0 / ( (eps+s0)**2 ) + c1 = d1 / ( (eps+s1)**2 ) + + w0 = c0 / ( c0 + c1 ) + w1 = c1 / ( c0 + c1 ) + + # candiate stencils + q0 = 0.5 * v2 + 0.5 * v3 + q1 = -0.5 * v1 + 1.5 * v2 + + # reconstructed value at interface + f = ( w0*q0 + w1*q1 ) + + return f + +#---------------------------------------------------------------------------# +#nonlinear weights for downwind direction +#---------------------------------------------------------------------------# +def wc3R(v1,v2,v3): + eps = 1.0e-6 + + # smoothness indicators + s0 = (v2-v1)**2 + s1 = (v3-v2)**2 + + # computing nonlinear weights w1,w2 + d0 = 2.0/3.0 + d1 = 1.0/3.0 + + c0 = d0 / ( (eps+s0)**2 ) + c1 = d1 / ( (eps+s1)**2 ) + + w0 = c0 / ( c0 + c1 ) + w1 = c1 / ( c0 + c1 ) + + # candiate stencils + q0 = 0.5 * v1 + 0.5 * v2 + q1 = 1.5 * v2 - 0.5 * v3 + + # reconstructed value at interface + f = ( w0*q0 + w1*q1 ) + + return f + + +def weno3L_periodic(eno,u,f): + #i:ist-1,ist,...,ied + #j:0,1,...,nx + for i in range(eno.ist - 1, eno.ied + 1): + j = i - eno.ist + 1 + v1 = u[i-1] + v2 = u[i ] + v3 = u[i+1] + f[j] = wc3L(v1,v2,v3) + +def weno3R_periodic(eno,u,f): + #i:ist,ist+1,...,ied,ied+1 + #j:0,1,...,nx + for i in range(eno.ist, eno.ied + 2): + j = i - eno.ist + v1 = u[i-1] + v2 = u[i ] + v3 = u[i+1] + f[j] = wc3R(v1,v2,v3) + + +def WenoReconstruction(q, eno): + # Reconstruction u(j+1/2) + weno3L_periodic( eno, q, eno.up1_2m ) + weno3R_periodic( eno, q, eno.up1_2p ) + #for i in range(eno.nx + 1): + # eno.up1_2m[i] = 0 + # eno.up1_2p[i] = 0 + # for m in range(eno.iorder): + # eno.up1_2m[i] += q[k1 + eno.ishift + m] * eno.coef[l1, m] + # eno.up1_2p[i] += q[k2 + eno.ishift + m] * eno.coef[l2, m] + + +fluxnames = [ + 'Rusanov', + 'Engquist-Osher', +] + +def inviscid_flux(up1_2m, up1_2p, flux, eno): + if eno.solver.iflux == 0: + rusanov_flux(up1_2m, up1_2p, flux, eno) + else: + engquist_osher_flux(up1_2m, up1_2p, flux, eno) + +def engquist_osher_flux(up1_2m, up1_2p, flux, eno): + for i in range(eno.nx + 1): + u_L = up1_2m[i] + u_R = up1_2p[i] + + cp = 0.5 * ( eno.solver.c + abs(eno.solver.c) ) + cm = 0.5 * ( eno.solver.c - abs(eno.solver.c) ) + + flux[i] = cp * u_L + cm * u_R + +def rusanov_flux(up1_2m, up1_2p, flux, eno): + for i in range(eno.nx + 1): + u_L = up1_2m[i] + u_R = up1_2p[i] + F_L = eno.solver.c * u_L # 左状态通量 + F_R = eno.solver.c * u_R # 右状态通量 + alpha = abs(eno.solver.c) # 最大波速 + flux[i] = 0.5 * (F_L + F_R) - 0.5 * alpha * (u_R - u_L) + + +def boundary(u, eno): + for i in range(-eno.ighost, 1): + u[eno.ist - 1 + i] = u[eno.ied + i] + for i in range(1, eno.ighost + 2): + u[eno.ied + i] = u[eno.ist - 1 + i] + +def update_oldfield(qn, q): + qn[:] = q[:] + +def init_coef( iorder, coef ): + if iorder == 1: + coef[0] = [1.0] + coef[1] = [1.0] + elif iorder == 2: + coef[0] = [3.0/2.0, -1.0/2.0] + coef[1] = [1.0/2.0, 1.0/2.0] + coef[2] = [-1.0/2.0, 3.0/2.0] + elif iorder == 3: + coef[0] = [ 11.0/6.0, -7.0/6.0, 1.0/3.0 ] + coef[1] = [ 1.0/3.0, 5.0/6.0, -1.0/6.0 ] + coef[2] = [ -1.0/6.0, 5.0/6.0, 1.0/3.0 ] + coef[3] = [ 1.0/3.0, -7.0/6.0, 11.0/6.0 ] + elif iorder == 4: + coef[0] = [ 25.0/12.0, -23.0/12.0, 13.0/12.0, -1.0/4.0 ] + coef[1] = [ 1.0/4.0, 13.0/12.0, -5.0/12.0, 1.0/12.0 ] + coef[2] = [ -1.0/12.0, 7.0/12.0, 7.0/12.0, -1.0/12.0 ] + coef[3] = [ 1.0/12.0, -5.0/12.0, 13.0/12.0, 1.0/4.0 ] + coef[4] = [ -1.0/4.0, 13.0/12.0, -23.0/12.0, 25.0/12.0 ] + elif iorder == 5: + coef[0] = [ 137.0/60.0, -163.0/60.0, 137.0/60.0, -21.0/20.0, 1.0/5.0 ] + coef[1] = [ 1.0/5.0, 77.0/60.0, -43.0/60.0, 17.0/60.0, -1.0/20.0 ] + coef[2] = [ -1.0/20.0, 9.0/20.0, 47.0/60.0, -13.0/60.0, 1.0/30.0 ] + coef[3] = [ 1.0/30.0, -13.0/60.0, 47.0/60.0, 9.0/20.0, -1.0/20.0 ] + coef[4] = [ -1.0/20.0, 17.0/60.0, -43.0/60.0, 77.0/60.0, 1.0/5.0 ] + coef[5] = [ 1.0/5.0, -21.0/20.0, 137.0/60.0, -163.0/60.0, 137.0/60.0 ] + elif iorder == 6: + coef[0] = [ 49.0/20.0, -71.0/20.0, 79.0/20.0, -163.0/60.0, 31.0/30.0, -1.0/6.0 ] + coef[1] = [ 1.0/6.0, 29.0/20.0, -21.0/20.0, 37.0/60.0, -13.0/60.0, 1.0/30.0 ] + coef[2] = [ -1.0/30.0, 11.0/30.0, 19.0/20.0, -23.0/60.0, 7.0/60.0, -1.0/60.0 ] + coef[3] = [ 1.0/60.0, -2.0/15.0, 37.0/60.0, 37.0/60.0, -2.0/15.0, 1.0/60.0 ] + coef[4] = [ -1.0/60.0, 7.0/60.0, -23.0/60.0, 19.0/20.0, 11.0/30.0, -1.0/30.0 ] + coef[5] = [ 1.0/30.0, -13.0/60.0, 37.0/60.0, -21.0/20.0, 29.0/20.0, 1.0/6.0 ] + coef[6] = [ -1.0/6.0, 31.0/30.0, -163.0/60.0, 79.0/20.0, -71.0/20.0, 49.0/20.0 ] + elif iorder == 7: + coef[0] = [ 363.0/140.0, -617.0/140.0, 853.0/140.0, -2341.0/420.0, 667.0/210.0, -43.0/42.0, 1.0/7.0 ] + coef[1] = [ 1.0/7.0, 223.0/140.0, -197.0/140.0, 153.0/140.0, -241.0/420.0, 37.0/210.0, -1.0/42.0 ] + coef[2] = [ -1.0/42.0, 13.0/42.0, 153.0/140.0, -241.0/420.0, 109.0/420.0, -31.0/420.0, 1.0/105.0 ] + coef[3] = [ 1.0/105.0, -19.0/210.0, 107.0/210.0, 319.0/420.0, -101.0/420.0, 5.0/84.0, -1.0/140.0 ] + coef[4] = [ -1.0/140.0, 5.0/84.0, -101.0/420.0, 319.0/420.0, 107.0/210.0, -19.0/210.0, 1.0/105.0 ] + coef[5] = [ 1.0/105.0, -31.0/420.0, 109.0/420.0, -241.0/420.0, 153.0/140.0, 13.0/42.0, -1.0/42.0 ] + coef[6] = [ -1.0/42.0, 37.0/210.0, -241.0/420.0, 153.0/140.0, -197.0/140.0, 223.0/140.0, 1.0/7.0 ] + coef[7] = [ 1.0/7.0, -43.0/42.0, 667.0/210.0, -2341.0/420.0, 853.0/140.0, -617.0/140.0, 363.0/140.0 ] + +def init_field(eno): + for i in range(eno.ist, eno.ied + 1): + j = i - eno.ist + if 0.5 <= eno.mesh.xcc[j] <= 1.0: + eno.u[i] = 2.0 + else: + eno.u[i] = 1.0 + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def runge_kutta(eno): + rk = eno.solver.rk + if rk == 1: + runge_kutta_1(eno) + elif rk == 2: + runge_kutta_2(eno) + else: + runge_kutta_3(eno) + +def runge_kutta_1(eno): + dt = eno.solver.dt + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = eno.u[j] + dt * eno.res[i] + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def runge_kutta_2(eno): + dt = eno.solver.dt + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = eno.u[j] + dt * eno.res[i] + boundary(eno.u, eno) + + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = 0.5 * eno.un[j] + 0.5 * eno.u[j] + 0.5 * dt * eno.res[i] + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def runge_kutta_3(eno): + dt = eno.solver.dt + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = eno.u[j] + dt * eno.res[i] + boundary(eno.u, eno) + + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = 0.75 * eno.un[j] + 0.25 * eno.u[j] + 0.25 * dt * eno.res[i] + boundary(eno.u, eno) + + residual(eno.u, eno) + c1, c2, c3 = 1.0/3.0, 2.0/3.0, 2.0/3.0 + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = c1 * eno.un[j] + c2 * eno.u[j] + c3 * dt * eno.res[i] + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def get_ordinal_numbers(order): + if order == 1: + return 'st' + elif order == 2: + return 'nd' + elif order == 3: + return 'rd' + else: + return 'th' + +def visualize(eno): + with open('solution.plt', 'w') as f: + for i in range(eno.ist, eno.ied + 1): + j = i - eno.ist + f.write(f"{eno.mesh.xcc[j]:20.10e}{eno.u[i]:20.10e}\n") + + # 可视化 + u_numerical = np.copy(eno.u[eno.ist:eno.ied+1]) + print(f'u_numerical.size={u_numerical.size}') + print(f'eno.mesh.xcc.size={eno.mesh.xcc.size}') + #计算理论解 + u_analytical = analytical_solution(eno.mesh.xcc, eno.solver.T, eno.solver.c, eno.mesh.L) + print(f'u_analytical.size={u_analytical.size}') + plt.figure("OneFLOW-CFD Solver", figsize=(10, 6)) + plt.scatter(eno.mesh.xcc, u_numerical, facecolor="none", edgecolor="blue", s=20, linewidths=0.5, label=f'Numerical (Rusanov)') + plt.plot(eno.mesh.xcc, u_analytical, 'r--', label='Analytical') + plt.xlabel('x') + plt.ylabel('u') + ordinal1 = get_ordinal_numbers(eno.iorder) + ordinal2 = get_ordinal_numbers(eno.solver.rk) + plt.title(f'1D Convection Equation at t = {eno.solver.T:.3f} using {eno.iorder}{ordinal1}-order WENO and {eno.solver.rk}{ordinal2}-order Runge-Kutta methods') + plt.legend() + plt.grid(True, color='gray', linestyle='--', linewidth=0.5, alpha=0.7) + plt.tight_layout() + plt.show() + +def visualizeEno(eno): + with open('solution.plt', 'w') as f: + for i in range(eno.ist, eno.ied + 1): + j = i - eno.ist + f.write(f"{eno.mesh.xcc[j]:20.10e}{eno.u[i]:20.10e}\n") + + # 可视化 + u_numerical = np.copy(eno.u[eno.ist:eno.ied+1]) + print(f'u_numerical.size={u_numerical.size}') + print(f'eno.mesh.xcc.size={eno.mesh.xcc.size}') + #计算理论解 + u_analytical = analytical_solution(eno.mesh.xcc, eno.solver.T, eno.solver.c, eno.mesh.L) + print(f'u_analytical.size={u_analytical.size}') + plt.figure("OneFLOW-CFD Solver", figsize=(10, 6)) + plt.scatter(eno.mesh.xcc, u_numerical, facecolor="none", edgecolor="blue", s=20, linewidths=0.5, label=f'Numerical (Rusanov)') + plt.plot(eno.mesh.xcc, u_analytical, 'r--', label='Analytical') + plt.xlabel('x') + plt.ylabel('u') + ordinal1 = get_ordinal_numbers(eno.iorder) + ordinal2 = get_ordinal_numbers(eno.solver.rk) + plt.title(f'1D Convection Equation at t = {eno.solver.T:.3f} using {eno.iorder}{ordinal1}-order ENO and {eno.solver.rk}{ordinal2}-order Runge-Kutta methods') + plt.legend() + plt.grid(True, color='gray', linestyle='--', linewidth=0.5, alpha=0.7) + plt.tight_layout() + plt.show() + +class Mesh: + def __init__(self): + self.nx = 40 + self.L = 2.0 + self.x = np.zeros(self.nx + 1) + self.xcc = np.zeros(self.nx) + self.init_mesh() + def init_mesh(self): + xstart = 0.0 + xend = self.L + self.dx = (xend - xstart) / self.nx + + for i in range(0, self.nx+1): + self.x[i] = xstart + i * self.dx + + for i in range(0, self.nx): + self.xcc[i] = 0.5 * (self.x[i] + self.x[i + 1]) + +class Solver: + def __init__(self): + #interpolation :0 Eno; 1 Weno + self.interpolation = 0 + self.iflux = 0 + self.rk = 1 + self.c = 1.0 + self.T = 0.625 + #self.dt = .0025 + self.dt = .025 + +class Eno: + def __init__(self, solver, mesh, iorder): + self.solver = solver + self.mesh = mesh + self.nx = mesh.nx + self.iorder = iorder + self.ighost = iorder + self.ishift = self.ighost + 1 + self.ist = 0 + self.ishift + self.ied = self.nx - 1 + self.ishift + self.ntcell = self.nx + 2 * self.ishift + self.isize = iorder * (iorder + 1) + + self.il = np.zeros(self.nx + 1, dtype=int) + self.ir = np.zeros(self.nx + 1, dtype=int) + self.coef = np.zeros((iorder + 1, iorder)) + self.dd = np.zeros((iorder, self.ntcell)) + self.up1_2m = np.zeros(self.nx + 1) + self.up1_2p = np.zeros(self.nx + 1) + self.flux = np.zeros(self.nx + 1) + self.res = np.zeros(self.nx) + + # Field module variables + self.u = np.zeros(self.ntcell) + self.un = np.zeros(self.ntcell) + +def RunEno(solver, mesh, iorder): + eno = Eno(solver, mesh, iorder) + init_coef(eno.iorder, eno.coef) + init_field(eno) + + simu_time = solver.T + t = 0.0 + dt = solver.dt + while t < simu_time: + runge_kutta(eno) + if t + dt > simu_time: + dt = simu_time - t + t += dt + print(f'T={t:.3f},runge_kutta{solver.rk},ENO{eno.iorder},{fluxnames[solver.iflux]} FLUX') + #visualizeEno(eno) + return np.copy(eno.u[eno.ist:eno.ied+1]) + +def RunWeno(solver, mesh, iorder): + eno = Eno(solver, mesh, iorder) + init_coef(eno.iorder, eno.coef) + init_field(eno) + + simu_time = solver.T + t = 0.0 + dt = solver.dt + while t < simu_time: + runge_kutta(eno) + if t + dt > simu_time: + dt = simu_time - t + t += dt + print(f'T={t:.3f},runge_kutta{solver.rk},WENO{eno.iorder},{fluxnames[solver.iflux]} FLUX') + #visualize(eno) + return np.copy(eno.u[eno.ist:eno.ied+1]) + +def performEnoOrderAnalysis(): + iorder_max = 7 + mesh = Mesh() + solver = Solver() + #计算理论解 + u_analytical = analytical_solution(mesh.xcc, solver.T, solver.c, mesh.L) + + u_list = [] + for iorder in range(1, iorder_max+1): + u = RunEno(solver, mesh, iorder) + u_list.append(u) + + plot_eno_OrderAnalysis(solver, mesh.xcc, u_list, u_analytical) + +def performEnoTimestepAnalysis(): + mesh = Mesh() + solver = Solver() + #计算理论解 + u_analytical = analytical_solution(mesh.xcc, solver.T, solver.c, mesh.L) + + u_list = [] + dt_list = [] + solver.dt = 0.025/4 + #solver.dt = 0.025/16 + n = 12 + solver.rk = 3 + iorder = 7 + for i in range(0, n): + u = RunEno(solver, mesh, iorder) + u_list.append(u) + dt_list.append(solver.dt) + print(f'i={i+1},N={n},T={solver.T:.3f},dt={solver.dt},nt={int(solver.T/solver.dt)},runge_kutta{solver.rk},ENO{iorder},{fluxnames[solver.iflux]} FLUX') + solver.dt /= 2 + + plot_eno_TimestepAnalysis(solver, mesh.xcc, u_list, u_analytical, dt_list, iorder) + +def performEnoWenoAnalysis(): + mesh = Mesh() + solver = Solver() + #计算理论解 + u_analytical = analytical_solution(mesh.xcc, solver.T, solver.c, mesh.L) + + solver.rk = 1 + solver.dt = 0.0025 + solver.iorder = 3 + + u_list = [] + solver.interpolation = 0 + u = RunEno(solver, mesh, solver.iorder) + u_list.append(u) + solver.interpolation = 1 + u = RunWeno(solver, mesh, solver.iorder) + u_list.append(u) + + plot_EnoWeno_Analysis(solver, mesh.xcc, u_list, u_analytical) + +def plot_eno_OrderAnalysis(solver, xcc, u_list, u_analytical): + # 定义一个包含不同颜色、线形和标记的列表 + styles = [ + {'color': 'black', 'linestyle': '-', 'marker': 'o'}, + {'color': 'blue', 'linestyle': '--', 'marker': 's'}, + {'color': 'black', 'linestyle': '-', 'marker': '^'}, + {'color': 'blue', 'linestyle': '--', 'marker': 'v'}, + {'color': 'black', 'linestyle': '-', 'marker': '<'}, + {'color': 'blue', 'linestyle': '--', 'marker': '>'}, + {'color': 'black', 'linestyle': '-', 'marker': 'D'}, + ] + + n = len(u_list) + num_styles = len(styles) + ordinal = get_ordinal_numbers(solver.rk) + + plt.figure("OneFLOW-CFD Solver", figsize=(10, 6)) + plt.title(f'1D Convection Equation at t = {solver.T:.3f} using [1-7]th-order ENO and {solver.rk}{ordinal}-order Runge-Kutta methods') + for i in range(0, n): + lable = 'Numerical (Rusanov)ENO' + str(i+1) + style = styles[i % num_styles] + plt.plot(xcc, u_list[i], marker=style['marker'], markerfacecolor='none', linestyle=style['linestyle'], color=style['color'], \ + markersize=5, linewidth=0.5, alpha=1.0, label=f'{lable}') + plt.plot(xcc, u_analytical, 'r--', label='Analytical') + plt.xlabel('x') + plt.ylabel('u') + plt.legend() + plt.grid(True, color='gray', linestyle='--', linewidth=0.5, alpha=0.7) + plt.tight_layout() + plt.show() + +def plot_EnoWeno_Analysis(solver, xcc, u_list, u_analytical): + # 定义一个包含不同颜色、线形和标记的列表 + styles = [ + {'color': 'black', 'linestyle': '-', 'marker': 'o'}, + {'color': 'blue', 'linestyle': '--', 'marker': 's'}, + {'color': 'black', 'linestyle': '-', 'marker': '^'}, + {'color': 'blue', 'linestyle': '--', 'marker': 'v'}, + {'color': 'black', 'linestyle': '-', 'marker': '<'}, + {'color': 'blue', 'linestyle': '--', 'marker': '>'}, + {'color': 'black', 'linestyle': '-', 'marker': 'D'}, + ] + + n = len(u_list) + num_styles = len(styles) + ordinal = get_ordinal_numbers(solver.rk) + + plt.figure("OneFLOW-CFD Solver", figsize=(10, 6)) + plt.title(f'1D Convection Equation at t = {solver.T:.3f} using 3rd-order ENO&WENO and {solver.rk}{ordinal}-order Runge-Kutta methods') + for i in range(0, n): + if i == 0: + lable = 'Numerical (Rusanov)ENO3' + else: + lable = 'Numerical (Rusanov)WENO3' + style = styles[i % num_styles] + plt.plot(xcc, u_list[i], marker=style['marker'], markerfacecolor='none', linestyle=style['linestyle'], color=style['color'], \ + markersize=5, linewidth=0.5, alpha=1.0, label=f'{lable}') + plt.plot(xcc, u_analytical, 'r--', label='Analytical') + plt.xlabel('x') + plt.ylabel('u') + plt.legend() + plt.grid(True, color='gray', linestyle='--', linewidth=0.5, alpha=0.7) + plt.tight_layout() + plt.show() + +def main(): + performEnoWenoAnalysis() + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/example/1d-linear-convection/weno5/python/01/weno.py b/example/1d-linear-convection/weno5/python/01/weno.py new file mode 100644 index 00000000..dd6b7876 --- /dev/null +++ b/example/1d-linear-convection/weno5/python/01/weno.py @@ -0,0 +1,682 @@ +import numpy as np +import matplotlib.pyplot as plt + +# 初始条件 +def initial_condition(x): + u0 = np.zeros_like(x) + for i in range(len(x)): + if 0.5 <= x[i] <= 1.0: + u0[i] = 2.0 + else: + u0[i] = 1.0 + return u0 + +# 理论解 +def analytical_solution(x, t, a, L): + # 初始条件沿 x - at 平移 + x_shifted = x - a * t + return initial_condition((x_shifted + L) % L) # 周期边界条件 + +def residual(q, eno): + reconstruction(q, eno) + inviscid_flux(eno.up1_2m, eno.up1_2p, eno.flux, eno) + for i in range(eno.nx): + eno.res[i] = -(eno.flux[i + 1] - eno.flux[i]) / eno.mesh.dx + +def reconstruction(q, eno): + if eno.solver.interpolation == 0: + EnoReconstruction(q, eno) + elif eno.solver.interpolation == 1: + WenoReconstruction(q, eno) + +def EnoReconstruction(q, eno): + # Choose the stencil by ENO method + eno.dd[0, 0:eno.ntcell-1] = q[0:eno.ntcell-1] + + for m in range(1, eno.iorder): + for j in range(0, eno.ntcell-1): + eno.dd[m, j] = eno.dd[m-1, j+1] - eno.dd[m-1, j] + + for i in range(eno.nx + 1): + eno.il[i] = i - 1 + for m in range(1, eno.iorder): + if abs(eno.dd[m, eno.il[i]-1+eno.ishift]) <= abs(eno.dd[m, eno.il[i]+eno.ishift]): + eno.il[i] -= 1 + + for i in range(eno.nx + 1): + eno.ir[i] = i + for m in range(1, eno.iorder): + if abs(eno.dd[m, eno.ir[i]-1+eno.ishift]) <= abs(eno.dd[m, eno.ir[i]+eno.ishift]): + eno.ir[i] -= 1 + + # Reconstruction u(j+1/2) + for i in range(eno.nx + 1): + k1 = eno.il[i] + k2 = eno.ir[i] + l1 = i - k1 + l2 = i - k2 + eno.up1_2m[i] = 0 + eno.up1_2p[i] = 0 + for m in range(eno.iorder): + eno.up1_2m[i] += q[k1 + eno.ishift + m] * eno.coef[l1, m] + eno.up1_2p[i] += q[k2 + eno.ishift + m] * eno.coef[l2, m] + +#---------------------------------------------------------------------------# +#nonlinear weights for upwind direction +#---------------------------------------------------------------------------# +def wc3L(v1,v2,v3): + eps = 1.0e-6 + + # smoothness indicators + s0 = (v3-v2)**2 + s1 = (v2-v1)**2 + + # computing nonlinear weights w1,w2 + d0 = 2.0/3.0 + d1 = 1.0/3.0 + + c0 = d0 / ( (eps+s0)**2 ) + c1 = d1 / ( (eps+s1)**2 ) + + w0 = c0 / ( c0 + c1 ) + w1 = c1 / ( c0 + c1 ) + + # candiate stencils + q0 = 0.5 * v2 + 0.5 * v3 + q1 = -0.5 * v1 + 1.5 * v2 + + # reconstructed value at interface + f = ( w0*q0 + w1*q1 ) + + return f + +#---------------------------------------------------------------------------# +#nonlinear weights for downwind direction +#---------------------------------------------------------------------------# +def wc3R(v1,v2,v3): + eps = 1.0e-6 + + # smoothness indicators + s0 = (v2-v1)**2 + s1 = (v3-v2)**2 + + # computing nonlinear weights w1,w2 + d0 = 2.0/3.0 + d1 = 1.0/3.0 + + c0 = d0 / ( (eps+s0)**2 ) + c1 = d1 / ( (eps+s1)**2 ) + + w0 = c0 / ( c0 + c1 ) + w1 = c1 / ( c0 + c1 ) + + # candiate stencils + q0 = 0.5 * v1 + 0.5 * v2 + q1 = 1.5 * v2 - 0.5 * v3 + + # reconstructed value at interface + f = ( w0*q0 + w1*q1 ) + + return f + + +def weno3L_periodic(eno,u,f): + #i:ist-1,ist,...,ied + #j:0,1,...,nx + for i in range(eno.ist - 1, eno.ied + 1): + j = i - eno.ist + 1 + v1 = u[i-1] + v2 = u[i ] + v3 = u[i+1] + f[j] = wc3L(v1,v2,v3) + +def weno3R_periodic(eno,u,f): + #i:ist,ist+1,...,ied,ied+1 + #j:0,1,...,nx + for i in range(eno.ist, eno.ied + 2): + j = i - eno.ist + v1 = u[i-1] + v2 = u[i ] + v3 = u[i+1] + f[j] = wc3R(v1,v2,v3) + +def wc5(v0,v1,v2,v3,v4): + eps = 1.0e-6 + + # smoothness indicators + s0 = (13.0/12.0)*(v2-2.0*v3+v4)**2 + 0.25*(3*v2-4.0*v3+v4)**2 + s1 = (13.0/12.0)*(v1-2.0*v2+v3)**2 + 0.25*(v1-v3)**2 + s2 = (13.0/12.0)*(v0-2.0*v1+v2)**2 + 0.25*(v0-4.0*v1+3.0*v2)**2 + + # computing nonlinear weights w0,w1,w2 + d0 = 3.0/10.0 + d1 = 3.0/5.0 + d2 = 1.0/10.0 + + c0 = d0 / ( (s0 + eps)**2 ) + c1 = d1 / ( (s1 + eps)**2 ) + c2 = d2 / ( (s2 + eps)**2 ) + + cc = c0+c1+c2 + + w0 = c0/cc + w1 = c1/cc + w2 = c2/cc + + # candiate stencils + q0 = 1.0/3.0 * v2 + 5.0/6.0 * v3 - 1.0/6.0 * v4 + q1 = -1.0/6.0 * v1 + 5.0/6.0 * v2 + 1.0/3.0 * v3 + q2 = 1.0/3.0 * v0 - 7.0/6.0 * v1 + 11.0/6.0 * v2 + + # reconstructed value at interface + f = ( w0 * q0 + w1 * q1 + w2 * q2 ) + + return f + +def weno5L_periodic(eno,u,f): + #i:ist-1,ist,...,ied + #j:0,1,...,nx + for i in range(eno.ist - 1, eno.ied + 1): + j = i - eno.ist + 1 + v0 = u[i-2] + v1 = u[i-1] + v2 = u[i ] + v3 = u[i+1] + v4 = u[i+2] + f[j] = wc5(v0,v1,v2,v3,v4) + +def weno5R_periodic(eno,u,f): + #i:ist,ist+1,...,ied,ied+1 + #j:0,1,...,nx + for i in range(eno.ist, eno.ied + 2): + j = i - eno.ist + v4 = u[i-1] + v3 = u[i ] + v2 = u[i+1] + v1 = u[i+2] + v0 = u[i+3] + f[j] = wc5(v0,v1,v2,v3,v4) + +def WenoReconstruction(q, eno): + if eno.iorder == 3: + Weno3Reconstruction(q, eno) + elif eno.iorder == 5: + Weno5Reconstruction(q, eno) + +def Weno3Reconstruction(q, eno): + weno3L_periodic( eno, q, eno.up1_2m ) + weno3R_periodic( eno, q, eno.up1_2p ) + +def Weno5Reconstruction(q, eno): + weno5L_periodic( eno, q, eno.up1_2m ) + weno5R_periodic( eno, q, eno.up1_2p ) + +fluxnames = [ + 'Rusanov', + 'Engquist-Osher', +] + +def inviscid_flux(up1_2m, up1_2p, flux, eno): + if eno.solver.iflux == 0: + rusanov_flux(up1_2m, up1_2p, flux, eno) + else: + engquist_osher_flux(up1_2m, up1_2p, flux, eno) + +def engquist_osher_flux(up1_2m, up1_2p, flux, eno): + for i in range(eno.nx + 1): + u_L = up1_2m[i] + u_R = up1_2p[i] + + cp = 0.5 * ( eno.solver.c + abs(eno.solver.c) ) + cm = 0.5 * ( eno.solver.c - abs(eno.solver.c) ) + + flux[i] = cp * u_L + cm * u_R + +def rusanov_flux(up1_2m, up1_2p, flux, eno): + for i in range(eno.nx + 1): + u_L = up1_2m[i] + u_R = up1_2p[i] + F_L = eno.solver.c * u_L # 左状态通量 + F_R = eno.solver.c * u_R # 右状态通量 + alpha = abs(eno.solver.c) # 最大波速 + flux[i] = 0.5 * (F_L + F_R) - 0.5 * alpha * (u_R - u_L) + + +def boundary(u, eno): + for i in range(-eno.ighost, 1): + u[eno.ist - 1 + i] = u[eno.ied + i] + for i in range(1, eno.ighost + 2): + u[eno.ied + i] = u[eno.ist - 1 + i] + +def update_oldfield(qn, q): + qn[:] = q[:] + +def init_coef( iorder, coef ): + if iorder == 1: + coef[0] = [1.0] + coef[1] = [1.0] + elif iorder == 2: + coef[0] = [3.0/2.0, -1.0/2.0] + coef[1] = [1.0/2.0, 1.0/2.0] + coef[2] = [-1.0/2.0, 3.0/2.0] + elif iorder == 3: + coef[0] = [ 11.0/6.0, -7.0/6.0, 1.0/3.0 ] + coef[1] = [ 1.0/3.0, 5.0/6.0, -1.0/6.0 ] + coef[2] = [ -1.0/6.0, 5.0/6.0, 1.0/3.0 ] + coef[3] = [ 1.0/3.0, -7.0/6.0, 11.0/6.0 ] + elif iorder == 4: + coef[0] = [ 25.0/12.0, -23.0/12.0, 13.0/12.0, -1.0/4.0 ] + coef[1] = [ 1.0/4.0, 13.0/12.0, -5.0/12.0, 1.0/12.0 ] + coef[2] = [ -1.0/12.0, 7.0/12.0, 7.0/12.0, -1.0/12.0 ] + coef[3] = [ 1.0/12.0, -5.0/12.0, 13.0/12.0, 1.0/4.0 ] + coef[4] = [ -1.0/4.0, 13.0/12.0, -23.0/12.0, 25.0/12.0 ] + elif iorder == 5: + coef[0] = [ 137.0/60.0, -163.0/60.0, 137.0/60.0, -21.0/20.0, 1.0/5.0 ] + coef[1] = [ 1.0/5.0, 77.0/60.0, -43.0/60.0, 17.0/60.0, -1.0/20.0 ] + coef[2] = [ -1.0/20.0, 9.0/20.0, 47.0/60.0, -13.0/60.0, 1.0/30.0 ] + coef[3] = [ 1.0/30.0, -13.0/60.0, 47.0/60.0, 9.0/20.0, -1.0/20.0 ] + coef[4] = [ -1.0/20.0, 17.0/60.0, -43.0/60.0, 77.0/60.0, 1.0/5.0 ] + coef[5] = [ 1.0/5.0, -21.0/20.0, 137.0/60.0, -163.0/60.0, 137.0/60.0 ] + elif iorder == 6: + coef[0] = [ 49.0/20.0, -71.0/20.0, 79.0/20.0, -163.0/60.0, 31.0/30.0, -1.0/6.0 ] + coef[1] = [ 1.0/6.0, 29.0/20.0, -21.0/20.0, 37.0/60.0, -13.0/60.0, 1.0/30.0 ] + coef[2] = [ -1.0/30.0, 11.0/30.0, 19.0/20.0, -23.0/60.0, 7.0/60.0, -1.0/60.0 ] + coef[3] = [ 1.0/60.0, -2.0/15.0, 37.0/60.0, 37.0/60.0, -2.0/15.0, 1.0/60.0 ] + coef[4] = [ -1.0/60.0, 7.0/60.0, -23.0/60.0, 19.0/20.0, 11.0/30.0, -1.0/30.0 ] + coef[5] = [ 1.0/30.0, -13.0/60.0, 37.0/60.0, -21.0/20.0, 29.0/20.0, 1.0/6.0 ] + coef[6] = [ -1.0/6.0, 31.0/30.0, -163.0/60.0, 79.0/20.0, -71.0/20.0, 49.0/20.0 ] + elif iorder == 7: + coef[0] = [ 363.0/140.0, -617.0/140.0, 853.0/140.0, -2341.0/420.0, 667.0/210.0, -43.0/42.0, 1.0/7.0 ] + coef[1] = [ 1.0/7.0, 223.0/140.0, -197.0/140.0, 153.0/140.0, -241.0/420.0, 37.0/210.0, -1.0/42.0 ] + coef[2] = [ -1.0/42.0, 13.0/42.0, 153.0/140.0, -241.0/420.0, 109.0/420.0, -31.0/420.0, 1.0/105.0 ] + coef[3] = [ 1.0/105.0, -19.0/210.0, 107.0/210.0, 319.0/420.0, -101.0/420.0, 5.0/84.0, -1.0/140.0 ] + coef[4] = [ -1.0/140.0, 5.0/84.0, -101.0/420.0, 319.0/420.0, 107.0/210.0, -19.0/210.0, 1.0/105.0 ] + coef[5] = [ 1.0/105.0, -31.0/420.0, 109.0/420.0, -241.0/420.0, 153.0/140.0, 13.0/42.0, -1.0/42.0 ] + coef[6] = [ -1.0/42.0, 37.0/210.0, -241.0/420.0, 153.0/140.0, -197.0/140.0, 223.0/140.0, 1.0/7.0 ] + coef[7] = [ 1.0/7.0, -43.0/42.0, 667.0/210.0, -2341.0/420.0, 853.0/140.0, -617.0/140.0, 363.0/140.0 ] + +def init_field(eno): + for i in range(eno.ist, eno.ied + 1): + j = i - eno.ist + if 0.5 <= eno.mesh.xcc[j] <= 1.0: + eno.u[i] = 2.0 + else: + eno.u[i] = 1.0 + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def runge_kutta(eno): + rk = eno.solver.rk + if rk == 1: + runge_kutta_1(eno) + elif rk == 2: + runge_kutta_2(eno) + else: + runge_kutta_3(eno) + +def runge_kutta_1(eno): + dt = eno.solver.dt + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = eno.u[j] + dt * eno.res[i] + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def runge_kutta_2(eno): + dt = eno.solver.dt + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = eno.u[j] + dt * eno.res[i] + boundary(eno.u, eno) + + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = 0.5 * eno.un[j] + 0.5 * eno.u[j] + 0.5 * dt * eno.res[i] + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def runge_kutta_3(eno): + dt = eno.solver.dt + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = eno.u[j] + dt * eno.res[i] + boundary(eno.u, eno) + + residual(eno.u, eno) + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = 0.75 * eno.un[j] + 0.25 * eno.u[j] + 0.25 * dt * eno.res[i] + boundary(eno.u, eno) + + residual(eno.u, eno) + c1, c2, c3 = 1.0/3.0, 2.0/3.0, 2.0/3.0 + for i in range(eno.nx): + j = i + eno.ishift + eno.u[j] = c1 * eno.un[j] + c2 * eno.u[j] + c3 * dt * eno.res[i] + boundary(eno.u, eno) + update_oldfield(eno.un, eno.u) + +def get_ordinal_numbers(order): + if order == 1: + return 'st' + elif order == 2: + return 'nd' + elif order == 3: + return 'rd' + else: + return 'th' + +def visualize(eno): + with open('solution.plt', 'w') as f: + for i in range(eno.ist, eno.ied + 1): + j = i - eno.ist + f.write(f"{eno.mesh.xcc[j]:20.10e}{eno.u[i]:20.10e}\n") + + # 可视化 + u_numerical = np.copy(eno.u[eno.ist:eno.ied+1]) + print(f'u_numerical.size={u_numerical.size}') + print(f'eno.mesh.xcc.size={eno.mesh.xcc.size}') + #计算理论解 + u_analytical = analytical_solution(eno.mesh.xcc, eno.solver.T, eno.solver.c, eno.mesh.L) + print(f'u_analytical.size={u_analytical.size}') + plt.figure("OneFLOW-CFD Solver", figsize=(10, 6)) + plt.scatter(eno.mesh.xcc, u_numerical, facecolor="none", edgecolor="blue", s=20, linewidths=0.5, label=f'Numerical (Rusanov)') + plt.plot(eno.mesh.xcc, u_analytical, 'r--', label='Analytical') + plt.xlabel('x') + plt.ylabel('u') + ordinal1 = get_ordinal_numbers(eno.iorder) + ordinal2 = get_ordinal_numbers(eno.solver.rk) + plt.title(f'1D Convection Equation at t = {eno.solver.T:.3f} using {eno.iorder}{ordinal1}-order WENO and {eno.solver.rk}{ordinal2}-order Runge-Kutta methods') + plt.legend() + plt.grid(True, color='gray', linestyle='--', linewidth=0.5, alpha=0.7) + plt.tight_layout() + plt.show() + +def visualizeEno(eno): + with open('solution.plt', 'w') as f: + for i in range(eno.ist, eno.ied + 1): + j = i - eno.ist + f.write(f"{eno.mesh.xcc[j]:20.10e}{eno.u[i]:20.10e}\n") + + # 可视化 + u_numerical = np.copy(eno.u[eno.ist:eno.ied+1]) + print(f'u_numerical.size={u_numerical.size}') + print(f'eno.mesh.xcc.size={eno.mesh.xcc.size}') + #计算理论解 + u_analytical = analytical_solution(eno.mesh.xcc, eno.solver.T, eno.solver.c, eno.mesh.L) + print(f'u_analytical.size={u_analytical.size}') + plt.figure("OneFLOW-CFD Solver", figsize=(10, 6)) + plt.scatter(eno.mesh.xcc, u_numerical, facecolor="none", edgecolor="blue", s=20, linewidths=0.5, label=f'Numerical (Rusanov)') + plt.plot(eno.mesh.xcc, u_analytical, 'r--', label='Analytical') + plt.xlabel('x') + plt.ylabel('u') + ordinal1 = get_ordinal_numbers(eno.iorder) + ordinal2 = get_ordinal_numbers(eno.solver.rk) + plt.title(f'1D Convection Equation at t = {eno.solver.T:.3f} using {eno.iorder}{ordinal1}-order ENO and {eno.solver.rk}{ordinal2}-order Runge-Kutta methods') + plt.legend() + plt.grid(True, color='gray', linestyle='--', linewidth=0.5, alpha=0.7) + plt.tight_layout() + plt.show() + +class Mesh: + def __init__(self): + self.nx = 40 + self.L = 2.0 + self.x = np.zeros(self.nx + 1) + self.xcc = np.zeros(self.nx) + self.init_mesh() + def init_mesh(self): + xstart = 0.0 + xend = self.L + self.dx = (xend - xstart) / self.nx + + for i in range(0, self.nx+1): + self.x[i] = xstart + i * self.dx + + for i in range(0, self.nx): + self.xcc[i] = 0.5 * (self.x[i] + self.x[i + 1]) + +class Solver: + def __init__(self): + #interpolation :0 Eno; 1 Weno + self.interpolation = 0 + self.iflux = 0 + self.rk = 1 + self.iorder = 3 + self.c = 1.0 + self.T = 0.625 + self.dt = .025 + +class Eno: + def __init__(self, solver, mesh, iorder): + self.solver = solver + self.mesh = mesh + self.nx = mesh.nx + self.iorder = iorder + self.ighost = iorder + self.ishift = self.ighost + 1 + self.ist = 0 + self.ishift + self.ied = self.nx - 1 + self.ishift + self.ntcell = self.nx + 2 * self.ishift + self.isize = iorder * (iorder + 1) + + self.il = np.zeros(self.nx + 1, dtype=int) + self.ir = np.zeros(self.nx + 1, dtype=int) + self.coef = np.zeros((iorder + 1, iorder)) + self.dd = np.zeros((iorder, self.ntcell)) + self.up1_2m = np.zeros(self.nx + 1) + self.up1_2p = np.zeros(self.nx + 1) + self.flux = np.zeros(self.nx + 1) + self.res = np.zeros(self.nx) + + # Field module variables + self.u = np.zeros(self.ntcell) + self.un = np.zeros(self.ntcell) + +def RunEno(solver, mesh, iorder): + eno = Eno(solver, mesh, iorder) + init_coef(eno.iorder, eno.coef) + init_field(eno) + + simu_time = solver.T + t = 0.0 + dt = solver.dt + while t < simu_time: + runge_kutta(eno) + if t + dt > simu_time: + dt = simu_time - t + t += dt + print(f'T={t:.3f},runge_kutta{solver.rk},ENO{eno.iorder},{fluxnames[solver.iflux]} FLUX') + #visualizeEno(eno) + return np.copy(eno.u[eno.ist:eno.ied+1]) + +def RunWeno(solver, mesh, iorder): + eno = Eno(solver, mesh, iorder) + init_coef(eno.iorder, eno.coef) + init_field(eno) + + simu_time = solver.T + t = 0.0 + dt = solver.dt + while t < simu_time: + runge_kutta(eno) + if t + dt > simu_time: + dt = simu_time - t + t += dt + print(f'T={t:.3f},runge_kutta{solver.rk},WENO{eno.iorder},{fluxnames[solver.iflux]} FLUX') + #visualize(eno) + return np.copy(eno.u[eno.ist:eno.ied+1]) + +def performEnoOrderAnalysis(): + iorder_max = 7 + mesh = Mesh() + solver = Solver() + #计算理论解 + u_analytical = analytical_solution(mesh.xcc, solver.T, solver.c, mesh.L) + + u_list = [] + for iorder in range(1, iorder_max+1): + u = RunEno(solver, mesh, iorder) + u_list.append(u) + + plot_eno_OrderAnalysis(solver, mesh.xcc, u_list, u_analytical) + +def performEnoTimestepAnalysis(): + mesh = Mesh() + solver = Solver() + #计算理论解 + u_analytical = analytical_solution(mesh.xcc, solver.T, solver.c, mesh.L) + + u_list = [] + dt_list = [] + solver.dt = 0.025/4 + #solver.dt = 0.025/16 + n = 12 + solver.rk = 3 + iorder = 7 + for i in range(0, n): + u = RunEno(solver, mesh, iorder) + u_list.append(u) + dt_list.append(solver.dt) + print(f'i={i+1},N={n},T={solver.T:.3f},dt={solver.dt},nt={int(solver.T/solver.dt)},runge_kutta{solver.rk},ENO{iorder},{fluxnames[solver.iflux]} FLUX') + solver.dt /= 2 + + plot_eno_TimestepAnalysis(solver, mesh.xcc, u_list, u_analytical, dt_list, iorder) + +def performEnoWenoAnalysis(): + mesh = Mesh() + solver = Solver() + #计算理论解 + u_analytical = analytical_solution(mesh.xcc, solver.T, solver.c, mesh.L) + + solver.rk = 1 + solver.dt = 0.0025 + solver.iorder = 5 + + u_list = [] + solver.interpolation = 0 + u = RunEno(solver, mesh, solver.iorder) + u_list.append(u) + solver.interpolation = 1 + u = RunWeno(solver, mesh, solver.iorder) + u_list.append(u) + + plot_EnoWeno_Analysis(solver, mesh.xcc, u_list, u_analytical) + +def plot_eno_TimestepAnalysis(solver, xcc, u_list, u_analytical, dt_list, iorder): + # 定义一个包含不同颜色、线形和标记的列表 + styles = [ + {'color': 'black', 'linestyle': '-', 'marker': 'o'}, + {'color': 'blue', 'linestyle': '--', 'marker': 's'}, + {'color': 'black', 'linestyle': '-', 'marker': '^'}, + {'color': 'blue', 'linestyle': '--', 'marker': 'v'}, + {'color': 'black', 'linestyle': '-', 'marker': '<'}, + {'color': 'blue', 'linestyle': '--', 'marker': '>'}, + {'color': 'black', 'linestyle': '-', 'marker': 'D'}, + {'color': 'blue', 'linestyle': '--', 'marker': 'o'}, + {'color': 'black', 'linestyle': '-', 'marker': 's'}, + {'color': 'blue', 'linestyle': '--', 'marker': '^'}, + {'color': 'black', 'linestyle': '-', 'marker': 'v'}, + {'color': 'blue', 'linestyle': '--', 'marker': '<'}, + {'color': 'black', 'linestyle': '-', 'marker': '>'}, + {'color': 'blue', 'linestyle': '--', 'marker': 'D'}, + ] + + n = len(u_list) + num_styles = len(styles) + + ordinalENO = get_ordinal_numbers(iorder) + ordinalRK = get_ordinal_numbers(solver.rk) + + plt.figure("OneFLOW-CFD Solver", figsize=(10, 6)) + plt.title(f'1D Convection Equation at t = {solver.T:.3f} using {iorder}{ordinalENO}-order ENO and {solver.rk}{ordinalRK}-order Runge-Kutta methods') + for i in range(0, n): + lable = 'Numerical (Rusanov)ENO' + str(iorder) + ' T='+str(dt_list[i]) + style = styles[i % num_styles] + plt.plot(xcc, u_list[i], marker=style['marker'], markerfacecolor='none', linestyle=style['linestyle'], color=style['color'], \ + markersize=5, linewidth=1.0, alpha=1.0, label=f'{lable}') + plt.plot(xcc, u_analytical, 'r--', label='Analytical') + plt.xlabel('x') + plt.ylabel('u') + plt.legend() + plt.grid(True, color='gray', linestyle='--', linewidth=0.5, alpha=0.7) + plt.tight_layout() + plt.show() + +def plot_eno_OrderAnalysis(solver, xcc, u_list, u_analytical): + # 定义一个包含不同颜色、线形和标记的列表 + styles = [ + {'color': 'black', 'linestyle': '-', 'marker': 'o'}, + {'color': 'blue', 'linestyle': '--', 'marker': 's'}, + {'color': 'black', 'linestyle': '-', 'marker': '^'}, + {'color': 'blue', 'linestyle': '--', 'marker': 'v'}, + {'color': 'black', 'linestyle': '-', 'marker': '<'}, + {'color': 'blue', 'linestyle': '--', 'marker': '>'}, + {'color': 'black', 'linestyle': '-', 'marker': 'D'}, + ] + + n = len(u_list) + num_styles = len(styles) + ordinal = get_ordinal_numbers(solver.rk) + + plt.figure("OneFLOW-CFD Solver", figsize=(10, 6)) + plt.title(f'1D Convection Equation at t = {solver.T:.3f} using [1-7]th-order ENO and {solver.rk}{ordinal}-order Runge-Kutta methods') + for i in range(0, n): + lable = 'Numerical (Rusanov)ENO' + str(i+1) + style = styles[i % num_styles] + plt.plot(xcc, u_list[i], marker=style['marker'], markerfacecolor='none', linestyle=style['linestyle'], color=style['color'], \ + markersize=5, linewidth=0.5, alpha=1.0, label=f'{lable}') + plt.plot(xcc, u_analytical, 'r--', label='Analytical') + plt.xlabel('x') + plt.ylabel('u') + plt.legend() + plt.grid(True, color='gray', linestyle='--', linewidth=0.5, alpha=0.7) + plt.tight_layout() + plt.show() + +def plot_EnoWeno_Analysis(solver, xcc, u_list, u_analytical): + # 定义一个包含不同颜色、线形和标记的列表 + styles = [ + {'color': 'black', 'linestyle': '-', 'marker': 'o'}, + {'color': 'blue', 'linestyle': '--', 'marker': 's'}, + {'color': 'black', 'linestyle': '-', 'marker': '^'}, + {'color': 'blue', 'linestyle': '--', 'marker': 'v'}, + {'color': 'black', 'linestyle': '-', 'marker': '<'}, + {'color': 'blue', 'linestyle': '--', 'marker': '>'}, + {'color': 'black', 'linestyle': '-', 'marker': 'D'}, + ] + + n = len(u_list) + num_styles = len(styles) + + ordinalENO = get_ordinal_numbers(solver.iorder) + ordinalRK = get_ordinal_numbers(solver.rk) + + plt.figure("OneFLOW-CFD Solver", figsize=(10, 6)) + plt.title(f'1D Convection Equation at t = {solver.T:.3f} using {solver.iorder}{ordinalENO}-order ENO&WENO and {solver.rk}{ordinalRK}-order Runge-Kutta methods') + for i in range(0, n): + if i == 0: + lable = f'Numerical (Rusanov)ENO{solver.iorder}' + else: + lable = f'Numerical (Rusanov)WENO{solver.iorder}' + style = styles[i % num_styles] + plt.plot(xcc, u_list[i], marker=style['marker'], markerfacecolor='none', linestyle=style['linestyle'], color=style['color'], \ + markersize=5, linewidth=0.5, alpha=1.0, label=f'{lable}') + plt.plot(xcc, u_analytical, 'r--', label='Analytical') + plt.xlabel('x') + plt.ylabel('u') + plt.legend() + plt.grid(True, color='gray', linestyle='--', linewidth=0.5, alpha=0.7) + plt.tight_layout() + plt.savefig('cfd.png', bbox_inches='tight', dpi=300) + plt.show() + +def main(): + performEnoWenoAnalysis() + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/example/weno-coef/eno/eno2_coef/01/testprj.py b/example/weno-coef/eno/eno2_coef/01/testprj.py new file mode 100644 index 00000000..d4033d9b --- /dev/null +++ b/example/weno-coef/eno/eno2_coef/01/testprj.py @@ -0,0 +1,14 @@ +import numpy as np +from fractions import Fraction + +# 定义原始矩阵 original_matrix +original_matrix = np.array([[1, -1], [1, 0]]) + +inverse = np.linalg.inv(original_matrix) + +print(f'{original_matrix=}') +print(f'{inverse=}') + +# 计算两个矩阵的乘积 +product = np.dot(original_matrix, inverse) +print(f'{product=}') diff --git a/example/weno-coef/eno/eno2_coef/01a/testprj.py b/example/weno-coef/eno/eno2_coef/01a/testprj.py new file mode 100644 index 00000000..1bdbfdac --- /dev/null +++ b/example/weno-coef/eno/eno2_coef/01a/testprj.py @@ -0,0 +1,21 @@ +import numpy as np +from fractions import Fraction + +# 定义原始矩阵 original_matrix +original_matrix = np.array([[1, -1], [1, 0]]) + +inverse = np.linalg.inv(original_matrix) + +print(f'{original_matrix=}') +print(f'{inverse=}') + +# 计算两个矩阵的乘积 +product = np.dot(original_matrix, inverse) +print(f'{product=}') + +#m = np.array([1, -1.0/2]) +m = np.array([1, 1.0/2]) + +m1 = np.dot(m, inverse) + +print(f'{m1=}') \ No newline at end of file diff --git a/example/weno-coef/eno/eno2_coef/02/testprj.py b/example/weno-coef/eno/eno2_coef/02/testprj.py new file mode 100644 index 00000000..7ea90c6c --- /dev/null +++ b/example/weno-coef/eno/eno2_coef/02/testprj.py @@ -0,0 +1,21 @@ +import numpy as np +from fractions import Fraction + +# 定义原始矩阵 original_matrix +original_matrix = np.array([[1, 0], [1, 1]]) + +inverse = np.linalg.inv(original_matrix) + +print(f'{original_matrix=}') +print(f'{inverse=}') + +# 计算两个矩阵的乘积 +product = np.dot(original_matrix, inverse) +print(f'{product=}') + +#m = np.array([1, -1.0/2]) +m = np.array([1, 1.0/2]) + +m1 = np.dot(m, inverse) + +print(f'{m1=}') \ No newline at end of file diff --git a/example/weno-coef/eno/eno2_coef/03/testprj.py b/example/weno-coef/eno/eno2_coef/03/testprj.py new file mode 100644 index 00000000..d812a576 --- /dev/null +++ b/example/weno-coef/eno/eno2_coef/03/testprj.py @@ -0,0 +1,20 @@ +import numpy as np +from fractions import Fraction + +# 定义原始矩阵 original_matrix +original_matrix = np.array([[1, 2], [1, 4]]) + +inverse = np.linalg.inv(original_matrix) + +print(f'{original_matrix=}') +print(f'{inverse=}') + +# 计算两个矩阵的乘积 +product = np.dot(original_matrix, inverse) +print(f'{product=}') + +m = np.array([1, 1.0/2]) + +m1 = np.dot(m, inverse) + +print(f'{m1=}') \ No newline at end of file diff --git a/example/weno-coef/eno/eno2_coef/04/testprj.py b/example/weno-coef/eno/eno2_coef/04/testprj.py new file mode 100644 index 00000000..2a893c55 --- /dev/null +++ b/example/weno-coef/eno/eno2_coef/04/testprj.py @@ -0,0 +1,20 @@ +import numpy as np +from fractions import Fraction + +# 定义原始矩阵 original_matrix +original_matrix = np.array([[1, 0], [1, 1]]) + +inverse = np.linalg.inv(original_matrix) + +print(f'{original_matrix=}') +print(f'{inverse=}') + +# 计算两个矩阵的乘积 +product = np.dot(original_matrix, inverse) +print(f'{product=}') + +m = np.array([1, -1.0/2]) + +m1 = np.dot(m, inverse) + +print(f'{m1=}') \ No newline at end of file