Flow Through Trees

Flow Through Trees#

The simulation of a turbulent flow over an arrangement of trees is used as validation for the points cloud implementation with immersed boundary method. The points cloud is distributed in an Cartesian arrangement with a distancing between points of 1 node of most refined lvl. The points area is the squared distance between points at lvl 0. For comparison, the results of Qi and Ishihara, 2018 and Kang et al., 2020 were used.

It consists of a 2 x 74 x 6(m) tree arrangement positioned at 1m height after an atmospheric flow. The drag coefficient is estimated 1.6 and LAD=1.16m1 hence the force_factor will be 1.856 for Δx=1m (and 0.468 for Δx=0.25m), as illustrated below:

localimage

The numerical setup goal is to correctly capture both velocity and turbulent kinetic energy changes caused by the tree arrangement. The domain setup is shown below:

localimage

Load experimental data:

base_path = Path("./tests/validation/comparison/Tree_effect/qi2018/exp")
positions = ["1H", "2H", "3H", "4H", "5H"]

df_exp = []

vel = pd.read_csv(base_path / "velocity/pitot.csv")
kin = pd.read_csv(base_path / "kinetic_energy/pitot.csv")
df_csv = pd.concat([vel, kin], axis=1, join="inner")
df_exp.append(df_csv)

for pos in positions:
    vel = pd.read_csv(base_path / f"velocity/{pos}.csv")
    kin = pd.read_csv(base_path / f"kinetic_energy/{pos}.csv")
    df_csv = pd.concat([vel, kin], axis=1, join="inner")
    df_exp.append(df_csv)

Results#

## Inflow plot
plot_curves("Inflow", df_num[0], df_num2[0], df_exp[0])

## Post obstacles plots
for i, pos in enumerate(positions):
    plot_curves(pos, df_num[i + 1], df_num2[i + 1], df_exp[i + 1])
../../../_images/0739e7c3212fe35384bfb2f91bfc2e4f7c158b36da01d4167ab1631680adb1c9.png ../../../_images/d035735973794d464c80c16d6a9711de22009deb09bf9420d7ad17bb4f460c22.png ../../../_images/1020ca92d70cf049bf93d35b5dc2d3e5a9b74e9246772b0fd87f9d56c33b8ffe.png ../../../_images/505256f7f042d305946c7f7c6c898ff85c475af5eef2cb898455c90272c27839.png ../../../_images/2823ba93dade97ce9418e76cc2aa6cba1525015f7ebf97e14514d6c2dd1a5f23.png ../../../_images/c79e9d4b7682c17f53f3d4a5a7593887222963247f0e9de41b9ec7a4c5e99224.png

It can be seen a satisfactory match between inflow and experimental data despite the coarse resolution applied on the validation case. The qualitative aspects of the flow profile after the tree arrangement are well reproduced and quantitative aspects also have a decent representation. The difference compared to Qi and Ishihara results might be due our resolution of 0.25m against their 0.025m close to the ground.

Version#

sim_cfg = next(iter(sim_cfgs.values()))
sim_info = sim_cfg.output.read_info()

nassu_commit = sim_info["commit"]
nassu_version = sim_info["version"]
print("Version:", nassu_version)
print("Commit hash:", nassu_commit)
Version: 1.6.17
Commit hash: cab6b7ad2a955ba7656e05b10c2cee0c8f0fdad4

Configuration#

from IPython.display import Code

Code(filename=filename)
variables:
  domain:
    scale: !math 1/1
    plane_height: 4.0
    body_pos: 200
    H_ref:
    pos_025H: !math ${domain.body_pos} + 0.25*${var.H_num}
    pos_05H: !math ${domain.body_pos} + 0.5*${var.H_num}
    pos_1H: !math ${domain.body_pos} + 1.0*${var.H_num}
    pos_2H: !math ${domain.body_pos} + 2.0*${var.H_num}
    pos_3H: !math ${domain.body_pos} + 3.0*${var.H_num}
    pos_4H: !math ${domain.body_pos} + 4.0*${var.H_num}
    pos_5H: !math ${domain.body_pos} + 5.0*${var.H_num}
  var:
    H_num: !math 7*${domain.scale}

simulations:
  - name: flowThroughTrees
    save_path: ./tests/validation/results/10_flow_through_trees

    n_steps: 40000

    report:
      frequency: 500

    domain:
      domain_size:
        x: 600
        y: 144
        z: 64
      block_size: 8
      point_clouds:
        tree:
          IBM:
            run: True
            cfg_use: tree_cfg
            order: 1
            interval_run:
              end_step: 0
              start_step: 0
          csv_path: fixture/point_clouds/cube_2x74x6.csv
          transformation:
            scale: !math ["${domain.scale}", "${domain.scale}", "${domain.scale}"]
            translation: !math ["${domain.body_pos}", 72, "1.0+${domain.plane_height}"]
      bodies:
        full_plane:
          IBM:
            run: True
            cfg_use: category_II
            order: 0
          lnas_path: fixture/lnas/wind_tunnel/full_plane.lnas
          small_triangles: add
          transformation:
            translation: !math [0, 0, "${domain.plane_height}"]
        plates_obstacles:
          IBM:
            order: 1
          lnas_path: fixture/lnas/wind_tunnel/category_II/plates_Nx160Ny70_6x2_spacing16x32_offset19y.lnas
          volumes_limits:
            body_transformed:
              - start: !math [10, 20, 0]
                end: !math [120, 124, 64]
          small_triangles: add
          transformation:
            translation: !math [0, 1, "${domain.plane_height}"]
            scale: !math [4.0, 4.0, "2*32.0*${domain.scale}"] #2m

      refinement:
        static:
          default:
            volumes_refine:
              # - start: [0, 56, 2]
              #   end: [256, 88, 12]
              #   lvl: 3
              #   is_abs: true
              - start: [0, 34, 0]
                end: [288, 110, 24]
                lvl: 2
                is_abs: true
              - start: [0, 0, 0]
                end: [352, 144, 40]
                lvl: 1
                is_abs: true

    data:
      divergence: { frequency: 10 }
      monitors:
        fields:
          rho_max:
            macrs: [rho]
            stats: [min, max]
            interval: { start_step: 500, end_step: 10000, frequency: 50 }
      instantaneous:
        full_domain:
          { interval: { frequency: 10000 }, macrs: [rho, u, omega_LES, f_IBM] }
      statistics:
        interval: { frequency: 10, start_step: 10000 }
        macrs_1st_order: [rho, u]
        macrs_2nd_order: [u]
        exports:
          full_domain: { interval: { frequency: 10000 } }
      probes:
        historic_series:
          velocities:
            macrs: ["u"]
            interval: { frequency: 10, lvl: 0 }
            points:
              velocity_probe:
                pos:
                  !math [
                    "${domain.body_pos}-50*${domain.scale}",
                    72,
                    "${domain.plane_height} + 7*${domain.scale}",
                  ]
            lines:
              inlet_profile:
                dist: 0.25
                start_pos: !math [0, 72.0, "${domain.plane_height}"]
                end_pos: !math [0, 72.0, "${domain.plane_height} + 14*${domain.scale}"]
              velocity_profile:
                dist: 0.25
                start_pos:
                  !math [
                    "${domain.body_pos}-50*${domain.scale}",
                    72.0,
                    "${domain.plane_height}",
                  ]
                end_pos:
                  !math [
                    "${domain.body_pos}-50*${domain.scale}",
                    72.0,
                    "${domain.plane_height} + 14*${domain.scale}",
                  ]
              pos_025H:
                dist: 0.25
                start_pos: !math ["${domain.pos_025H}", 72.0, "${domain.plane_height}"]
                end_pos:
                  !math [
                    "${domain.pos_025H}",
                    72.0,
                    "${domain.plane_height} + 14*${domain.scale}",
                  ]
              pos_05H:
                dist: 0.25
                start_pos: !math ["${domain.pos_05H}", 72.0, "${domain.plane_height}"]
                end_pos:
                  !math [
                    "${domain.pos_05H}",
                    72.0,
                    "${domain.plane_height} + 14*${domain.scale}",
                  ]
              pos_1H:
                dist: 0.25
                start_pos: !math ["${domain.pos_1H}", 72.0, "${domain.plane_height}"]
                end_pos:
                  !math [
                    "${domain.pos_1H}",
                    72.0,
                    "${domain.plane_height} + 14*${domain.scale}",
                  ]
              pos_2H:
                dist: 0.25
                start_pos: !math ["${domain.pos_2H}", 72.0, "${domain.plane_height}"]
                end_pos:
                  !math [
                    "${domain.pos_2H}",
                    72.0,
                    "${domain.plane_height} + 14*${domain.scale}",
                  ]
              pos_3H:
                dist: 0.25
                start_pos: !math ["${domain.pos_3H}", 72.0, "${domain.plane_height}"]
                end_pos:
                  !math [
                    "${domain.pos_3H}",
                    72.0,
                    "${domain.plane_height} + 14*${domain.scale}",
                  ]
              pos_4H:
                dist: 0.25
                start_pos: !math ["${domain.pos_4H}", 72.0, "${domain.plane_height}"]
                end_pos:
                  !math [
                    "${domain.pos_4H}",
                    72.0,
                    "${domain.plane_height} + 14*${domain.scale}",
                  ]
              pos_5H:
                dist: 0.25
                start_pos: !math ["${domain.pos_5H}", 72.0, "${domain.plane_height}"]
                end_pos:
                  !math [
                    "${domain.pos_5H}",
                    72.0,
                    "${domain.plane_height} + 14*${domain.scale}",
                  ]

    models:
      precision:
        default: single

      LBM:
        tau: 0.500011
        vel_set: D3Q27
        coll_oper: RRBGK
      initialization:
        rho: 1
        u: { x: 0.05, y: 0, z: 0 }

      engine:
        name: CUDA

      BC:
        periodic_dims: [false, false, false]
        BC_map:
          - pos: E
            BC: RegularizedNeumannOutlet
            rho: 1.0
            wall_normal: E
            order: 2

          - pos: F
            BC: Neumann
            wall_normal: F
            order: 1

          - pos: B
            BC: RegularizedHWBB
            wall_normal: B
            order: 1

          - pos: N
            BC: Neumann
            wall_normal: N
            order: 0

          - pos: S
            BC: Neumann
            wall_normal: S
            order: 0
        SEM:
          eddies:
            lengthscale: { x: 20, y: 20, z: 20 }
            domain_limits_yz:
              start: [20, -20]
              end: [124, 40]
          profile:
            csv_profile_data: "fixture/SEM/category_vprofile/profile_log_cat4_H150_Uh0.06.csv"
            z_offset: !math "${domain.plane_height}"
            K: 1.0

      LES:
        model: Smagorinsky
        sgs_cte: 0.17

      IBM:
        body_cfgs:
          tree_cfg:
            n_iterations: 1
            forces_factor: !math 1.6*1.16
            kinetic_energy_correction: true
          category_II:
            n_iterations: 3
            forces_factor: 0.5
            wall_model:
              name: EqLog
              dist_ref: 3.125
              dist_shell: 0.125
              start_step: 5000
              params:
                z0: !math "0.01*${domain.scale}"
                TDMA_max_error: 1e-04
                TDMA_max_iters: 10
                TDMA_n_div: 51
          default: {}