From d3087d5560d2ff1264bbc79694133f21701d53aa Mon Sep 17 00:00:00 2001 From: hgopalan Date: Wed, 3 Apr 2024 19:49:24 -0600 Subject: [PATCH 01/77] Initial Commit of Terrain Model --- .../icns/source_terms/CMakeLists.txt | 3 +- .../icns/source_terms/DragForcing.H | 50 ++++++++ .../icns/source_terms/DragForcing.cpp | 109 ++++++++++++++++++ amr-wind/physics/CMakeLists.txt | 1 + amr-wind/physics/TerrainDrag.H | 54 +++++++++ amr-wind/physics/TerrainDrag.cpp | 106 +++++++++++++++++ 6 files changed, 322 insertions(+), 1 deletion(-) create mode 100644 amr-wind/equation_systems/icns/source_terms/DragForcing.H create mode 100644 amr-wind/equation_systems/icns/source_terms/DragForcing.cpp create mode 100644 amr-wind/physics/TerrainDrag.H create mode 100644 amr-wind/physics/TerrainDrag.cpp diff --git a/amr-wind/equation_systems/icns/source_terms/CMakeLists.txt b/amr-wind/equation_systems/icns/source_terms/CMakeLists.txt index 41b7032f4d..959893163c 100644 --- a/amr-wind/equation_systems/icns/source_terms/CMakeLists.txt +++ b/amr-wind/equation_systems/icns/source_terms/CMakeLists.txt @@ -13,5 +13,6 @@ target_sources(${amr_wind_lib_name} PRIVATE ABLMesoForcingMom.cpp BurggrafFlowForcing.cpp RayleighDamping.cpp - NonLinearSGSTerm.cpp + NonLinearSGSTerm.cpp + DragForcing.cpp ) diff --git a/amr-wind/equation_systems/icns/source_terms/DragForcing.H b/amr-wind/equation_systems/icns/source_terms/DragForcing.H new file mode 100644 index 0000000000..589791062c --- /dev/null +++ b/amr-wind/equation_systems/icns/source_terms/DragForcing.H @@ -0,0 +1,50 @@ +#ifndef DRAGFORCING_H +#define DRAGFORCING_H + +#include "amr-wind/equation_systems/icns/MomentumSource.H" +#include "amr-wind/core/SimTime.H" +#include "amr-wind/CFDSim.H" + +namespace amr_wind::pde::icns { + +/** Adds the non-linear terms from the Kosovic Model to Momentum Equation.. + * + * \ingroup icns_src NonLinearSGS + * + * \sa NonLinearSGS + */ +class DragForcing : public MomentumSource::Register +{ +public: + static std::string identifier() { return "DragForcing"; } + + explicit DragForcing(const CFDSim& sim); + + ~DragForcing() override; + + void operator()( + const int lev, + const amrex::MFIter& mfi, + const amrex::Box& bx, + const FieldState fstate, + const amrex::Array4& src_term) const override; + + +private: + const CFDSim& m_sim; + const amrex::AmrCore&m_mesh; + const Field& m_velocity; + Field& m_terrainBlank; + Field& m_terrainDrag; + amrex::Gpu::DeviceVector gpu_vel_ht; + amrex::Gpu::DeviceVector gpu_vel_vals; + amrex::Real m_drag{8.0}; + amrex::Real m_spongeStrength{1.0}; + amrex::Real m_spongeDensity{1.0}; + amrex::Real m_spongePercentX{20}; + amrex::Real m_spongePercentY{20}; +}; + +} // namespace amr_wind::pde::icns + +#endif /* NONLINEARSGSTERM_H */ diff --git a/amr-wind/equation_systems/icns/source_terms/DragForcing.cpp b/amr-wind/equation_systems/icns/source_terms/DragForcing.cpp new file mode 100644 index 0000000000..54a000b6c1 --- /dev/null +++ b/amr-wind/equation_systems/icns/source_terms/DragForcing.cpp @@ -0,0 +1,109 @@ +#include "amr-wind/equation_systems/icns/source_terms/DragForcing.H" +#include "amr-wind/utilities/IOManager.H" + +#include "AMReX_Gpu.H" +#include "AMReX_Random.H" +#include "amr-wind/wind_energy/ABL.H" + +namespace amr_wind::pde::icns { + +DragForcing::DragForcing(const CFDSim& sim) + :m_sim(sim), + m_mesh(sim.mesh()), + m_velocity(sim.repo().get_field("velocity")), + m_terrainBlank(sim.repo().get_field("terrainBlank")), + m_terrainDrag(sim.repo().get_field("terrainDrag")) + +{ + const auto& abl = m_sim.physics_manager().get(); + const VelPlaneAveraging& fa_velocity=abl.abl_statistics().vel_profile_coarse(); + gpu_vel_ht.resize(fa_velocity.line_centroids().size()); + gpu_vel_vals.resize(fa_velocity.line_average().size()); + amrex::Gpu::copy(amrex::Gpu::hostToDevice, fa_velocity.line_centroids().begin(), + fa_velocity.line_centroids().end(), gpu_vel_ht.begin()); + amrex::Gpu::copy(amrex::Gpu::hostToDevice, fa_velocity.line_average().begin(), + fa_velocity.line_average().end(), gpu_vel_vals.begin()); + /*for(int ii=0;ii& src_term) const +{ + const auto& vel = + m_velocity.state(field_impl::dof_state(fstate))(lev).const_array(mfi); + const auto blank = m_terrainBlank(lev).const_array(mfi); + const auto drag = m_terrainDrag(lev).const_array(mfi); + const auto& geom_vec = m_mesh.Geom(); + const auto& geom = geom_vec[lev]; + const auto& dx = geom.CellSize(); + const auto& prob_lo = geom.ProbLoArray(); + const auto& prob_hi = geom.ProbHiArray(); + //const amrex::Real dy = geom.CellSize()[1]; + //const amrex::Real dz = geom.CellSize()[2]; + //Real xi = (x - xhi_sponge_start) / (ProbHiArr[0] - xhi_sponge_start); + //rho_u_rhs(i, j, k) -= sponge_strength * xi * xi * (rho_u(i, j, k) - sponge_density*sponge_x_velocity); + const amrex::Real gpu_drag=m_drag; + const amrex::Real gpu_spongeStrength=m_spongeStrength; + const amrex::Real gpu_spongeDensity=m_spongeDensity; + const amrex::Real gpu_startX=(1-m_spongePercentX/100.0)*prob_hi[0]; + const amrex::Real gpu_startY=(1-m_spongePercentY/100.0)*prob_hi[1]; + amrex::ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept { + const amrex::Real ux=vel(i,j,k,0); + const amrex::Real uy=vel(i,j,k,1); + const amrex::Real uz=vel(i,j,k,2); + const amrex::Real x1 = prob_lo[0] + (i + 0.5) * dx[0]; + const amrex::Real x2 = prob_lo[1] + (j + 0.5) * dx[1]; + const amrex::Real x3 = prob_lo[2] + (k + 0.5) * dx[2]; + amrex::Real xdamping=0; + amrex::Real ydamping=0; + if(x1>gpu_startX){ + amrex::Real xi=(x1 - gpu_startX) / (prob_hi[0] - gpu_startX); + xdamping=gpu_spongeStrength * xi * xi ; + } + if(x2>gpu_startY){ + amrex::Real yi=(x2 - gpu_startY) / (prob_hi[1] - gpu_startY); + ydamping=gpu_spongeStrength * yi * yi; + } + const amrex::Real m=std::sqrt(ux*ux+uy*uy+uz*uz); + amrex::Real Cd=gpu_drag/dx[0]; + amrex::Real gpu_spongeVelX=0.0; + amrex::Real gpu_spongeVelY=0.0; + amrex::Real gpu_spongeVelZ=0.0; + amrex::Real residual=1000; + amrex::Real height_error=0.0; + for(int ii=0;ii +{ +public: + static std::string identifier() { return "TerrainDrag"; } + + explicit TerrainDrag(CFDSim& sim); + + ~TerrainDrag() override = default; + + void initialize_fields(int level, const amrex::Geometry& geom) override; + + void post_init_actions() override{} + + void post_regrid_actions() override {} + + void pre_advance_work() override{} + + void post_advance_work() override{} + + // amrex::Real computeTerrainHeight(const amrex::Real x1,const amrex::Real x2) const; +private: + CFDSim& m_sim; + const FieldRepo& m_repo; + const amrex::AmrCore& m_mesh; + Field& m_velocity; + // Blanking Field for Terrain or Buildings + Field& m_terrainBlank; + // Terrain Height field - Not in use now + Field& m_terrainDrag; + // Reading the Terrain Coordinates from file + amrex::Vector m_xterrain,m_yterrain,m_zterrain; + +}; +} // namespace amr_wind::terraindrag + +#endif diff --git a/amr-wind/physics/TerrainDrag.cpp b/amr-wind/physics/TerrainDrag.cpp new file mode 100644 index 0000000000..bd2b7f0e1c --- /dev/null +++ b/amr-wind/physics/TerrainDrag.cpp @@ -0,0 +1,106 @@ +#include "amr-wind/physics/TerrainDrag.H" +#include "amr-wind/CFDSim.H" +#include "AMReX_iMultiFab.H" +#include "AMReX_MultiFabUtil.H" +#include "AMReX_ParmParse.H" +#include "AMReX_ParReduce.H" +#include "amr-wind/utilities/trig_ops.H" +#include "amr-wind/utilities/IOManager.H" + +namespace amr_wind::terraindrag { + +namespace { + +} // namespace + +TerrainDrag::TerrainDrag(CFDSim& sim) + : m_sim(sim) + , m_repo(sim.repo()) + , m_mesh(sim.mesh()) + , m_velocity(sim.repo().get_field("velocity")) + , m_terrainBlank(sim.repo().declare_field("terrainBlank", 1,1,1)) + , m_terrainDrag(sim.repo().declare_field("terrainDrag", 1,1,1)) +{ + std::ifstream file("terrain.amrwind"); + amrex::Real value1,value2,value3; + while(file>>value1>>value2>>value3){ + m_xterrain.push_back(value1); + m_yterrain.push_back(value2); + m_zterrain.push_back(value3); + } + file.close(); + m_sim.io_manager().register_io_var("terrainDrag"); + m_sim.io_manager().register_io_var("terrainBlank"); +} + +void TerrainDrag::initialize_fields(int level, const amrex::Geometry& geom) +{ + using namespace utils; + + const auto& dx = geom.CellSizeArray(); + const auto& prob_lo = geom.ProbLoArray(); + auto& velocity = m_velocity(level); + auto& blanking = m_terrainBlank(level); + auto& drag=m_terrainDrag(level); + //amrex::Print()<<" Terrain Initial:"< gpu_xterrain(m_xterrain.size()); + amrex::Gpu::DeviceVector gpu_yterrain(m_xterrain.size()); + amrex::Gpu::DeviceVector gpu_zterrain(m_xterrain.size()); + auto* xterrain_ptr = gpu_xterrain.data(); + auto* yterrain_ptr = gpu_yterrain.data(); + auto* zterrain_ptr = gpu_zterrain.data(); + amrex::ParallelFor(m_xterrain.size(), [=] AMREX_GPU_DEVICE(int n) { + xterrain_ptr[n] = m_xterrain[n]; + yterrain_ptr[n] = m_yterrain[n]; + zterrain_ptr[n] = m_zterrain[n]; + }); + for (amrex::MFIter mfi(velocity); mfi.isValid(); ++mfi) { + const auto& vbx = mfi.validbox(); + auto levelBlanking = blanking.array(mfi); + auto levelDrag=drag.array(mfi); + const amrex::Real terrainSize=m_xterrain.size(); + amrex::ParallelFor( + vbx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept { + // compute the source term + const amrex::Real x1 = prob_lo[0] + (i + 0.5) * dx[0]; + const amrex::Real x2 = prob_lo[1] + (j + 0.5) * dx[1]; + const amrex::Real x3 = prob_lo[2] + (k + 0.5) * dx[2]; + // Terrain Height + amrex::Real residual=10000; + amrex::Real terrainHt=0.0; + for(int ii=0;iiterrainHt && k>0 && levelBlanking(i,j,k-1,0)==1){ + // amrex::Print()<<"Adding Drag:"< Date: Mon, 8 Apr 2024 09:24:50 -0600 Subject: [PATCH 02/77] Update for clang format consistency --- .../icns/source_terms/DragForcing.H | 29 ++-- .../icns/source_terms/DragForcing.cpp | 145 ++++++++++-------- amr-wind/physics/TerrainDrag.H | 35 ++--- amr-wind/physics/TerrainDrag.cpp | 122 ++++++++------- 4 files changed, 171 insertions(+), 160 deletions(-) diff --git a/amr-wind/equation_systems/icns/source_terms/DragForcing.H b/amr-wind/equation_systems/icns/source_terms/DragForcing.H index 589791062c..55e687f6af 100644 --- a/amr-wind/equation_systems/icns/source_terms/DragForcing.H +++ b/amr-wind/equation_systems/icns/source_terms/DragForcing.H @@ -18,7 +18,7 @@ class DragForcing : public MomentumSource::Register public: static std::string identifier() { return "DragForcing"; } - explicit DragForcing(const CFDSim& sim); + explicit DragForcing(const CFDSim& sim); ~DragForcing() override; @@ -27,22 +27,21 @@ public: const amrex::MFIter& mfi, const amrex::Box& bx, const FieldState fstate, - const amrex::Array4& src_term) const override; + const amrex::Array4& src_term) const override; - private: - const CFDSim& m_sim; - const amrex::AmrCore&m_mesh; - const Field& m_velocity; - Field& m_terrainBlank; - Field& m_terrainDrag; - amrex::Gpu::DeviceVector gpu_vel_ht; - amrex::Gpu::DeviceVector gpu_vel_vals; - amrex::Real m_drag{8.0}; - amrex::Real m_spongeStrength{1.0}; - amrex::Real m_spongeDensity{1.0}; - amrex::Real m_spongePercentX{20}; - amrex::Real m_spongePercentY{20}; + const CFDSim& m_sim; + const amrex::AmrCore& m_mesh; + const Field& m_velocity; + Field& m_terrainBlank; + Field& m_terrainDrag; + amrex::Gpu::DeviceVector gpu_vel_ht; + amrex::Gpu::DeviceVector gpu_vel_vals; + amrex::Real m_drag{8.0}; + amrex::Real m_spongeStrength{1.0}; + amrex::Real m_spongeDensity{1.0}; + amrex::Real m_spongePercentX{20}; + amrex::Real m_spongePercentY{20}; }; } // namespace amr_wind::pde::icns diff --git a/amr-wind/equation_systems/icns/source_terms/DragForcing.cpp b/amr-wind/equation_systems/icns/source_terms/DragForcing.cpp index 54a000b6c1..e3a09ae4af 100644 --- a/amr-wind/equation_systems/icns/source_terms/DragForcing.cpp +++ b/amr-wind/equation_systems/icns/source_terms/DragForcing.cpp @@ -8,21 +8,24 @@ namespace amr_wind::pde::icns { DragForcing::DragForcing(const CFDSim& sim) - :m_sim(sim), - m_mesh(sim.mesh()), - m_velocity(sim.repo().get_field("velocity")), - m_terrainBlank(sim.repo().get_field("terrainBlank")), - m_terrainDrag(sim.repo().get_field("terrainDrag")) - + : m_sim(sim) + , m_mesh(sim.mesh()) + , m_velocity(sim.repo().get_field("velocity")) + , m_terrainBlank(sim.repo().get_field("terrainBlank")) + , m_terrainDrag(sim.repo().get_field("terrainDrag")) + { const auto& abl = m_sim.physics_manager().get(); - const VelPlaneAveraging& fa_velocity=abl.abl_statistics().vel_profile_coarse(); + const VelPlaneAveraging& fa_velocity = + abl.abl_statistics().vel_profile_coarse(); gpu_vel_ht.resize(fa_velocity.line_centroids().size()); gpu_vel_vals.resize(fa_velocity.line_average().size()); - amrex::Gpu::copy(amrex::Gpu::hostToDevice, fa_velocity.line_centroids().begin(), - fa_velocity.line_centroids().end(), gpu_vel_ht.begin()); - amrex::Gpu::copy(amrex::Gpu::hostToDevice, fa_velocity.line_average().begin(), - fa_velocity.line_average().end(), gpu_vel_vals.begin()); + amrex::Gpu::copy( + amrex::Gpu::hostToDevice, fa_velocity.line_centroids().begin(), + fa_velocity.line_centroids().end(), gpu_vel_ht.begin()); + amrex::Gpu::copy( + amrex::Gpu::hostToDevice, fa_velocity.line_average().begin(), + fa_velocity.line_average().end(), gpu_vel_vals.begin()); /*for(int ii=0;ii& src_term) const { const auto& vel = - m_velocity.state(field_impl::dof_state(fstate))(lev).const_array(mfi); + m_velocity.state(field_impl::dof_state(fstate))(lev).const_array(mfi); const auto blank = m_terrainBlank(lev).const_array(mfi); const auto drag = m_terrainDrag(lev).const_array(mfi); const auto& geom_vec = m_mesh.Geom(); - const auto& geom = geom_vec[lev]; + const auto& geom = geom_vec[lev]; const auto& dx = geom.CellSize(); const auto& prob_lo = geom.ProbLoArray(); const auto& prob_hi = geom.ProbHiArray(); - //const amrex::Real dy = geom.CellSize()[1]; - //const amrex::Real dz = geom.CellSize()[2]; - //Real xi = (x - xhi_sponge_start) / (ProbHiArr[0] - xhi_sponge_start); - //rho_u_rhs(i, j, k) -= sponge_strength * xi * xi * (rho_u(i, j, k) - sponge_density*sponge_x_velocity); - const amrex::Real gpu_drag=m_drag; - const amrex::Real gpu_spongeStrength=m_spongeStrength; - const amrex::Real gpu_spongeDensity=m_spongeDensity; - const amrex::Real gpu_startX=(1-m_spongePercentX/100.0)*prob_hi[0]; - const amrex::Real gpu_startY=(1-m_spongePercentY/100.0)*prob_hi[1]; + // const amrex::Real dy = geom.CellSize()[1]; + // const amrex::Real dz = geom.CellSize()[2]; + // Real xi = (x - xhi_sponge_start) / (ProbHiArr[0] - xhi_sponge_start); + // rho_u_rhs(i, j, k) -= sponge_strength * xi * xi * (rho_u(i, j, k) - + // sponge_density*sponge_x_velocity); + const amrex::Real gpu_drag = m_drag; + const amrex::Real gpu_spongeStrength = m_spongeStrength; + const amrex::Real gpu_spongeDensity = m_spongeDensity; + const amrex::Real gpu_startX = (1 - m_spongePercentX / 100.0) * prob_hi[0]; + const amrex::Real gpu_startY = (1 - m_spongePercentY / 100.0) * prob_hi[1]; amrex::ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept { - const amrex::Real ux=vel(i,j,k,0); - const amrex::Real uy=vel(i,j,k,1); - const amrex::Real uz=vel(i,j,k,2); - const amrex::Real x1 = prob_lo[0] + (i + 0.5) * dx[0]; - const amrex::Real x2 = prob_lo[1] + (j + 0.5) * dx[1]; - const amrex::Real x3 = prob_lo[2] + (k + 0.5) * dx[2]; - amrex::Real xdamping=0; - amrex::Real ydamping=0; - if(x1>gpu_startX){ - amrex::Real xi=(x1 - gpu_startX) / (prob_hi[0] - gpu_startX); - xdamping=gpu_spongeStrength * xi * xi ; - } - if(x2>gpu_startY){ - amrex::Real yi=(x2 - gpu_startY) / (prob_hi[1] - gpu_startY); - ydamping=gpu_spongeStrength * yi * yi; - } - const amrex::Real m=std::sqrt(ux*ux+uy*uy+uz*uz); - amrex::Real Cd=gpu_drag/dx[0]; - amrex::Real gpu_spongeVelX=0.0; - amrex::Real gpu_spongeVelY=0.0; - amrex::Real gpu_spongeVelZ=0.0; - amrex::Real residual=1000; - amrex::Real height_error=0.0; - for(int ii=0;ii gpu_startX) { + amrex::Real xi = (x1 - gpu_startX) / (prob_hi[0] - gpu_startX); + xdamping = gpu_spongeStrength * xi * xi; + } + if (x2 > gpu_startY) { + amrex::Real yi = (x2 - gpu_startY) / (prob_hi[1] - gpu_startY); + ydamping = gpu_spongeStrength * yi * yi; + } + const amrex::Real m = std::sqrt(ux * ux + uy * uy + uz * uz); + amrex::Real Cd = gpu_drag / dx[0]; + amrex::Real gpu_spongeVelX = 0.0; + amrex::Real gpu_spongeVelY = 0.0; + amrex::Real gpu_spongeVelZ = 0.0; + amrex::Real residual = 1000; + amrex::Real height_error = 0.0; + for (int ii = 0; ii < gpu_vel_ht.size(); ++ii) { + height_error = std::abs(x3 - gpu_vel_ht[ii]); + if (height_error < residual) { + residual = height_error; + gpu_spongeVelX = gpu_vel_vals[3 * ii]; + gpu_spongeVelY = gpu_vel_vals[3 * ii + 1]; + gpu_spongeVelZ = gpu_vel_vals[3 * ii + 2]; + } + } + // Terrain Drag + amrex::Real kappa = 0.41; + amrex::Real ustar = + std::sqrt(ux * ux + uy * uy) * kappa / std::log((x3 + 0.1) / 0.1); + amrex::Real Dxz = + -ustar * ustar * ux / (1e-5 + std::sqrt(ux * ux + uy * uy)) / dx[2]; + amrex::Real Dyz = + -ustar * ustar * uy / (1e-5 + std::sqrt(ux * ux + uy * uy)) / dx[2]; + // Adjusting Cd for momentum + amrex::Real CdM = std::min(Cd * 5.0 / (m + 1e-5), 100.0); + src_term(i, j, k, 0) -= + (CdM * m * ux * blank(i, j, k) + Dxz * drag(i, j, k) + + (xdamping + ydamping) * (ux - gpu_spongeDensity * gpu_spongeVelX)); + src_term(i, j, k, 1) -= + (CdM * m * uy * blank(i, j, k) + Dyz * drag(i, j, k) + + (xdamping + ydamping) * (uy - gpu_spongeDensity * gpu_spongeVelY)); + src_term(i, j, k, 2) -= + (CdM * m * uz * blank(i, j, k) + + (xdamping + ydamping) * (uz - gpu_spongeDensity * gpu_spongeVelZ)); }); } diff --git a/amr-wind/physics/TerrainDrag.H b/amr-wind/physics/TerrainDrag.H index 3ab067a5eb..345db18ee6 100644 --- a/amr-wind/physics/TerrainDrag.H +++ b/amr-wind/physics/TerrainDrag.H @@ -7,10 +7,7 @@ namespace amr_wind::terraindrag { -namespace { - - -} // namespace +namespace {} // namespace /** Terraindrag Flow physics * \ingroup physics @@ -27,27 +24,27 @@ public: void initialize_fields(int level, const amrex::Geometry& geom) override; - void post_init_actions() override{} + void post_init_actions() override {} void post_regrid_actions() override {} - void pre_advance_work() override{} + void pre_advance_work() override {} - void post_advance_work() override{} + void post_advance_work() override {} - // amrex::Real computeTerrainHeight(const amrex::Real x1,const amrex::Real x2) const; + // amrex::Real computeTerrainHeight(const amrex::Real x1,const + // amrex::Real x2) const; private: - CFDSim& m_sim; - const FieldRepo& m_repo; - const amrex::AmrCore& m_mesh; - Field& m_velocity; - // Blanking Field for Terrain or Buildings - Field& m_terrainBlank; - // Terrain Height field - Not in use now - Field& m_terrainDrag; - // Reading the Terrain Coordinates from file - amrex::Vector m_xterrain,m_yterrain,m_zterrain; - + CFDSim& m_sim; + const FieldRepo& m_repo; + const amrex::AmrCore& m_mesh; + Field& m_velocity; + // Blanking Field for Terrain or Buildings + Field& m_terrainBlank; + // Terrain Height field - Not in use now + Field& m_terrainDrag; + // Reading the Terrain Coordinates from file + amrex::Vector m_xterrain, m_yterrain, m_zterrain; }; } // namespace amr_wind::terraindrag diff --git a/amr-wind/physics/TerrainDrag.cpp b/amr-wind/physics/TerrainDrag.cpp index bd2b7f0e1c..45118e0ca7 100644 --- a/amr-wind/physics/TerrainDrag.cpp +++ b/amr-wind/physics/TerrainDrag.cpp @@ -9,28 +9,26 @@ namespace amr_wind::terraindrag { -namespace { - -} // namespace +namespace {} // namespace TerrainDrag::TerrainDrag(CFDSim& sim) : m_sim(sim) , m_repo(sim.repo()) , m_mesh(sim.mesh()) , m_velocity(sim.repo().get_field("velocity")) - , m_terrainBlank(sim.repo().declare_field("terrainBlank", 1,1,1)) - , m_terrainDrag(sim.repo().declare_field("terrainDrag", 1,1,1)) + , m_terrainBlank(sim.repo().declare_field("terrainBlank", 1, 1, 1)) + , m_terrainDrag(sim.repo().declare_field("terrainDrag", 1, 1, 1)) { - std::ifstream file("terrain.amrwind"); - amrex::Real value1,value2,value3; - while(file>>value1>>value2>>value3){ - m_xterrain.push_back(value1); - m_yterrain.push_back(value2); - m_zterrain.push_back(value3); - } - file.close(); - m_sim.io_manager().register_io_var("terrainDrag"); - m_sim.io_manager().register_io_var("terrainBlank"); + std::ifstream file("terrain.amrwind"); + amrex::Real value1, value2, value3; + while (file >> value1 >> value2 >> value3) { + m_xterrain.push_back(value1); + m_yterrain.push_back(value2); + m_zterrain.push_back(value3); + } + file.close(); + m_sim.io_manager().register_io_var("terrainDrag"); + m_sim.io_manager().register_io_var("terrainBlank"); } void TerrainDrag::initialize_fields(int level, const amrex::Geometry& geom) @@ -41,9 +39,9 @@ void TerrainDrag::initialize_fields(int level, const amrex::Geometry& geom) const auto& prob_lo = geom.ProbLoArray(); auto& velocity = m_velocity(level); auto& blanking = m_terrainBlank(level); - auto& drag=m_terrainDrag(level); - //amrex::Print()<<" Terrain Initial:"< gpu_xterrain(m_xterrain.size()); amrex::Gpu::DeviceVector gpu_yterrain(m_xterrain.size()); amrex::Gpu::DeviceVector gpu_zterrain(m_xterrain.size()); @@ -51,56 +49,62 @@ void TerrainDrag::initialize_fields(int level, const amrex::Geometry& geom) auto* yterrain_ptr = gpu_yterrain.data(); auto* zterrain_ptr = gpu_zterrain.data(); amrex::ParallelFor(m_xterrain.size(), [=] AMREX_GPU_DEVICE(int n) { - xterrain_ptr[n] = m_xterrain[n]; - yterrain_ptr[n] = m_yterrain[n]; - zterrain_ptr[n] = m_zterrain[n]; + xterrain_ptr[n] = m_xterrain[n]; + yterrain_ptr[n] = m_yterrain[n]; + zterrain_ptr[n] = m_zterrain[n]; }); for (amrex::MFIter mfi(velocity); mfi.isValid(); ++mfi) { const auto& vbx = mfi.validbox(); auto levelBlanking = blanking.array(mfi); - auto levelDrag=drag.array(mfi); - const amrex::Real terrainSize=m_xterrain.size(); + auto levelDrag = drag.array(mfi); + const amrex::Real terrainSize = m_xterrain.size(); amrex::ParallelFor( - vbx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept { + vbx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept { // compute the source term const amrex::Real x1 = prob_lo[0] + (i + 0.5) * dx[0]; const amrex::Real x2 = prob_lo[1] + (j + 0.5) * dx[1]; - const amrex::Real x3 = prob_lo[2] + (k + 0.5) * dx[2]; - // Terrain Height - amrex::Real residual=10000; - amrex::Real terrainHt=0.0; - for(int ii=0;iiterrainHt && k>0 && levelBlanking(i,j,k-1,0)==1){ - // amrex::Print()<<"Adding Drag:"< terrainHt && k > 0 && + levelBlanking(i, j, k - 1, 0) == 1) { + // amrex::Print()<<"Adding Drag:"< Date: Mon, 8 Apr 2024 10:46:31 -0600 Subject: [PATCH 03/77] Coding modifications for consistency --- .../icns/source_terms/DragForcing.H | 14 +- .../icns/source_terms/DragForcing.cpp | 145 +++++++++--------- amr-wind/physics/TerrainDrag.cpp | 41 +++-- 3 files changed, 98 insertions(+), 102 deletions(-) diff --git a/amr-wind/equation_systems/icns/source_terms/DragForcing.H b/amr-wind/equation_systems/icns/source_terms/DragForcing.H index 55e687f6af..ba100b81a0 100644 --- a/amr-wind/equation_systems/icns/source_terms/DragForcing.H +++ b/amr-wind/equation_systems/icns/source_terms/DragForcing.H @@ -7,11 +7,11 @@ namespace amr_wind::pde::icns { -/** Adds the non-linear terms from the Kosovic Model to Momentum Equation.. +/** Adding Terrain-induced drag forcing to momentum equation .. * - * \ingroup icns_src NonLinearSGS + * \ingroup icns_src DragForcing * - * \sa NonLinearSGS + * \sa DragForcing */ class DragForcing : public MomentumSource::Register { @@ -35,9 +35,9 @@ private: const Field& m_velocity; Field& m_terrainBlank; Field& m_terrainDrag; - amrex::Gpu::DeviceVector gpu_vel_ht; - amrex::Gpu::DeviceVector gpu_vel_vals; - amrex::Real m_drag{8.0}; + amrex::Gpu::DeviceVector device_vel_ht; + amrex::Gpu::DeviceVector device_vel_vals; + amrex::Real m_dragCoeff{8.0}; amrex::Real m_spongeStrength{1.0}; amrex::Real m_spongeDensity{1.0}; amrex::Real m_spongePercentX{20}; @@ -46,4 +46,4 @@ private: } // namespace amr_wind::pde::icns -#endif /* NONLINEARSGSTERM_H */ +#endif /* DRAGFORCING_H */ diff --git a/amr-wind/equation_systems/icns/source_terms/DragForcing.cpp b/amr-wind/equation_systems/icns/source_terms/DragForcing.cpp index e3a09ae4af..a2c3397049 100644 --- a/amr-wind/equation_systems/icns/source_terms/DragForcing.cpp +++ b/amr-wind/equation_systems/icns/source_terms/DragForcing.cpp @@ -18,20 +18,14 @@ DragForcing::DragForcing(const CFDSim& sim) const auto& abl = m_sim.physics_manager().get(); const VelPlaneAveraging& fa_velocity = abl.abl_statistics().vel_profile_coarse(); - gpu_vel_ht.resize(fa_velocity.line_centroids().size()); - gpu_vel_vals.resize(fa_velocity.line_average().size()); + device_vel_ht.resize(fa_velocity.line_centroids().size()); + device_vel_vals.resize(fa_velocity.line_average().size()); amrex::Gpu::copy( amrex::Gpu::hostToDevice, fa_velocity.line_centroids().begin(), - fa_velocity.line_centroids().end(), gpu_vel_ht.begin()); + fa_velocity.line_centroids().end(), device_vel_ht.begin()); amrex::Gpu::copy( amrex::Gpu::hostToDevice, fa_velocity.line_average().begin(), - fa_velocity.line_average().end(), gpu_vel_vals.begin()); - /*for(int ii=0;ii gpu_startX) { - amrex::Real xi = (x1 - gpu_startX) / (prob_hi[0] - gpu_startX); - xdamping = gpu_spongeStrength * xi * xi; - } - if (x2 > gpu_startY) { - amrex::Real yi = (x2 - gpu_startY) / (prob_hi[1] - gpu_startY); - ydamping = gpu_spongeStrength * yi * yi; - } - const amrex::Real m = std::sqrt(ux * ux + uy * uy + uz * uz); - amrex::Real Cd = gpu_drag / dx[0]; - amrex::Real gpu_spongeVelX = 0.0; - amrex::Real gpu_spongeVelY = 0.0; - amrex::Real gpu_spongeVelZ = 0.0; - amrex::Real residual = 1000; - amrex::Real height_error = 0.0; - for (int ii = 0; ii < gpu_vel_ht.size(); ++ii) { - height_error = std::abs(x3 - gpu_vel_ht[ii]); - if (height_error < residual) { - residual = height_error; - gpu_spongeVelX = gpu_vel_vals[3 * ii]; - gpu_spongeVelY = gpu_vel_vals[3 * ii + 1]; - gpu_spongeVelZ = gpu_vel_vals[3 * ii + 2]; + const amrex::Real dragCoeff= m_dragCoeff; + const amrex::Real spongeStrength = m_spongeStrength; + const amrex::Real spongeDensity = m_spongeDensity; + const amrex::Real startX = + (1 - m_spongePercentX / 100.0) * prob_hi[0]; + const amrex::Real startY = + (1 - m_spongePercentY / 100.0) * prob_hi[1]; + amrex::ParallelFor( + bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept { + const amrex::Real ux = vel(i, j, k, 0); + const amrex::Real uy = vel(i, j, k, 1); + const amrex::Real uz = vel(i, j, k, 2); + const amrex::Real x1 = prob_lo[0] + (i + 0.5) * dx[0]; + const amrex::Real x2 = prob_lo[1] + (j + 0.5) * dx[1]; + const amrex::Real x3 = prob_lo[2] + (k + 0.5) * dx[2]; + amrex::Real xdamping = 0; + amrex::Real ydamping = 0; + if (x1 > startX) { + amrex::Real xi = + (x1 - startX) / (prob_hi[0] - startX); + xdamping = spongeStrength * xi * xi; } - } - // Terrain Drag - amrex::Real kappa = 0.41; - amrex::Real ustar = - std::sqrt(ux * ux + uy * uy) * kappa / std::log((x3 + 0.1) / 0.1); - amrex::Real Dxz = - -ustar * ustar * ux / (1e-5 + std::sqrt(ux * ux + uy * uy)) / dx[2]; - amrex::Real Dyz = - -ustar * ustar * uy / (1e-5 + std::sqrt(ux * ux + uy * uy)) / dx[2]; - // Adjusting Cd for momentum - amrex::Real CdM = std::min(Cd * 5.0 / (m + 1e-5), 100.0); - src_term(i, j, k, 0) -= - (CdM * m * ux * blank(i, j, k) + Dxz * drag(i, j, k) + - (xdamping + ydamping) * (ux - gpu_spongeDensity * gpu_spongeVelX)); - src_term(i, j, k, 1) -= - (CdM * m * uy * blank(i, j, k) + Dyz * drag(i, j, k) + - (xdamping + ydamping) * (uy - gpu_spongeDensity * gpu_spongeVelY)); - src_term(i, j, k, 2) -= - (CdM * m * uz * blank(i, j, k) + - (xdamping + ydamping) * (uz - gpu_spongeDensity * gpu_spongeVelZ)); - }); + if (x2 > startY) { + amrex::Real yi = + (x2 - startY) / (prob_hi[1] - startY); + ydamping = spongeStrength * yi * yi; + } + const amrex::Real m = std::sqrt(ux * ux + uy * uy + uz * uz); + amrex::Real Cd = dragCoeff / dx[0]; + amrex::Real spongeVelX = 0.0; + amrex::Real spongeVelY = 0.0; + amrex::Real spongeVelZ = 0.0; + amrex::Real residual = 1000; + amrex::Real height_error = 0.0; + for (unsigned long ii = 0; ii < device_vel_ht.size(); ++ii) { + height_error = std::abs(x3 - device_vel_ht[ii]); + if (height_error < residual) { + residual = height_error; + spongeVelX = device_vel_vals[3 * ii]; + spongeVelY = device_vel_vals[3 * ii + 1]; + spongeVelZ = device_vel_vals[3 * ii + 2]; + } + } + // Terrain Drag + amrex::Real kappa = 0.41; + amrex::Real ustar = std::sqrt(ux * ux + uy * uy) * kappa / + std::log((x3 + 0.1) / 0.1); + amrex::Real Dxz = -ustar * ustar * ux / + (1e-5 + std::sqrt(ux * ux + uy * uy)) / dx[2]; + amrex::Real Dyz = -ustar * ustar * uy / + (1e-5 + std::sqrt(ux * ux + uy * uy)) / dx[2]; + // Adjusting Cd for momentum + amrex::Real CdM = std::min(Cd * 5.0 / (m + 1e-5), 100.0); + src_term(i, j, k, 0) -= + (CdM * m * ux * blank(i, j, k) + Dxz * drag(i, j, k) + + (xdamping + ydamping) * + (ux - spongeDensity * spongeVelX)); + src_term(i, j, k, 1) -= + (CdM * m * uy * blank(i, j, k) + Dyz * drag(i, j, k) + + (xdamping + ydamping) * + (uy - spongeDensity * spongeVelY)); + src_term(i, j, k, 2) -= + (CdM * m * uz * blank(i, j, k) + + (xdamping + ydamping) * + (uz - spongeDensity * spongeVelZ)); + }); } -} // namespace amr_wind::pde::icns +} // namespace amr_wind::pde::icns \ No newline at end of file diff --git a/amr-wind/physics/TerrainDrag.cpp b/amr-wind/physics/TerrainDrag.cpp index 45118e0ca7..4d3fc286db 100644 --- a/amr-wind/physics/TerrainDrag.cpp +++ b/amr-wind/physics/TerrainDrag.cpp @@ -37,22 +37,23 @@ void TerrainDrag::initialize_fields(int level, const amrex::Geometry& geom) const auto& dx = geom.CellSizeArray(); const auto& prob_lo = geom.ProbLoArray(); - auto& velocity = m_velocity(level); + const auto& velocity = m_velocity(level); auto& blanking = m_terrainBlank(level); auto& drag = m_terrainDrag(level); - // amrex::Print()<<" Terrain Initial:"< gpu_xterrain(m_xterrain.size()); - amrex::Gpu::DeviceVector gpu_yterrain(m_xterrain.size()); - amrex::Gpu::DeviceVector gpu_zterrain(m_xterrain.size()); - auto* xterrain_ptr = gpu_xterrain.data(); - auto* yterrain_ptr = gpu_yterrain.data(); - auto* zterrain_ptr = gpu_zterrain.data(); - amrex::ParallelFor(m_xterrain.size(), [=] AMREX_GPU_DEVICE(int n) { - xterrain_ptr[n] = m_xterrain[n]; - yterrain_ptr[n] = m_yterrain[n]; - zterrain_ptr[n] = m_zterrain[n]; - }); + amrex::Gpu::DeviceVector device_xterrain(m_xterrain.size()); + amrex::Gpu::DeviceVector device_yterrain(m_xterrain.size()); + amrex::Gpu::DeviceVector device_zterrain(m_xterrain.size()); + amrex::Gpu::copy( + amrex::Gpu::hostToDevice, m_xterrain.begin(), m_xterrain.end(), + device_xterrain.begin()); + amrex::Gpu::copy( + amrex::Gpu::hostToDevice, m_yterrain.begin(), m_yterrain.end(), + device_yterrain.begin()); + amrex::Gpu::copy( + amrex::Gpu::hostToDevice, m_zterrain.begin(), m_zterrain.end(), + device_zterrain.begin()); + for (amrex::MFIter mfi(velocity); mfi.isValid(); ++mfi) { const auto& vbx = mfi.validbox(); auto levelBlanking = blanking.array(mfi); @@ -69,11 +70,11 @@ void TerrainDrag::initialize_fields(int level, const amrex::Geometry& geom) amrex::Real terrainHt = 0.0; for (int ii = 0; ii < terrainSize; ++ii) { const amrex::Real radius = std::sqrt( - std::pow(x1 - xterrain_ptr[ii], 2) + - std::pow(x2 - yterrain_ptr[ii], 2)); + std::pow(x1 - device_xterrain[ii], 2) + + std::pow(x2 - device_yterrain[ii], 2)); if (radius < residual) { residual = radius; - terrainHt = zterrain_ptr[ii]; + terrainHt = device_zterrain[ii]; } } const amrex::Real turnOn = (x3 <= terrainHt) ? 1.0 : 0.0; @@ -89,18 +90,16 @@ void TerrainDrag::initialize_fields(int level, const amrex::Geometry& geom) const amrex::Real x3 = prob_lo[2] + (k + 0.5) * dx[2]; for (int ii = 0; ii < terrainSize; ++ii) { const amrex::Real radius = std::sqrt( - std::pow(x1 - xterrain_ptr[ii], 2) + - std::pow(x2 - yterrain_ptr[ii], 2)); + std::pow(x1 - device_xterrain[ii], 2) + + std::pow(x2 - device_yterrain[ii], 2)); if (radius < residual) { residual = radius; - terrainHt = zterrain_ptr[ii]; + terrainHt = device_zterrain[ii]; } } levelDrag(i, j, k, 0) = 0.0; if (x3 > terrainHt && k > 0 && levelBlanking(i, j, k - 1, 0) == 1) { - // amrex::Print()<<"Adding Drag:"< Date: Mon, 8 Apr 2024 10:51:08 -0600 Subject: [PATCH 04/77] Clang Formatting --- .../icns/source_terms/DragForcing.cpp | 118 ++++++++---------- 1 file changed, 55 insertions(+), 63 deletions(-) diff --git a/amr-wind/equation_systems/icns/source_terms/DragForcing.cpp b/amr-wind/equation_systems/icns/source_terms/DragForcing.cpp index a2c3397049..6120f58e5a 100644 --- a/amr-wind/equation_systems/icns/source_terms/DragForcing.cpp +++ b/amr-wind/equation_systems/icns/source_terms/DragForcing.cpp @@ -46,72 +46,64 @@ void DragForcing::operator()( const auto& dx = geom.CellSizeArray(); const auto& prob_lo = geom.ProbLoArray(); const auto& prob_hi = geom.ProbHiArray(); - const amrex::Real dragCoeff= m_dragCoeff; + const amrex::Real dragCoeff = m_dragCoeff; const amrex::Real spongeStrength = m_spongeStrength; const amrex::Real spongeDensity = m_spongeDensity; - const amrex::Real startX = - (1 - m_spongePercentX / 100.0) * prob_hi[0]; - const amrex::Real startY = - (1 - m_spongePercentY / 100.0) * prob_hi[1]; - amrex::ParallelFor( - bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept { - const amrex::Real ux = vel(i, j, k, 0); - const amrex::Real uy = vel(i, j, k, 1); - const amrex::Real uz = vel(i, j, k, 2); - const amrex::Real x1 = prob_lo[0] + (i + 0.5) * dx[0]; - const amrex::Real x2 = prob_lo[1] + (j + 0.5) * dx[1]; - const amrex::Real x3 = prob_lo[2] + (k + 0.5) * dx[2]; - amrex::Real xdamping = 0; - amrex::Real ydamping = 0; - if (x1 > startX) { - amrex::Real xi = - (x1 - startX) / (prob_hi[0] - startX); - xdamping = spongeStrength * xi * xi; + const amrex::Real startX = (1 - m_spongePercentX / 100.0) * prob_hi[0]; + const amrex::Real startY = (1 - m_spongePercentY / 100.0) * prob_hi[1]; + amrex::ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept { + const amrex::Real ux = vel(i, j, k, 0); + const amrex::Real uy = vel(i, j, k, 1); + const amrex::Real uz = vel(i, j, k, 2); + const amrex::Real x1 = prob_lo[0] + (i + 0.5) * dx[0]; + const amrex::Real x2 = prob_lo[1] + (j + 0.5) * dx[1]; + const amrex::Real x3 = prob_lo[2] + (k + 0.5) * dx[2]; + amrex::Real xdamping = 0; + amrex::Real ydamping = 0; + if (x1 > startX) { + amrex::Real xi = (x1 - startX) / (prob_hi[0] - startX); + xdamping = spongeStrength * xi * xi; + } + if (x2 > startY) { + amrex::Real yi = (x2 - startY) / (prob_hi[1] - startY); + ydamping = spongeStrength * yi * yi; + } + const amrex::Real m = std::sqrt(ux * ux + uy * uy + uz * uz); + amrex::Real Cd = dragCoeff / dx[0]; + amrex::Real spongeVelX = 0.0; + amrex::Real spongeVelY = 0.0; + amrex::Real spongeVelZ = 0.0; + amrex::Real residual = 1000; + amrex::Real height_error = 0.0; + for (unsigned long ii = 0; ii < device_vel_ht.size(); ++ii) { + height_error = std::abs(x3 - device_vel_ht[ii]); + if (height_error < residual) { + residual = height_error; + spongeVelX = device_vel_vals[3 * ii]; + spongeVelY = device_vel_vals[3 * ii + 1]; + spongeVelZ = device_vel_vals[3 * ii + 2]; } - if (x2 > startY) { - amrex::Real yi = - (x2 - startY) / (prob_hi[1] - startY); - ydamping = spongeStrength * yi * yi; - } - const amrex::Real m = std::sqrt(ux * ux + uy * uy + uz * uz); - amrex::Real Cd = dragCoeff / dx[0]; - amrex::Real spongeVelX = 0.0; - amrex::Real spongeVelY = 0.0; - amrex::Real spongeVelZ = 0.0; - amrex::Real residual = 1000; - amrex::Real height_error = 0.0; - for (unsigned long ii = 0; ii < device_vel_ht.size(); ++ii) { - height_error = std::abs(x3 - device_vel_ht[ii]); - if (height_error < residual) { - residual = height_error; - spongeVelX = device_vel_vals[3 * ii]; - spongeVelY = device_vel_vals[3 * ii + 1]; - spongeVelZ = device_vel_vals[3 * ii + 2]; - } - } - // Terrain Drag - amrex::Real kappa = 0.41; - amrex::Real ustar = std::sqrt(ux * ux + uy * uy) * kappa / - std::log((x3 + 0.1) / 0.1); - amrex::Real Dxz = -ustar * ustar * ux / - (1e-5 + std::sqrt(ux * ux + uy * uy)) / dx[2]; - amrex::Real Dyz = -ustar * ustar * uy / - (1e-5 + std::sqrt(ux * ux + uy * uy)) / dx[2]; - // Adjusting Cd for momentum - amrex::Real CdM = std::min(Cd * 5.0 / (m + 1e-5), 100.0); - src_term(i, j, k, 0) -= - (CdM * m * ux * blank(i, j, k) + Dxz * drag(i, j, k) + - (xdamping + ydamping) * - (ux - spongeDensity * spongeVelX)); - src_term(i, j, k, 1) -= - (CdM * m * uy * blank(i, j, k) + Dyz * drag(i, j, k) + - (xdamping + ydamping) * - (uy - spongeDensity * spongeVelY)); - src_term(i, j, k, 2) -= - (CdM * m * uz * blank(i, j, k) + - (xdamping + ydamping) * - (uz - spongeDensity * spongeVelZ)); - }); + } + // Terrain Drag + amrex::Real kappa = 0.41; + amrex::Real ustar = + std::sqrt(ux * ux + uy * uy) * kappa / std::log((x3 + 0.1) / 0.1); + amrex::Real Dxz = + -ustar * ustar * ux / (1e-5 + std::sqrt(ux * ux + uy * uy)) / dx[2]; + amrex::Real Dyz = + -ustar * ustar * uy / (1e-5 + std::sqrt(ux * ux + uy * uy)) / dx[2]; + // Adjusting Cd for momentum + amrex::Real CdM = std::min(Cd * 5.0 / (m + 1e-5), 100.0); + src_term(i, j, k, 0) -= + (CdM * m * ux * blank(i, j, k) + Dxz * drag(i, j, k) + + (xdamping + ydamping) * (ux - spongeDensity * spongeVelX)); + src_term(i, j, k, 1) -= + (CdM * m * uy * blank(i, j, k) + Dyz * drag(i, j, k) + + (xdamping + ydamping) * (uy - spongeDensity * spongeVelY)); + src_term(i, j, k, 2) -= + (CdM * m * uz * blank(i, j, k) + + (xdamping + ydamping) * (uz - spongeDensity * spongeVelZ)); + }); } } // namespace amr_wind::pde::icns \ No newline at end of file From 77978473c1c4b9a2b6fd52d5030c55c2b7c5e656 Mon Sep 17 00:00:00 2001 From: hgopalan Date: Mon, 8 Apr 2024 11:10:43 -0600 Subject: [PATCH 05/77] GPU Compatibility --- .../icns/source_terms/DragForcing.H | 4 ++-- .../icns/source_terms/DragForcing.cpp | 17 +++++++++++++++-- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/amr-wind/equation_systems/icns/source_terms/DragForcing.H b/amr-wind/equation_systems/icns/source_terms/DragForcing.H index ba100b81a0..4a16650d30 100644 --- a/amr-wind/equation_systems/icns/source_terms/DragForcing.H +++ b/amr-wind/equation_systems/icns/source_terms/DragForcing.H @@ -35,8 +35,8 @@ private: const Field& m_velocity; Field& m_terrainBlank; Field& m_terrainDrag; - amrex::Gpu::DeviceVector device_vel_ht; - amrex::Gpu::DeviceVector device_vel_vals; + //amrex::Gpu::DeviceVector device_vel_ht; + //amrex::Gpu::DeviceVector device_vel_vals; amrex::Real m_dragCoeff{8.0}; amrex::Real m_spongeStrength{1.0}; amrex::Real m_spongeDensity{1.0}; diff --git a/amr-wind/equation_systems/icns/source_terms/DragForcing.cpp b/amr-wind/equation_systems/icns/source_terms/DragForcing.cpp index 6120f58e5a..51815698a7 100644 --- a/amr-wind/equation_systems/icns/source_terms/DragForcing.cpp +++ b/amr-wind/equation_systems/icns/source_terms/DragForcing.cpp @@ -15,7 +15,7 @@ DragForcing::DragForcing(const CFDSim& sim) , m_terrainDrag(sim.repo().get_field("terrainDrag")) { - const auto& abl = m_sim.physics_manager().get(); + /*const auto& abl = m_sim.physics_manager().get(); const VelPlaneAveraging& fa_velocity = abl.abl_statistics().vel_profile_coarse(); device_vel_ht.resize(fa_velocity.line_centroids().size()); @@ -25,7 +25,7 @@ DragForcing::DragForcing(const CFDSim& sim) fa_velocity.line_centroids().end(), device_vel_ht.begin()); amrex::Gpu::copy( amrex::Gpu::hostToDevice, fa_velocity.line_average().begin(), - fa_velocity.line_average().end(), device_vel_vals.begin()); + fa_velocity.line_average().end(), device_vel_vals.begin()); */ } DragForcing::~DragForcing() = default; @@ -51,6 +51,19 @@ void DragForcing::operator()( const amrex::Real spongeDensity = m_spongeDensity; const amrex::Real startX = (1 - m_spongePercentX / 100.0) * prob_hi[0]; const amrex::Real startY = (1 - m_spongePercentY / 100.0) * prob_hi[1]; + amrex::Gpu::DeviceVector device_vel_ht; + amrex::Gpu::DeviceVector device_vel_vals; + const auto& abl = m_sim.physics_manager().get(); + const VelPlaneAveraging& fa_velocity = + abl.abl_statistics().vel_profile_coarse(); + device_vel_ht.resize(fa_velocity.line_centroids().size()); + device_vel_vals.resize(fa_velocity.line_average().size()); + amrex::Gpu::copy( + amrex::Gpu::hostToDevice, fa_velocity.line_centroids().begin(), + fa_velocity.line_centroids().end(), device_vel_ht.begin()); + amrex::Gpu::copy( + amrex::Gpu::hostToDevice, fa_velocity.line_average().begin(), + fa_velocity.line_average().end(), device_vel_vals.begin()); amrex::ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept { const amrex::Real ux = vel(i, j, k, 0); const amrex::Real uy = vel(i, j, k, 1); From c3ad937a782ff16556e638ff8cca021abf7ddea6 Mon Sep 17 00:00:00 2001 From: hgopalan Date: Mon, 8 Apr 2024 11:13:03 -0600 Subject: [PATCH 06/77] Clang format --- amr-wind/equation_systems/icns/source_terms/DragForcing.H | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/amr-wind/equation_systems/icns/source_terms/DragForcing.H b/amr-wind/equation_systems/icns/source_terms/DragForcing.H index 4a16650d30..aabc594178 100644 --- a/amr-wind/equation_systems/icns/source_terms/DragForcing.H +++ b/amr-wind/equation_systems/icns/source_terms/DragForcing.H @@ -35,8 +35,8 @@ private: const Field& m_velocity; Field& m_terrainBlank; Field& m_terrainDrag; - //amrex::Gpu::DeviceVector device_vel_ht; - //amrex::Gpu::DeviceVector device_vel_vals; + // amrex::Gpu::DeviceVector device_vel_ht; + // amrex::Gpu::DeviceVector device_vel_vals; amrex::Real m_dragCoeff{8.0}; amrex::Real m_spongeStrength{1.0}; amrex::Real m_spongeDensity{1.0}; From bd87c4809ecfe9f605ff81338fa9c73392bb35e4 Mon Sep 17 00:00:00 2001 From: hgopalan Date: Mon, 8 Apr 2024 13:44:05 -0600 Subject: [PATCH 07/77] Code update for GPU compatibility --- .../icns/source_terms/DragForcing.H | 4 +- .../icns/source_terms/DragForcing.cpp | 17 +------ amr-wind/physics/TerrainDrag.H | 18 +++++++ amr-wind/physics/TerrainDrag.cpp | 48 ++++++++++--------- 4 files changed, 47 insertions(+), 40 deletions(-) diff --git a/amr-wind/equation_systems/icns/source_terms/DragForcing.H b/amr-wind/equation_systems/icns/source_terms/DragForcing.H index aabc594178..ba100b81a0 100644 --- a/amr-wind/equation_systems/icns/source_terms/DragForcing.H +++ b/amr-wind/equation_systems/icns/source_terms/DragForcing.H @@ -35,8 +35,8 @@ private: const Field& m_velocity; Field& m_terrainBlank; Field& m_terrainDrag; - // amrex::Gpu::DeviceVector device_vel_ht; - // amrex::Gpu::DeviceVector device_vel_vals; + amrex::Gpu::DeviceVector device_vel_ht; + amrex::Gpu::DeviceVector device_vel_vals; amrex::Real m_dragCoeff{8.0}; amrex::Real m_spongeStrength{1.0}; amrex::Real m_spongeDensity{1.0}; diff --git a/amr-wind/equation_systems/icns/source_terms/DragForcing.cpp b/amr-wind/equation_systems/icns/source_terms/DragForcing.cpp index 51815698a7..8d33e8c7d4 100644 --- a/amr-wind/equation_systems/icns/source_terms/DragForcing.cpp +++ b/amr-wind/equation_systems/icns/source_terms/DragForcing.cpp @@ -15,7 +15,7 @@ DragForcing::DragForcing(const CFDSim& sim) , m_terrainDrag(sim.repo().get_field("terrainDrag")) { - /*const auto& abl = m_sim.physics_manager().get(); + const auto& abl = m_sim.physics_manager().get(); const VelPlaneAveraging& fa_velocity = abl.abl_statistics().vel_profile_coarse(); device_vel_ht.resize(fa_velocity.line_centroids().size()); @@ -25,7 +25,7 @@ DragForcing::DragForcing(const CFDSim& sim) fa_velocity.line_centroids().end(), device_vel_ht.begin()); amrex::Gpu::copy( amrex::Gpu::hostToDevice, fa_velocity.line_average().begin(), - fa_velocity.line_average().end(), device_vel_vals.begin()); */ + fa_velocity.line_average().end(), device_vel_vals.begin()); } DragForcing::~DragForcing() = default; @@ -51,19 +51,6 @@ void DragForcing::operator()( const amrex::Real spongeDensity = m_spongeDensity; const amrex::Real startX = (1 - m_spongePercentX / 100.0) * prob_hi[0]; const amrex::Real startY = (1 - m_spongePercentY / 100.0) * prob_hi[1]; - amrex::Gpu::DeviceVector device_vel_ht; - amrex::Gpu::DeviceVector device_vel_vals; - const auto& abl = m_sim.physics_manager().get(); - const VelPlaneAveraging& fa_velocity = - abl.abl_statistics().vel_profile_coarse(); - device_vel_ht.resize(fa_velocity.line_centroids().size()); - device_vel_vals.resize(fa_velocity.line_average().size()); - amrex::Gpu::copy( - amrex::Gpu::hostToDevice, fa_velocity.line_centroids().begin(), - fa_velocity.line_centroids().end(), device_vel_ht.begin()); - amrex::Gpu::copy( - amrex::Gpu::hostToDevice, fa_velocity.line_average().begin(), - fa_velocity.line_average().end(), device_vel_vals.begin()); amrex::ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept { const amrex::Real ux = vel(i, j, k, 0); const amrex::Real uy = vel(i, j, k, 1); diff --git a/amr-wind/physics/TerrainDrag.H b/amr-wind/physics/TerrainDrag.H index 345db18ee6..38481b213f 100644 --- a/amr-wind/physics/TerrainDrag.H +++ b/amr-wind/physics/TerrainDrag.H @@ -46,6 +46,24 @@ private: // Reading the Terrain Coordinates from file amrex::Vector m_xterrain, m_yterrain, m_zterrain; }; + +AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real find_terrain_height( + const int terrainSize,const amrex::Real x1, const amrex::Real x2, amrex::Gpu::DeviceVector device_xterrain, + amrex::Gpu::DeviceVector device_yterrain,amrex::Gpu::DeviceVector device_zterrain) +{ + amrex::Real terrainHt=0; + amrex::Real residual=300000; + for (int ii = 0; ii < terrainSize; ++ii) { + const amrex::Real radius = std::sqrt( + std::pow(x1 - device_xterrain[ii], 2) + + std::pow(x2 - device_yterrain[ii], 2)); + if (radius < residual) { + residual = radius; + terrainHt = device_zterrain[ii]; + } + } + return terrainHt; +} } // namespace amr_wind::terraindrag #endif diff --git a/amr-wind/physics/TerrainDrag.cpp b/amr-wind/physics/TerrainDrag.cpp index 4d3fc286db..787df242ce 100644 --- a/amr-wind/physics/TerrainDrag.cpp +++ b/amr-wind/physics/TerrainDrag.cpp @@ -58,7 +58,7 @@ void TerrainDrag::initialize_fields(int level, const amrex::Geometry& geom) const auto& vbx = mfi.validbox(); auto levelBlanking = blanking.array(mfi); auto levelDrag = drag.array(mfi); - const amrex::Real terrainSize = m_xterrain.size(); + const int terrainSize=m_xterrain.size(); amrex::ParallelFor( vbx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept { // compute the source term @@ -66,37 +66,38 @@ void TerrainDrag::initialize_fields(int level, const amrex::Geometry& geom) const amrex::Real x2 = prob_lo[1] + (j + 0.5) * dx[1]; const amrex::Real x3 = prob_lo[2] + (k + 0.5) * dx[2]; // Terrain Height - amrex::Real residual = 10000; - amrex::Real terrainHt = 0.0; - for (int ii = 0; ii < terrainSize; ++ii) { - const amrex::Real radius = std::sqrt( - std::pow(x1 - device_xterrain[ii], 2) + - std::pow(x2 - device_yterrain[ii], 2)); - if (radius < residual) { - residual = radius; - terrainHt = device_zterrain[ii]; - } - } + //amrex::Real residual = 10000; + amrex::Real terrainHt = find_terrain_height(terrainSize,x1,x2,device_xterrain,device_yterrain,device_zterrain); + // for (int ii = 0; ii < terrainSize; ++ii) { + // const amrex::Real radius = std::sqrt( + // std::pow(x1 - device_xterrain[ii], 2) + + // std::pow(x2 - device_yterrain[ii], 2)); + // if (radius < residual) { + // residual = radius; + // terrainHt = device_zterrain[ii]; + // } + // } const amrex::Real turnOn = (x3 <= terrainHt) ? 1.0 : 0.0; levelBlanking(i, j, k, 0) = turnOn; }); amrex::ParallelFor( vbx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept { // Terrain Height - amrex::Real residual = 10000; - amrex::Real terrainHt = 0.0; + //amrex::Real residual = 10000; + //amrex::Real terrainHt = 0.0; const amrex::Real x1 = prob_lo[0] + (i + 0.5) * dx[0]; const amrex::Real x2 = prob_lo[1] + (j + 0.5) * dx[1]; const amrex::Real x3 = prob_lo[2] + (k + 0.5) * dx[2]; - for (int ii = 0; ii < terrainSize; ++ii) { - const amrex::Real radius = std::sqrt( - std::pow(x1 - device_xterrain[ii], 2) + - std::pow(x2 - device_yterrain[ii], 2)); - if (radius < residual) { - residual = radius; - terrainHt = device_zterrain[ii]; - } - } + // for (int ii = 0; ii < terrainSize; ++ii) { + // const amrex::Real radius = std::sqrt( + // std::pow(x1 - device_xterrain[ii], 2) + + // std::pow(x2 - device_yterrain[ii], 2)); + // if (radius < residual) { + // residual = radius; + // terrainHt = device_zterrain[ii]; + // } + // } + amrex::Real terrainHt = find_terrain_height(terrainSize,x1,x2,device_xterrain,device_yterrain,device_zterrain); levelDrag(i, j, k, 0) = 0.0; if (x3 > terrainHt && k > 0 && levelBlanking(i, j, k - 1, 0) == 1) { @@ -106,4 +107,5 @@ void TerrainDrag::initialize_fields(int level, const amrex::Geometry& geom) } } + } // namespace amr_wind::terraindrag From 25ffb13b80bda8e9164096c256cd3eb114e8cfa9 Mon Sep 17 00:00:00 2001 From: hgopalan Date: Mon, 8 Apr 2024 13:46:09 -0600 Subject: [PATCH 08/77] Update for Clang Format --- .../icns/source_terms/DragForcing.cpp | 2 +- amr-wind/physics/TerrainDrag.H | 12 ++++++++---- amr-wind/physics/TerrainDrag.cpp | 17 ++++++++++------- 3 files changed, 19 insertions(+), 12 deletions(-) diff --git a/amr-wind/equation_systems/icns/source_terms/DragForcing.cpp b/amr-wind/equation_systems/icns/source_terms/DragForcing.cpp index 8d33e8c7d4..6120f58e5a 100644 --- a/amr-wind/equation_systems/icns/source_terms/DragForcing.cpp +++ b/amr-wind/equation_systems/icns/source_terms/DragForcing.cpp @@ -25,7 +25,7 @@ DragForcing::DragForcing(const CFDSim& sim) fa_velocity.line_centroids().end(), device_vel_ht.begin()); amrex::Gpu::copy( amrex::Gpu::hostToDevice, fa_velocity.line_average().begin(), - fa_velocity.line_average().end(), device_vel_vals.begin()); + fa_velocity.line_average().end(), device_vel_vals.begin()); } DragForcing::~DragForcing() = default; diff --git a/amr-wind/physics/TerrainDrag.H b/amr-wind/physics/TerrainDrag.H index 38481b213f..4b10adb838 100644 --- a/amr-wind/physics/TerrainDrag.H +++ b/amr-wind/physics/TerrainDrag.H @@ -48,11 +48,15 @@ private: }; AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real find_terrain_height( - const int terrainSize,const amrex::Real x1, const amrex::Real x2, amrex::Gpu::DeviceVector device_xterrain, - amrex::Gpu::DeviceVector device_yterrain,amrex::Gpu::DeviceVector device_zterrain) + const int terrainSize, + const amrex::Real x1, + const amrex::Real x2, + amrex::Gpu::DeviceVector device_xterrain, + amrex::Gpu::DeviceVector device_yterrain, + amrex::Gpu::DeviceVector device_zterrain) { - amrex::Real terrainHt=0; - amrex::Real residual=300000; + amrex::Real terrainHt = 0; + amrex::Real residual = 300000; for (int ii = 0; ii < terrainSize; ++ii) { const amrex::Real radius = std::sqrt( std::pow(x1 - device_xterrain[ii], 2) + diff --git a/amr-wind/physics/TerrainDrag.cpp b/amr-wind/physics/TerrainDrag.cpp index 787df242ce..5c390c518a 100644 --- a/amr-wind/physics/TerrainDrag.cpp +++ b/amr-wind/physics/TerrainDrag.cpp @@ -58,7 +58,7 @@ void TerrainDrag::initialize_fields(int level, const amrex::Geometry& geom) const auto& vbx = mfi.validbox(); auto levelBlanking = blanking.array(mfi); auto levelDrag = drag.array(mfi); - const int terrainSize=m_xterrain.size(); + const int terrainSize = m_xterrain.size(); amrex::ParallelFor( vbx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept { // compute the source term @@ -66,8 +66,10 @@ void TerrainDrag::initialize_fields(int level, const amrex::Geometry& geom) const amrex::Real x2 = prob_lo[1] + (j + 0.5) * dx[1]; const amrex::Real x3 = prob_lo[2] + (k + 0.5) * dx[2]; // Terrain Height - //amrex::Real residual = 10000; - amrex::Real terrainHt = find_terrain_height(terrainSize,x1,x2,device_xterrain,device_yterrain,device_zterrain); + // amrex::Real residual = 10000; + amrex::Real terrainHt = find_terrain_height( + terrainSize, x1, x2, device_xterrain, device_yterrain, + device_zterrain); // for (int ii = 0; ii < terrainSize; ++ii) { // const amrex::Real radius = std::sqrt( // std::pow(x1 - device_xterrain[ii], 2) + @@ -83,8 +85,8 @@ void TerrainDrag::initialize_fields(int level, const amrex::Geometry& geom) amrex::ParallelFor( vbx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept { // Terrain Height - //amrex::Real residual = 10000; - //amrex::Real terrainHt = 0.0; + // amrex::Real residual = 10000; + // amrex::Real terrainHt = 0.0; const amrex::Real x1 = prob_lo[0] + (i + 0.5) * dx[0]; const amrex::Real x2 = prob_lo[1] + (j + 0.5) * dx[1]; const amrex::Real x3 = prob_lo[2] + (k + 0.5) * dx[2]; @@ -97,7 +99,9 @@ void TerrainDrag::initialize_fields(int level, const amrex::Geometry& geom) // terrainHt = device_zterrain[ii]; // } // } - amrex::Real terrainHt = find_terrain_height(terrainSize,x1,x2,device_xterrain,device_yterrain,device_zterrain); + amrex::Real terrainHt = find_terrain_height( + terrainSize, x1, x2, device_xterrain, device_yterrain, + device_zterrain); levelDrag(i, j, k, 0) = 0.0; if (x3 > terrainHt && k > 0 && levelBlanking(i, j, k - 1, 0) == 1) { @@ -107,5 +111,4 @@ void TerrainDrag::initialize_fields(int level, const amrex::Geometry& geom) } } - } // namespace amr_wind::terraindrag From 1b1b61245f2e188d64d89e7d61eab495696dee4c Mon Sep 17 00:00:00 2001 From: hgopalan Date: Mon, 8 Apr 2024 14:23:19 -0600 Subject: [PATCH 09/77] GPU compatiblity for Drag Force --- .../icns/source_terms/DragForcing.H | 25 +++++++++++++++++++ .../icns/source_terms/DragForcing.cpp | 25 ++++++------------- amr-wind/physics/TerrainDrag.H | 2 -- amr-wind/physics/TerrainDrag.cpp | 24 ------------------ 4 files changed, 33 insertions(+), 43 deletions(-) diff --git a/amr-wind/equation_systems/icns/source_terms/DragForcing.H b/amr-wind/equation_systems/icns/source_terms/DragForcing.H index ba100b81a0..bbaef03fde 100644 --- a/amr-wind/equation_systems/icns/source_terms/DragForcing.H +++ b/amr-wind/equation_systems/icns/source_terms/DragForcing.H @@ -44,6 +44,31 @@ private: amrex::Real m_spongePercentY{20}; }; +AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Vector +findRefVelocity( + const int verticalSize, + const amrex::Real x3, + amrex::Gpu::DeviceVector vel_ht, + amrex::Gpu::DeviceVector vel_vals) +{ + amrex::Real spongeVelX = 0.0; + amrex::Real spongeVelY = 0.0; + amrex::Real spongeVelZ = 0.0; + amrex::Real residual = 1000; + amrex::Real height_error = 0.0; + for (int ii = 0; ii < verticalSize; ++ii) { + height_error = std::abs(x3 - vel_ht[ii]); + if (height_error < residual) { + residual = height_error; + spongeVelX = vel_vals[3 * ii]; + spongeVelY = vel_vals[3 * ii + 1]; + spongeVelZ = vel_vals[3 * ii + 2]; + } + } + amrex::Vector wind({spongeVelX, spongeVelY, spongeVelZ}); + return wind; +} + } // namespace amr_wind::pde::icns #endif /* DRAGFORCING_H */ diff --git a/amr-wind/equation_systems/icns/source_terms/DragForcing.cpp b/amr-wind/equation_systems/icns/source_terms/DragForcing.cpp index 6120f58e5a..b5af8fd131 100644 --- a/amr-wind/equation_systems/icns/source_terms/DragForcing.cpp +++ b/amr-wind/equation_systems/icns/source_terms/DragForcing.cpp @@ -51,6 +51,9 @@ void DragForcing::operator()( const amrex::Real spongeDensity = m_spongeDensity; const amrex::Real startX = (1 - m_spongePercentX / 100.0) * prob_hi[0]; const amrex::Real startY = (1 - m_spongePercentY / 100.0) * prob_hi[1]; + amrex::Gpu::DeviceVector vel_ht = device_vel_ht; + amrex::Gpu::DeviceVector vel_vals = device_vel_vals; + const int verticalSize = vel_ht.size(); amrex::ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept { const amrex::Real ux = vel(i, j, k, 0); const amrex::Real uy = vel(i, j, k, 1); @@ -70,20 +73,8 @@ void DragForcing::operator()( } const amrex::Real m = std::sqrt(ux * ux + uy * uy + uz * uz); amrex::Real Cd = dragCoeff / dx[0]; - amrex::Real spongeVelX = 0.0; - amrex::Real spongeVelY = 0.0; - amrex::Real spongeVelZ = 0.0; - amrex::Real residual = 1000; - amrex::Real height_error = 0.0; - for (unsigned long ii = 0; ii < device_vel_ht.size(); ++ii) { - height_error = std::abs(x3 - device_vel_ht[ii]); - if (height_error < residual) { - residual = height_error; - spongeVelX = device_vel_vals[3 * ii]; - spongeVelY = device_vel_vals[3 * ii + 1]; - spongeVelZ = device_vel_vals[3 * ii + 2]; - } - } + amrex::Vector wind = + findRefVelocity(verticalSize, x3, vel_ht, vel_vals); // Terrain Drag amrex::Real kappa = 0.41; amrex::Real ustar = @@ -96,13 +87,13 @@ void DragForcing::operator()( amrex::Real CdM = std::min(Cd * 5.0 / (m + 1e-5), 100.0); src_term(i, j, k, 0) -= (CdM * m * ux * blank(i, j, k) + Dxz * drag(i, j, k) + - (xdamping + ydamping) * (ux - spongeDensity * spongeVelX)); + (xdamping + ydamping) * (ux - spongeDensity * wind[0])); src_term(i, j, k, 1) -= (CdM * m * uy * blank(i, j, k) + Dyz * drag(i, j, k) + - (xdamping + ydamping) * (uy - spongeDensity * spongeVelY)); + (xdamping + ydamping) * (uy - spongeDensity * wind[1])); src_term(i, j, k, 2) -= (CdM * m * uz * blank(i, j, k) + - (xdamping + ydamping) * (uz - spongeDensity * spongeVelZ)); + (xdamping + ydamping) * (uz - spongeDensity * wind[2])); }); } diff --git a/amr-wind/physics/TerrainDrag.H b/amr-wind/physics/TerrainDrag.H index 4b10adb838..5d4bd88775 100644 --- a/amr-wind/physics/TerrainDrag.H +++ b/amr-wind/physics/TerrainDrag.H @@ -32,8 +32,6 @@ public: void post_advance_work() override {} - // amrex::Real computeTerrainHeight(const amrex::Real x1,const - // amrex::Real x2) const; private: CFDSim& m_sim; const FieldRepo& m_repo; diff --git a/amr-wind/physics/TerrainDrag.cpp b/amr-wind/physics/TerrainDrag.cpp index 5c390c518a..28b0206035 100644 --- a/amr-wind/physics/TerrainDrag.cpp +++ b/amr-wind/physics/TerrainDrag.cpp @@ -61,44 +61,20 @@ void TerrainDrag::initialize_fields(int level, const amrex::Geometry& geom) const int terrainSize = m_xterrain.size(); amrex::ParallelFor( vbx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept { - // compute the source term const amrex::Real x1 = prob_lo[0] + (i + 0.5) * dx[0]; const amrex::Real x2 = prob_lo[1] + (j + 0.5) * dx[1]; const amrex::Real x3 = prob_lo[2] + (k + 0.5) * dx[2]; - // Terrain Height - // amrex::Real residual = 10000; amrex::Real terrainHt = find_terrain_height( terrainSize, x1, x2, device_xterrain, device_yterrain, device_zterrain); - // for (int ii = 0; ii < terrainSize; ++ii) { - // const amrex::Real radius = std::sqrt( - // std::pow(x1 - device_xterrain[ii], 2) + - // std::pow(x2 - device_yterrain[ii], 2)); - // if (radius < residual) { - // residual = radius; - // terrainHt = device_zterrain[ii]; - // } - // } const amrex::Real turnOn = (x3 <= terrainHt) ? 1.0 : 0.0; levelBlanking(i, j, k, 0) = turnOn; }); amrex::ParallelFor( vbx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept { - // Terrain Height - // amrex::Real residual = 10000; - // amrex::Real terrainHt = 0.0; const amrex::Real x1 = prob_lo[0] + (i + 0.5) * dx[0]; const amrex::Real x2 = prob_lo[1] + (j + 0.5) * dx[1]; const amrex::Real x3 = prob_lo[2] + (k + 0.5) * dx[2]; - // for (int ii = 0; ii < terrainSize; ++ii) { - // const amrex::Real radius = std::sqrt( - // std::pow(x1 - device_xterrain[ii], 2) + - // std::pow(x2 - device_yterrain[ii], 2)); - // if (radius < residual) { - // residual = radius; - // terrainHt = device_zterrain[ii]; - // } - // } amrex::Real terrainHt = find_terrain_height( terrainSize, x1, x2, device_xterrain, device_yterrain, device_zterrain); From b735987905425fe6cc6e2a5c1d37719035e2a5c2 Mon Sep 17 00:00:00 2001 From: hgopalan Date: Mon, 8 Apr 2024 14:41:33 -0600 Subject: [PATCH 10/77] GPU Compatbility for Vertical Location --- .../equation_systems/icns/source_terms/DragForcing.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/amr-wind/equation_systems/icns/source_terms/DragForcing.cpp b/amr-wind/equation_systems/icns/source_terms/DragForcing.cpp index b5af8fd131..9fc27c12c7 100644 --- a/amr-wind/equation_systems/icns/source_terms/DragForcing.cpp +++ b/amr-wind/equation_systems/icns/source_terms/DragForcing.cpp @@ -51,9 +51,7 @@ void DragForcing::operator()( const amrex::Real spongeDensity = m_spongeDensity; const amrex::Real startX = (1 - m_spongePercentX / 100.0) * prob_hi[0]; const amrex::Real startY = (1 - m_spongePercentY / 100.0) * prob_hi[1]; - amrex::Gpu::DeviceVector vel_ht = device_vel_ht; - amrex::Gpu::DeviceVector vel_vals = device_vel_vals; - const int verticalSize = vel_ht.size(); + const int verticalSize = device_vel_ht.size(); amrex::ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept { const amrex::Real ux = vel(i, j, k, 0); const amrex::Real uy = vel(i, j, k, 1); @@ -73,8 +71,9 @@ void DragForcing::operator()( } const amrex::Real m = std::sqrt(ux * ux + uy * uy + uz * uz); amrex::Real Cd = dragCoeff / dx[0]; - amrex::Vector wind = - findRefVelocity(verticalSize, x3, vel_ht, vel_vals); + amrex::Vector wind(3, 0); + wind = + findRefVelocity(verticalSize, x3, device_vel_ht, device_vel_vals); // Terrain Drag amrex::Real kappa = 0.41; amrex::Real ustar = From 7fca03d762478b910b792083b09face0634b3097 Mon Sep 17 00:00:00 2001 From: hgopalan Date: Mon, 8 Apr 2024 15:02:24 -0600 Subject: [PATCH 11/77] GPU compatibility --- amr-wind/equation_systems/icns/source_terms/DragForcing.H | 2 +- amr-wind/equation_systems/icns/source_terms/DragForcing.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/amr-wind/equation_systems/icns/source_terms/DragForcing.H b/amr-wind/equation_systems/icns/source_terms/DragForcing.H index bbaef03fde..89c27f3137 100644 --- a/amr-wind/equation_systems/icns/source_terms/DragForcing.H +++ b/amr-wind/equation_systems/icns/source_terms/DragForcing.H @@ -65,7 +65,7 @@ findRefVelocity( spongeVelZ = vel_vals[3 * ii + 2]; } } - amrex::Vector wind({spongeVelX, spongeVelY, spongeVelZ}); + amrex::Vector wind{{spongeVelX, spongeVelY, spongeVelZ}}; return wind; } diff --git a/amr-wind/equation_systems/icns/source_terms/DragForcing.cpp b/amr-wind/equation_systems/icns/source_terms/DragForcing.cpp index 9fc27c12c7..121ebaeadc 100644 --- a/amr-wind/equation_systems/icns/source_terms/DragForcing.cpp +++ b/amr-wind/equation_systems/icns/source_terms/DragForcing.cpp @@ -71,7 +71,7 @@ void DragForcing::operator()( } const amrex::Real m = std::sqrt(ux * ux + uy * uy + uz * uz); amrex::Real Cd = dragCoeff / dx[0]; - amrex::Vector wind(3, 0); + amrex::Vector wind{{ux, uy, uz}}; wind = findRefVelocity(verticalSize, x3, device_vel_ht, device_vel_vals); // Terrain Drag From 903ae8e962d60c81fee7ddd3d368c50c7fa909ac Mon Sep 17 00:00:00 2001 From: hgopalan Date: Mon, 8 Apr 2024 16:42:20 -0600 Subject: [PATCH 12/77] GPU Compatible Local Copy --- .../equation_systems/icns/source_terms/DragForcing.H | 5 +++-- .../icns/source_terms/DragForcing.cpp | 12 +++++++++++- amr-wind/physics/TerrainDrag.H | 4 ++-- amr-wind/physics/TerrainDrag.cpp | 2 +- 4 files changed, 17 insertions(+), 6 deletions(-) diff --git a/amr-wind/equation_systems/icns/source_terms/DragForcing.H b/amr-wind/equation_systems/icns/source_terms/DragForcing.H index 89c27f3137..808a45817c 100644 --- a/amr-wind/equation_systems/icns/source_terms/DragForcing.H +++ b/amr-wind/equation_systems/icns/source_terms/DragForcing.H @@ -2,6 +2,7 @@ #define DRAGFORCING_H #include "amr-wind/equation_systems/icns/MomentumSource.H" +#include "amr-wind/utilities/FieldPlaneAveraging.H" #include "amr-wind/core/SimTime.H" #include "amr-wind/CFDSim.H" @@ -46,7 +47,7 @@ private: AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Vector findRefVelocity( - const int verticalSize, + unsigned long verticalSize, const amrex::Real x3, amrex::Gpu::DeviceVector vel_ht, amrex::Gpu::DeviceVector vel_vals) @@ -56,7 +57,7 @@ findRefVelocity( amrex::Real spongeVelZ = 0.0; amrex::Real residual = 1000; amrex::Real height_error = 0.0; - for (int ii = 0; ii < verticalSize; ++ii) { + for (unsigned long ii = 0; ii < verticalSize; ++ii) { height_error = std::abs(x3 - vel_ht[ii]); if (height_error < residual) { residual = height_error; diff --git a/amr-wind/equation_systems/icns/source_terms/DragForcing.cpp b/amr-wind/equation_systems/icns/source_terms/DragForcing.cpp index 121ebaeadc..84c4b7f362 100644 --- a/amr-wind/equation_systems/icns/source_terms/DragForcing.cpp +++ b/amr-wind/equation_systems/icns/source_terms/DragForcing.cpp @@ -51,7 +51,17 @@ void DragForcing::operator()( const amrex::Real spongeDensity = m_spongeDensity; const amrex::Real startX = (1 - m_spongePercentX / 100.0) * prob_hi[0]; const amrex::Real startY = (1 - m_spongePercentY / 100.0) * prob_hi[1]; - const int verticalSize = device_vel_ht.size(); + unsigned long verticalSize = device_vel_ht.size(); + amrex::Gpu::DeviceVector vel_ht; + amrex::Gpu::DeviceVector vel_vals; + vel_ht.resize(verticalSize); + vel_vals.resize(verticalSize); + amrex::Gpu::copy( + amrex::Gpu::deviceToDevice, device_vel_ht.begin(), + device_vel_ht.end(), vel_ht.begin()); + amrex::Gpu::copy( + amrex::Gpu::deviceToDevice, device_vel_vals.begin(), + device_vel_vals.end(), vel_vals.begin()); amrex::ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept { const amrex::Real ux = vel(i, j, k, 0); const amrex::Real uy = vel(i, j, k, 1); diff --git a/amr-wind/physics/TerrainDrag.H b/amr-wind/physics/TerrainDrag.H index 5d4bd88775..963586bc7a 100644 --- a/amr-wind/physics/TerrainDrag.H +++ b/amr-wind/physics/TerrainDrag.H @@ -46,7 +46,7 @@ private: }; AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real find_terrain_height( - const int terrainSize, + unsigned long terrainSize, const amrex::Real x1, const amrex::Real x2, amrex::Gpu::DeviceVector device_xterrain, @@ -55,7 +55,7 @@ AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real find_terrain_height( { amrex::Real terrainHt = 0; amrex::Real residual = 300000; - for (int ii = 0; ii < terrainSize; ++ii) { + for (unsigned long ii = 0; ii < terrainSize; ++ii) { const amrex::Real radius = std::sqrt( std::pow(x1 - device_xterrain[ii], 2) + std::pow(x2 - device_yterrain[ii], 2)); diff --git a/amr-wind/physics/TerrainDrag.cpp b/amr-wind/physics/TerrainDrag.cpp index 28b0206035..d0bb8d7c4a 100644 --- a/amr-wind/physics/TerrainDrag.cpp +++ b/amr-wind/physics/TerrainDrag.cpp @@ -58,7 +58,7 @@ void TerrainDrag::initialize_fields(int level, const amrex::Geometry& geom) const auto& vbx = mfi.validbox(); auto levelBlanking = blanking.array(mfi); auto levelDrag = drag.array(mfi); - const int terrainSize = m_xterrain.size(); + unsigned long terrainSize = m_xterrain.size(); amrex::ParallelFor( vbx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept { const amrex::Real x1 = prob_lo[0] + (i + 0.5) * dx[0]; From 201602c09bec7b6b30512a3ef51185f766c5db79 Mon Sep 17 00:00:00 2001 From: hgopalan Date: Mon, 8 Apr 2024 16:44:41 -0600 Subject: [PATCH 13/77] Clang --- amr-wind/equation_systems/icns/source_terms/DragForcing.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/amr-wind/equation_systems/icns/source_terms/DragForcing.cpp b/amr-wind/equation_systems/icns/source_terms/DragForcing.cpp index 84c4b7f362..9c6166073c 100644 --- a/amr-wind/equation_systems/icns/source_terms/DragForcing.cpp +++ b/amr-wind/equation_systems/icns/source_terms/DragForcing.cpp @@ -57,8 +57,8 @@ void DragForcing::operator()( vel_ht.resize(verticalSize); vel_vals.resize(verticalSize); amrex::Gpu::copy( - amrex::Gpu::deviceToDevice, device_vel_ht.begin(), - device_vel_ht.end(), vel_ht.begin()); + amrex::Gpu::deviceToDevice, device_vel_ht.begin(), device_vel_ht.end(), + vel_ht.begin()); amrex::Gpu::copy( amrex::Gpu::deviceToDevice, device_vel_vals.begin(), device_vel_vals.end(), vel_vals.begin()); From 6055ba783c9768d5d86e916251025da9671d31a6 Mon Sep 17 00:00:00 2001 From: hgopalan Date: Mon, 8 Apr 2024 16:56:54 -0600 Subject: [PATCH 14/77] GPU Updated --- amr-wind/equation_systems/icns/source_terms/DragForcing.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/amr-wind/equation_systems/icns/source_terms/DragForcing.cpp b/amr-wind/equation_systems/icns/source_terms/DragForcing.cpp index 9c6166073c..6b8aa39b7d 100644 --- a/amr-wind/equation_systems/icns/source_terms/DragForcing.cpp +++ b/amr-wind/equation_systems/icns/source_terms/DragForcing.cpp @@ -83,7 +83,7 @@ void DragForcing::operator()( amrex::Real Cd = dragCoeff / dx[0]; amrex::Vector wind{{ux, uy, uz}}; wind = - findRefVelocity(verticalSize, x3, device_vel_ht, device_vel_vals); + findRefVelocity(verticalSize, x3, vel_ht, vel_vals); // Terrain Drag amrex::Real kappa = 0.41; amrex::Real ustar = From 7e74c7907938e4a46546ede29c082fe58b47da03 Mon Sep 17 00:00:00 2001 From: hgopalan Date: Mon, 8 Apr 2024 16:58:32 -0600 Subject: [PATCH 15/77] Clang --- amr-wind/equation_systems/icns/source_terms/DragForcing.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/amr-wind/equation_systems/icns/source_terms/DragForcing.cpp b/amr-wind/equation_systems/icns/source_terms/DragForcing.cpp index 6b8aa39b7d..d5433aaa45 100644 --- a/amr-wind/equation_systems/icns/source_terms/DragForcing.cpp +++ b/amr-wind/equation_systems/icns/source_terms/DragForcing.cpp @@ -82,8 +82,7 @@ void DragForcing::operator()( const amrex::Real m = std::sqrt(ux * ux + uy * uy + uz * uz); amrex::Real Cd = dragCoeff / dx[0]; amrex::Vector wind{{ux, uy, uz}}; - wind = - findRefVelocity(verticalSize, x3, vel_ht, vel_vals); + wind = findRefVelocity(verticalSize, x3, vel_ht, vel_vals); // Terrain Drag amrex::Real kappa = 0.41; amrex::Real ustar = From 425d455cce577af52940b8e7896578c9c3b37263 Mon Sep 17 00:00:00 2001 From: hgopalan Date: Tue, 9 Apr 2024 07:09:42 -0600 Subject: [PATCH 16/77] GPU Compatibility --- .../icns/source_terms/DragForcing.H | 11 ++++++++--- .../icns/source_terms/DragForcing.cpp | 14 +++++++++----- 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/amr-wind/equation_systems/icns/source_terms/DragForcing.H b/amr-wind/equation_systems/icns/source_terms/DragForcing.H index 808a45817c..137295fad6 100644 --- a/amr-wind/equation_systems/icns/source_terms/DragForcing.H +++ b/amr-wind/equation_systems/icns/source_terms/DragForcing.H @@ -45,10 +45,10 @@ private: amrex::Real m_spongePercentY{20}; }; -AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Vector -findRefVelocity( +AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real findRefVelocity( unsigned long verticalSize, const amrex::Real x3, + const int idir, amrex::Gpu::DeviceVector vel_ht, amrex::Gpu::DeviceVector vel_vals) { @@ -66,7 +66,12 @@ findRefVelocity( spongeVelZ = vel_vals[3 * ii + 2]; } } - amrex::Vector wind{{spongeVelX, spongeVelY, spongeVelZ}}; + amrex::Real wind = spongeVelZ; + if (idir == 1) { + wind = spongeVelX; + } else if (idir == 2) { + wind = spongeVelY; + } return wind; } diff --git a/amr-wind/equation_systems/icns/source_terms/DragForcing.cpp b/amr-wind/equation_systems/icns/source_terms/DragForcing.cpp index d5433aaa45..3429eae46d 100644 --- a/amr-wind/equation_systems/icns/source_terms/DragForcing.cpp +++ b/amr-wind/equation_systems/icns/source_terms/DragForcing.cpp @@ -81,8 +81,12 @@ void DragForcing::operator()( } const amrex::Real m = std::sqrt(ux * ux + uy * uy + uz * uz); amrex::Real Cd = dragCoeff / dx[0]; - amrex::Vector wind{{ux, uy, uz}}; - wind = findRefVelocity(verticalSize, x3, vel_ht, vel_vals); + amrex::Real windx = + findRefVelocity(verticalSize, x3, 1, vel_ht, vel_vals); + amrex::Real windy = + findRefVelocity(verticalSize, x3, 2, vel_ht, vel_vals); + amrex::Real windz = + findRefVelocity(verticalSize, x3, 3, vel_ht, vel_vals); // Terrain Drag amrex::Real kappa = 0.41; amrex::Real ustar = @@ -95,13 +99,13 @@ void DragForcing::operator()( amrex::Real CdM = std::min(Cd * 5.0 / (m + 1e-5), 100.0); src_term(i, j, k, 0) -= (CdM * m * ux * blank(i, j, k) + Dxz * drag(i, j, k) + - (xdamping + ydamping) * (ux - spongeDensity * wind[0])); + (xdamping + ydamping) * (ux - spongeDensity * windx)); src_term(i, j, k, 1) -= (CdM * m * uy * blank(i, j, k) + Dyz * drag(i, j, k) + - (xdamping + ydamping) * (uy - spongeDensity * wind[1])); + (xdamping + ydamping) * (uy - spongeDensity * windy)); src_term(i, j, k, 2) -= (CdM * m * uz * blank(i, j, k) + - (xdamping + ydamping) * (uz - spongeDensity * wind[2])); + (xdamping + ydamping) * (uz - spongeDensity * windz)); }); } From db46f4aaa1e2b5a7bf6fb7118447d07bd66a837b Mon Sep 17 00:00:00 2001 From: hgopalan Date: Tue, 2 Jul 2024 11:35:39 -0600 Subject: [PATCH 17/77] This update modifies the code-base to make it more convenient to make changes. --- .../icns/source_terms/DragForcing.H | 70 +++---- .../icns/source_terms/DragForcing.cpp | 175 ++++++++++-------- .../temperature/source_terms/CMakeLists.txt | 1 + .../source_terms/DragTempForcing.H | 44 +++++ .../source_terms/DragTempForcing.cpp | 45 +++++ amr-wind/physics/TerrainDrag.H | 66 +++---- amr-wind/physics/TerrainDrag.cpp | 171 +++++++++++------ amr-wind/turbulence/LES/Kosovic.cpp | 19 +- 8 files changed, 363 insertions(+), 228 deletions(-) create mode 100644 amr-wind/equation_systems/temperature/source_terms/DragTempForcing.H create mode 100644 amr-wind/equation_systems/temperature/source_terms/DragTempForcing.cpp diff --git a/amr-wind/equation_systems/icns/source_terms/DragForcing.H b/amr-wind/equation_systems/icns/source_terms/DragForcing.H index 137295fad6..4d53abca96 100644 --- a/amr-wind/equation_systems/icns/source_terms/DragForcing.H +++ b/amr-wind/equation_systems/icns/source_terms/DragForcing.H @@ -2,24 +2,23 @@ #define DRAGFORCING_H #include "amr-wind/equation_systems/icns/MomentumSource.H" -#include "amr-wind/utilities/FieldPlaneAveraging.H" #include "amr-wind/core/SimTime.H" #include "amr-wind/CFDSim.H" namespace amr_wind::pde::icns { -/** Adding Terrain-induced drag forcing to momentum equation .. +/** Adds the non-linear terms from the Kosovic Model to Momentum Equation.. * - * \ingroup icns_src DragForcing + * \ingroup icns_src NonLinearSGS * - * \sa DragForcing + * \sa NonLinearSGS */ class DragForcing : public MomentumSource::Register { public: static std::string identifier() { return "DragForcing"; } - explicit DragForcing(const CFDSim& sim); + explicit DragForcing(const CFDSim& sim); ~DragForcing() override; @@ -28,53 +27,26 @@ public: const amrex::MFIter& mfi, const amrex::Box& bx, const FieldState fstate, - const amrex::Array4& src_term) const override; + const amrex::Array4& src_term) const override; + private: - const CFDSim& m_sim; - const amrex::AmrCore& m_mesh; - const Field& m_velocity; - Field& m_terrainBlank; - Field& m_terrainDrag; - amrex::Gpu::DeviceVector device_vel_ht; - amrex::Gpu::DeviceVector device_vel_vals; - amrex::Real m_dragCoeff{8.0}; - amrex::Real m_spongeStrength{1.0}; - amrex::Real m_spongeDensity{1.0}; - amrex::Real m_spongePercentX{20}; - amrex::Real m_spongePercentY{20}; + const CFDSim& m_sim; + const amrex::AmrCore&m_mesh; + const Field& m_velocity; + Field& m_terrainBlank; + Field& m_terrainDrag; + Field& m_terrainz0; + amrex::Gpu::DeviceVector gpu_vel_ht; + amrex::Gpu::DeviceVector gpu_vel_vals; + amrex::Real m_drag{100.0}; + amrex::Real m_spongeStrength{1.0}; + amrex::Real m_spongeDensity{1.0}; + amrex::Real m_spongeDistanceX{1000}; + amrex::Real m_spongeDistanceY{1000}; + amrex::Real m_verificationMode{0}; }; -AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real findRefVelocity( - unsigned long verticalSize, - const amrex::Real x3, - const int idir, - amrex::Gpu::DeviceVector vel_ht, - amrex::Gpu::DeviceVector vel_vals) -{ - amrex::Real spongeVelX = 0.0; - amrex::Real spongeVelY = 0.0; - amrex::Real spongeVelZ = 0.0; - amrex::Real residual = 1000; - amrex::Real height_error = 0.0; - for (unsigned long ii = 0; ii < verticalSize; ++ii) { - height_error = std::abs(x3 - vel_ht[ii]); - if (height_error < residual) { - residual = height_error; - spongeVelX = vel_vals[3 * ii]; - spongeVelY = vel_vals[3 * ii + 1]; - spongeVelZ = vel_vals[3 * ii + 2]; - } - } - amrex::Real wind = spongeVelZ; - if (idir == 1) { - wind = spongeVelX; - } else if (idir == 2) { - wind = spongeVelY; - } - return wind; -} - } // namespace amr_wind::pde::icns -#endif /* DRAGFORCING_H */ +#endif /* NONLINEARSGSTERM_H */ diff --git a/amr-wind/equation_systems/icns/source_terms/DragForcing.cpp b/amr-wind/equation_systems/icns/source_terms/DragForcing.cpp index 3429eae46d..e8abf86946 100644 --- a/amr-wind/equation_systems/icns/source_terms/DragForcing.cpp +++ b/amr-wind/equation_systems/icns/source_terms/DragForcing.cpp @@ -8,26 +8,33 @@ namespace amr_wind::pde::icns { DragForcing::DragForcing(const CFDSim& sim) - : m_sim(sim) - , m_mesh(sim.mesh()) - , m_velocity(sim.repo().get_field("velocity")) - , m_terrainBlank(sim.repo().get_field("terrainBlank")) - , m_terrainDrag(sim.repo().get_field("terrainDrag")) - + :m_sim(sim), + m_mesh(sim.mesh()), + m_velocity(sim.repo().get_field("velocity")), + m_terrainBlank(sim.repo().get_field("terrainBlank")), + m_terrainDrag(sim.repo().get_field("terrainDrag")), + m_terrainz0(sim.repo().get_field("terrainz0")) { - const auto& abl = m_sim.physics_manager().get(); - const VelPlaneAveraging& fa_velocity = - abl.abl_statistics().vel_profile_coarse(); - device_vel_ht.resize(fa_velocity.line_centroids().size()); - device_vel_vals.resize(fa_velocity.line_average().size()); - amrex::Gpu::copy( - amrex::Gpu::hostToDevice, fa_velocity.line_centroids().begin(), - fa_velocity.line_centroids().end(), device_vel_ht.begin()); - amrex::Gpu::copy( - amrex::Gpu::hostToDevice, fa_velocity.line_average().begin(), - fa_velocity.line_average().end(), device_vel_vals.begin()); + auto& phy_mgr = m_sim.physics_manager(); + if (phy_mgr.contains("ABL")) { + const auto& abl = m_sim.physics_manager().get(); + const VelPlaneAveraging& fa_velocity=abl.abl_statistics().vel_profile_coarse(); + gpu_vel_ht.resize(fa_velocity.line_centroids().size()); + gpu_vel_vals.resize(fa_velocity.line_average().size()); + amrex::Gpu::copy(amrex::Gpu::hostToDevice, fa_velocity.line_centroids().begin(), + fa_velocity.line_centroids().end(), gpu_vel_ht.begin()); + amrex::Gpu::copy(amrex::Gpu::hostToDevice, fa_velocity.line_average().begin(), + fa_velocity.line_average().end(), gpu_vel_vals.begin()); + } + amrex::ParmParse pp("DragForcing"); + pp.query("dragCoefficient", m_drag); + pp.query("spongeStrength",m_spongeStrength); + pp.query("spongeDensity",m_spongeDensity); + pp.query("spongeDistanceX",m_spongeDistanceX); + pp.query("spongeDistanceY",m_spongeDistanceY); + pp.query("verificationMode",m_verificationMode); } - + DragForcing::~DragForcing() = default; void DragForcing::operator()( @@ -38,75 +45,81 @@ void DragForcing::operator()( const amrex::Array4& src_term) const { const auto& vel = - m_velocity.state(field_impl::dof_state(fstate))(lev).const_array(mfi); + m_velocity.state(field_impl::dof_state(fstate))(lev).const_array(mfi); const auto blank = m_terrainBlank(lev).const_array(mfi); const auto drag = m_terrainDrag(lev).const_array(mfi); + const auto terrainz0=m_terrainz0(lev).const_array(mfi); const auto& geom_vec = m_mesh.Geom(); - const auto& geom = geom_vec[lev]; - const auto& dx = geom.CellSizeArray(); + const auto& geom = geom_vec[lev]; + const auto& dx = geom.CellSize(); const auto& prob_lo = geom.ProbLoArray(); const auto& prob_hi = geom.ProbHiArray(); - const amrex::Real dragCoeff = m_dragCoeff; - const amrex::Real spongeStrength = m_spongeStrength; - const amrex::Real spongeDensity = m_spongeDensity; - const amrex::Real startX = (1 - m_spongePercentX / 100.0) * prob_hi[0]; - const amrex::Real startY = (1 - m_spongePercentY / 100.0) * prob_hi[1]; - unsigned long verticalSize = device_vel_ht.size(); - amrex::Gpu::DeviceVector vel_ht; - amrex::Gpu::DeviceVector vel_vals; - vel_ht.resize(verticalSize); - vel_vals.resize(verticalSize); - amrex::Gpu::copy( - amrex::Gpu::deviceToDevice, device_vel_ht.begin(), device_vel_ht.end(), - vel_ht.begin()); - amrex::Gpu::copy( - amrex::Gpu::deviceToDevice, device_vel_vals.begin(), - device_vel_vals.end(), vel_vals.begin()); + const amrex::Real gpu_drag=m_drag; + const amrex::Real gpu_spongeStrength=m_spongeStrength; + const amrex::Real gpu_spongeDensity=m_spongeDensity; + const amrex::Real gpu_startX=prob_hi[0]-m_spongeDistanceX; + const amrex::Real gpu_startY=prob_hi[1]-m_spongeDistanceY; + const amrex::Real gpu_verificationMode=m_verificationMode; + // Copy Data + const auto* local_gpu_vel_ht = gpu_vel_ht.data(); + const auto* local_gpu_vel_vals=gpu_vel_vals.data(); + const amrex::Real vsize=gpu_vel_ht.size(); amrex::ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept { - const amrex::Real ux = vel(i, j, k, 0); - const amrex::Real uy = vel(i, j, k, 1); - const amrex::Real uz = vel(i, j, k, 2); - const amrex::Real x1 = prob_lo[0] + (i + 0.5) * dx[0]; - const amrex::Real x2 = prob_lo[1] + (j + 0.5) * dx[1]; - const amrex::Real x3 = prob_lo[2] + (k + 0.5) * dx[2]; - amrex::Real xdamping = 0; - amrex::Real ydamping = 0; - if (x1 > startX) { - amrex::Real xi = (x1 - startX) / (prob_hi[0] - startX); - xdamping = spongeStrength * xi * xi; - } - if (x2 > startY) { - amrex::Real yi = (x2 - startY) / (prob_hi[1] - startY); - ydamping = spongeStrength * yi * yi; - } - const amrex::Real m = std::sqrt(ux * ux + uy * uy + uz * uz); - amrex::Real Cd = dragCoeff / dx[0]; - amrex::Real windx = - findRefVelocity(verticalSize, x3, 1, vel_ht, vel_vals); - amrex::Real windy = - findRefVelocity(verticalSize, x3, 2, vel_ht, vel_vals); - amrex::Real windz = - findRefVelocity(verticalSize, x3, 3, vel_ht, vel_vals); - // Terrain Drag - amrex::Real kappa = 0.41; - amrex::Real ustar = - std::sqrt(ux * ux + uy * uy) * kappa / std::log((x3 + 0.1) / 0.1); - amrex::Real Dxz = - -ustar * ustar * ux / (1e-5 + std::sqrt(ux * ux + uy * uy)) / dx[2]; - amrex::Real Dyz = - -ustar * ustar * uy / (1e-5 + std::sqrt(ux * ux + uy * uy)) / dx[2]; - // Adjusting Cd for momentum - amrex::Real CdM = std::min(Cd * 5.0 / (m + 1e-5), 100.0); - src_term(i, j, k, 0) -= - (CdM * m * ux * blank(i, j, k) + Dxz * drag(i, j, k) + - (xdamping + ydamping) * (ux - spongeDensity * windx)); - src_term(i, j, k, 1) -= - (CdM * m * uy * blank(i, j, k) + Dyz * drag(i, j, k) + - (xdamping + ydamping) * (uy - spongeDensity * windy)); - src_term(i, j, k, 2) -= - (CdM * m * uz * blank(i, j, k) + - (xdamping + ydamping) * (uz - spongeDensity * windz)); + const amrex::Real x1 = prob_lo[0] + (i + 0.5) * dx[0]; + const amrex::Real x2 = prob_lo[1] + (j + 0.5) * dx[1]; + const amrex::Real x3 = prob_lo[2] + (k + 0.5) * dx[2]; + amrex::Real xdamping=0; + amrex::Real ydamping=0; + if(x1>gpu_startX){ + amrex::Real xi=(x1 - gpu_startX) / (prob_hi[0] - gpu_startX); + xdamping=(1-gpu_verificationMode)*gpu_spongeStrength * xi * xi ; + } + if(x2>gpu_startY){ + amrex::Real yi=(x2 - gpu_startY) / (prob_hi[1] - gpu_startY); + ydamping=(1-gpu_verificationMode)*gpu_spongeStrength * yi * yi; + } + amrex::Real Cd=gpu_drag/dx[0]; + amrex::Real gpu_spongeVelX=0.0; + amrex::Real gpu_spongeVelY=0.0; + amrex::Real gpu_spongeVelZ=0.0; + amrex::Real residual=1000; + amrex::Real height_error=0.0; + for(int ii=0;ii +{ +public: + static std::string identifier() { return "DragTempForcing"; } + + explicit DragTempForcing(const CFDSim& sim); + + ~DragTempForcing() override; + + void operator()( + const int lev, + const amrex::MFIter& mfi, + const amrex::Box& bx, + const FieldState fstate, + const amrex::Array4& src_term) const override; + + +private: + const CFDSim& m_sim; + const amrex::AmrCore&m_mesh; + Field& m_temperature; + Field& m_terrainBlank; + amrex::Real m_drag{10.0}; + amrex::Real m_verificationMode{0}; +}; + +} // namespace amr_wind::pde::temperature + +#endif /* NONLINEARSGSTERM_H */ diff --git a/amr-wind/equation_systems/temperature/source_terms/DragTempForcing.cpp b/amr-wind/equation_systems/temperature/source_terms/DragTempForcing.cpp new file mode 100644 index 0000000000..f4dcf04d98 --- /dev/null +++ b/amr-wind/equation_systems/temperature/source_terms/DragTempForcing.cpp @@ -0,0 +1,45 @@ +#include "amr-wind/equation_systems/temperature/source_terms/DragTempForcing.H" +#include "amr-wind/utilities/IOManager.H" + +#include "AMReX_ParmParse.H" +#include "AMReX_Gpu.H" +#include "AMReX_Random.H" + + +namespace amr_wind::pde::temperature { + +DragTempForcing::DragTempForcing(const CFDSim& sim) + :m_sim(sim), + m_mesh(sim.mesh()), + m_temperature(sim.repo().get_field("temperature")), + m_terrainBlank(sim.repo().get_field("terrainBlank")) +{ + amrex::ParmParse pp("DragTempForcing"); + pp.query("dragCoefficient", m_drag); + pp.query("verificationMode",m_verificationMode); +} + +DragTempForcing::~DragTempForcing() = default; + +void DragTempForcing::operator()( + const int lev, + const amrex::MFIter& mfi, + const amrex::Box& bx, + const FieldState fstate, + const amrex::Array4& src_term) const +{ + const auto temperature=m_temperature(lev).const_array(mfi); + const auto blank = m_terrainBlank(lev).const_array(mfi); + const auto& geom_vec = m_mesh.Geom(); + const auto& geom = geom_vec[lev]; + const auto& dx = geom.CellSize(); + const amrex::Real gpu_drag=m_drag; + const amrex::Real gpu_verificationMode=m_verificationMode; + const amrex::Real gpu_TRef=300.0; + amrex::ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept { + amrex::Real Cd=gpu_drag/dx[0]; + src_term(i, j, k, 0) -= (Cd*(temperature(i,j,k,0)-gpu_TRef)*blank(i,j,k)); + }); +} + +} // namespace amr_wind::pde::temperature diff --git a/amr-wind/physics/TerrainDrag.H b/amr-wind/physics/TerrainDrag.H index 963586bc7a..53e4b519fe 100644 --- a/amr-wind/physics/TerrainDrag.H +++ b/amr-wind/physics/TerrainDrag.H @@ -7,7 +7,10 @@ namespace amr_wind::terraindrag { -namespace {} // namespace +namespace { + + +} // namespace /** Terraindrag Flow physics * \ingroup physics @@ -22,50 +25,37 @@ public: ~TerrainDrag() override = default; - void initialize_fields(int level, const amrex::Geometry& geom) override; - - void post_init_actions() override {} + void initialize_fields(int /*level*/, const amrex::Geometry& /*geom*/) override{} + + void pre_init_actions() override; + + void post_init_actions() override; void post_regrid_actions() override {} - void pre_advance_work() override {} + void pre_advance_work() override{} - void post_advance_work() override {} + void post_advance_work() override{} + // amrex::Real computeTerrainHeight(const amrex::Real x1,const amrex::Real x2) const; private: - CFDSim& m_sim; - const FieldRepo& m_repo; - const amrex::AmrCore& m_mesh; - Field& m_velocity; - // Blanking Field for Terrain or Buildings - Field& m_terrainBlank; - // Terrain Height field - Not in use now - Field& m_terrainDrag; - // Reading the Terrain Coordinates from file - amrex::Vector m_xterrain, m_yterrain, m_zterrain; -}; + CFDSim& m_sim; + const FieldRepo& m_repo; + const amrex::AmrCore& m_mesh; + Field& m_velocity; + // Blanking Field for Terrain or Buildings + Field& m_terrainBlank; + // Terrain Drag Force Term + Field& m_terrainDrag; + // Reading the Terrain Coordinates from file + amrex::Vector m_xterrain,m_yterrain,m_zterrain; + // Roughness Field + Field& m_terrainz0; + // Reading the Roughness Coordinates from file - Not Fully there yet + // Need updates to ABLWallFunction in future + amrex::Vector m_xrough,m_yrough,m_z0rough; -AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real find_terrain_height( - unsigned long terrainSize, - const amrex::Real x1, - const amrex::Real x2, - amrex::Gpu::DeviceVector device_xterrain, - amrex::Gpu::DeviceVector device_yterrain, - amrex::Gpu::DeviceVector device_zterrain) -{ - amrex::Real terrainHt = 0; - amrex::Real residual = 300000; - for (unsigned long ii = 0; ii < terrainSize; ++ii) { - const amrex::Real radius = std::sqrt( - std::pow(x1 - device_xterrain[ii], 2) + - std::pow(x2 - device_yterrain[ii], 2)); - if (radius < residual) { - residual = radius; - terrainHt = device_zterrain[ii]; - } - } - return terrainHt; -} +}; } // namespace amr_wind::terraindrag #endif diff --git a/amr-wind/physics/TerrainDrag.cpp b/amr-wind/physics/TerrainDrag.cpp index d0bb8d7c4a..417c142914 100644 --- a/amr-wind/physics/TerrainDrag.cpp +++ b/amr-wind/physics/TerrainDrag.cpp @@ -9,7 +9,9 @@ namespace amr_wind::terraindrag { -namespace {} // namespace +namespace { + +} // namespace TerrainDrag::TerrainDrag(CFDSim& sim) : m_sim(sim) @@ -18,73 +20,136 @@ TerrainDrag::TerrainDrag(CFDSim& sim) , m_velocity(sim.repo().get_field("velocity")) , m_terrainBlank(sim.repo().declare_field("terrainBlank", 1, 1, 1)) , m_terrainDrag(sim.repo().declare_field("terrainDrag", 1, 1, 1)) + , m_terrainz0(sim.repo().declare_field("terrainz0", 1, 1, 1)) { - std::ifstream file("terrain.amrwind"); - amrex::Real value1, value2, value3; - while (file >> value1 >> value2 >> value3) { - m_xterrain.push_back(value1); - m_yterrain.push_back(value2); - m_zterrain.push_back(value3); - } - file.close(); - m_sim.io_manager().register_io_var("terrainDrag"); - m_sim.io_manager().register_io_var("terrainBlank"); + std::string terrainfile("terrain.amrwind"); + std::ifstream file(terrainfile, std::ios::in); + if (!file.good()) { + amrex::Abort("Cannot find terrain.amrwind file"); + } + amrex::Real value1,value2,value3; + while(file>>value1>>value2>>value3){ + m_xterrain.push_back(value1); + m_yterrain.push_back(value2); + m_zterrain.push_back(value3); + } + file.close(); + // No checks for the file as it is optional currently + std::string roughnessfile("terrain.roughness"); + std::ifstream file1(roughnessfile, std::ios::in); + while(file1>>value1>>value2>>value3){ + m_xrough.push_back(value1); + m_yrough.push_back(value2); + m_z0rough.push_back(value3); + } + file1.close(); + m_sim.io_manager().register_io_var("terrainDrag"); + m_sim.io_manager().register_io_var("terrainBlank"); + m_sim.io_manager().register_io_var("terrainz0"); } -void TerrainDrag::initialize_fields(int level, const amrex::Geometry& geom) + void TerrainDrag::post_init_actions() { - using namespace utils; - + BL_PROFILE("amr-wind::" + this->identifier() + "::post_init_actions"); + //using namespace utils; + const auto& geom_vec = m_sim.repo().mesh().Geom(); + const int nlevels = m_sim.repo().num_active_levels(); + for (int level = 0; level < nlevels; ++level) { + const auto& geom = geom_vec[level]; const auto& dx = geom.CellSizeArray(); const auto& prob_lo = geom.ProbLoArray(); - const auto& velocity = m_velocity(level); + auto& velocity = m_velocity(level); auto& blanking = m_terrainBlank(level); - auto& drag = m_terrainDrag(level); - // copy terrain data to gpu - amrex::Gpu::DeviceVector device_xterrain(m_xterrain.size()); - amrex::Gpu::DeviceVector device_yterrain(m_xterrain.size()); - amrex::Gpu::DeviceVector device_zterrain(m_xterrain.size()); - amrex::Gpu::copy( - amrex::Gpu::hostToDevice, m_xterrain.begin(), m_xterrain.end(), - device_xterrain.begin()); - amrex::Gpu::copy( - amrex::Gpu::hostToDevice, m_yterrain.begin(), m_yterrain.end(), - device_yterrain.begin()); - amrex::Gpu::copy( - amrex::Gpu::hostToDevice, m_zterrain.begin(), m_zterrain.end(), - device_zterrain.begin()); - + auto& terrainz0=m_terrainz0(level); + auto& drag=m_terrainDrag(level); + // copy terrain data to gpu + amrex::Gpu::DeviceVector gpu_xterrain(m_xterrain.size()); + amrex::Gpu::DeviceVector gpu_yterrain(m_xterrain.size()); + amrex::Gpu::DeviceVector gpu_zterrain(m_xterrain.size()); + amrex::Gpu::copy(amrex::Gpu::hostToDevice, m_xterrain.begin(), m_xterrain.end(), gpu_xterrain.begin()); + amrex::Gpu::copy(amrex::Gpu::hostToDevice, m_yterrain.begin(), m_yterrain.end(), gpu_yterrain.begin()); + amrex::Gpu::copy(amrex::Gpu::hostToDevice, m_zterrain.begin(), m_zterrain.end(), gpu_zterrain.begin()); + const auto* xterrain_ptr = gpu_xterrain.data(); + const auto* yterrain_ptr = gpu_yterrain.data(); + const auto* zterrain_ptr = gpu_zterrain.data(); + // Copy Roughness to gpu + amrex::Gpu::DeviceVector gpu_xrough(m_xrough.size()); + amrex::Gpu::DeviceVector gpu_yrough(m_xrough.size()); + amrex::Gpu::DeviceVector gpu_z0rough(m_xrough.size()); + amrex::Gpu::copy(amrex::Gpu::hostToDevice, m_xrough.begin(), m_xrough.end(), gpu_xrough.begin()); + amrex::Gpu::copy(amrex::Gpu::hostToDevice, m_yrough.begin(), m_yrough.end(), gpu_yrough.begin()); + amrex::Gpu::copy(amrex::Gpu::hostToDevice, m_z0rough.begin(), m_z0rough.end(), gpu_z0rough.begin()); + const auto* xrough_ptr = gpu_xrough.data(); + const auto* yrough_ptr = gpu_yrough.data(); + const auto* z0rough_ptr = gpu_z0rough.data(); for (amrex::MFIter mfi(velocity); mfi.isValid(); ++mfi) { const auto& vbx = mfi.validbox(); auto levelBlanking = blanking.array(mfi); - auto levelDrag = drag.array(mfi); - unsigned long terrainSize = m_xterrain.size(); + auto levelDrag=drag.array(mfi); + auto levelz0=terrainz0.array(mfi); + const amrex::Real terrainSize=m_xterrain.size(); + const amrex::Real roughnessSize=m_xrough.size(); amrex::ParallelFor( - vbx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept { + vbx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept { + // compute the source term const amrex::Real x1 = prob_lo[0] + (i + 0.5) * dx[0]; const amrex::Real x2 = prob_lo[1] + (j + 0.5) * dx[1]; - const amrex::Real x3 = prob_lo[2] + (k + 0.5) * dx[2]; - amrex::Real terrainHt = find_terrain_height( - terrainSize, x1, x2, device_xterrain, device_yterrain, - device_zterrain); - const amrex::Real turnOn = (x3 <= terrainHt) ? 1.0 : 0.0; + const amrex::Real x3 = prob_lo[2] + (k + 0.5) * dx[2]; + // Terrain Height + amrex::Real residual=10000; + amrex::Real terrainHt=0.0; + for(int ii=0;ii terrainHt && k > 0 && - levelBlanking(i, j, k - 1, 0) == 1) { - levelDrag(i, j, k, 0) = 1.0; - } - }); + residual=10000; + amrex::Real roughz0=0.1; + for(int ii=0;iiterrainHt && k>0 && levelBlanking(i,j,k-1,0)==1){ + levelDrag(i,j,k,0)=1.0; + } + + }); } + } } + void TerrainDrag::pre_init_actions() + { + BL_PROFILE("amr-wind::" + this->identifier() + "::pre_init_actions"); + + } + } // namespace amr_wind::terraindrag diff --git a/amr-wind/turbulence/LES/Kosovic.cpp b/amr-wind/turbulence/LES/Kosovic.cpp index 13f975c87c..614a4f0a6c 100644 --- a/amr-wind/turbulence/LES/Kosovic.cpp +++ b/amr-wind/turbulence/LES/Kosovic.cpp @@ -18,7 +18,7 @@ Kosovic::Kosovic(CFDSim& sim) , m_vel(sim.repo().get_field("velocity")) , m_rho(sim.repo().get_field("density")) , m_Nij(sim.repo().declare_field("Nij", 9, 1, 1)) - , m_divNij(sim.repo().declare_field("divNij", 3)) + , m_divNij(sim.repo().declare_field("divNij", 3, 1, 1)) { amrex::ParmParse pp("Kosovic"); pp.query("Cb", m_Cb); @@ -41,7 +41,6 @@ Kosovic::Kosovic(CFDSim& sim) } pp.query("LESOff", m_LESTurnOff); } - template void Kosovic::update_turbulent_viscosity( const FieldState fstate, const DiffusionType /*unused*/) @@ -55,7 +54,11 @@ void Kosovic::update_turbulent_viscosity( const auto& den = m_rho.state(fstate); const auto& geom_vec = repo.mesh().Geom(); const amrex::Real Cs_sqr = this->m_Cs * this->m_Cs; - + bool is_terrain = this->m_sim.repo().field_exists("terrainBlank"); + Field* m_terrainBlank= &mu_turb; + if (is_terrain) { + m_terrainBlank = &this->m_sim.repo().get_field("terrainBlank"); + } // Populate strainrate into the turbulent viscosity arrays to avoid creating // a temporary buffer fvm::strainrate(mu_turb, vel); @@ -83,6 +86,7 @@ void Kosovic::update_turbulent_viscosity( const auto& mu_arr = mu_turb(lev).array(mfi); const auto& rho_arr = den(lev).const_array(mfi); const auto& divNijLevel = (this->m_divNij)(lev).array(mfi); + const auto& blank_arr = (*m_terrainBlank)(lev).array(mfi); amrex::ParallelFor( bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept { const amrex::Real rho = rho_arr(i, j, k); @@ -100,16 +104,17 @@ void Kosovic::update_turbulent_viscosity( smag_factor + std::pow(fmu, locSurfaceRANSExp) * ransL) + (1 - locSurfaceFactor) * smag_factor; - mu_arr(i, j, k) *= rho * viscosityScale * turnOff; + const amrex::Real blankTerrain = (is_terrain)? 1-blank_arr(i,j,k,0):1.0; + mu_arr(i, j, k) *= rho * viscosityScale * turnOff * blankTerrain; amrex::Real stressScale = locSurfaceFactor * (std::pow(1 - fmu, locSurfaceRANSExp) * smag_factor * 0.25 * locC1 + std::pow(fmu, locSurfaceRANSExp) * ransL) + (1 - locSurfaceFactor) * smag_factor * 0.25 * locC1; - divNijLevel(i, j, k, 0) *= rho * stressScale * turnOff; - divNijLevel(i, j, k, 1) *= rho * stressScale * turnOff; - divNijLevel(i, j, k, 2) *= rho * stressScale * turnOff; + divNijLevel(i, j, k, 0) *= rho * stressScale * turnOff * blankTerrain; + divNijLevel(i, j, k, 1) *= rho * stressScale * turnOff * blankTerrain; + divNijLevel(i, j, k, 2) *= rho * stressScale * turnOff * blankTerrain; }); } } From b225703ab013a241e6cd1ee241a2d5b75185db2d Mon Sep 17 00:00:00 2001 From: hgopalan Date: Tue, 2 Jul 2024 11:44:35 -0600 Subject: [PATCH 18/77] Python Utilities to create the terrain file --- tools/terrain/SRTM_to_STL_example.py | 414 +++++++++++++ tools/terrain/backendInterface.py | 836 +++++++++++++++++++++++++ tools/terrain/sampleYaml.yaml | 30 + tools/terrain/saveTurbines.py | 26 + tools/terrain/stl2XYZ.py | 62 ++ tools/terrain/terrain.py | 884 +++++++++++++++++++++++++++ 6 files changed, 2252 insertions(+) create mode 100644 tools/terrain/SRTM_to_STL_example.py create mode 100644 tools/terrain/backendInterface.py create mode 100644 tools/terrain/sampleYaml.yaml create mode 100644 tools/terrain/saveTurbines.py create mode 100644 tools/terrain/stl2XYZ.py create mode 100644 tools/terrain/terrain.py diff --git a/tools/terrain/SRTM_to_STL_example.py b/tools/terrain/SRTM_to_STL_example.py new file mode 100644 index 0000000000..cc756d895c --- /dev/null +++ b/tools/terrain/SRTM_to_STL_example.py @@ -0,0 +1,414 @@ +def SRTM_Converter(outputDir,refLat,refLon,refHeight,left,right,bottom,top): + import os + import sys + import numpy as np + import matplotlib.pyplot as plt + from matplotlib.patches import Rectangle + import xarray as xr + from scipy.interpolate import RectBivariateSpline, griddata + import utm + from stl import mesh # install with `pip install numpy-stl` + from terrain import SRTM + # # Terrain-Resolved Domain Setup + # This notebook will generate a surface geometry file to be used by the microscale solver (e.g., SOWFA) to conform the solver domain to the terrain (e.g., with `moveDynamicMesh`). + # + # Notebook written by Eliot Quon, modified by Regis Thedin\ + # {eliot.quon,regis.thedin}@nrel.gov + + # ## 1. User input + # Output directory (absolute dir) + outdir = outputDir + # ### 1.1 Mesoscale parameters + # Get lower resolution WRF terrain data + getWRFdata = False + # WRF reference solution to blend from low-res (WRF) at inflow boundaries to full SRTM resolution + wrfout = '/home/rthedin/MMC/WFIP2Region/20161121_YSU/wrfout_d01_2016-11-22_00:00:00' + # ### 1.2 Microscale parameters + # + # First, set the resolution of the data the STL will be created from, and the output resolution. + product = 'SRTM1' # SRTM1 | SRTM3 (30- and 90-m DEM) + ds = 10. # output resolution + + + # The following cell should be modified by the user, following the examples given. The cell contains information about the actual location to be saved. + # + # The `refloc` variable is the location coresponding to (0,0) in SOWFA. + # + # Set the fringe on each side of the domain. This fringe region will used to blend the high-resolution SRTM domain data with either i) low-reosolution WRF (mesoscale) digital elevation model (DEM), or ii) flat. + # + # If `getWRFdata` above is `True`, then blending to mesoscale will occur; otherwise, the domain will be blended to flat. If blending to flat, the user can specify an extra fringe region of completely flat domain (`fringe_flat`). Additionally, if blending to flat, the terrain surface data can be shifted vertically such that the flat region is at $z=0$ by setting `shiftFlatToZero` to `True`. + # + # With respect to the bounding box, it is nice to have the boundaries exactly where the mesh would go because of the blending. For instance, a 5x5 km domain needs to match all the levels of cells: 20, 40, 80, 160 m. Essentially, 5000/160 needs to be an integer number, the same way 5000/80 needs to be as well. However, we only really need to match the coarsest resolution because they are multiple. Finally, an extra fringe of width `ds` (the resolution set above) is added, half on each side. The desired bounding box should go into the `xmin`,`xmax`,`ymin`,`ymax` variables, ignoring the `ds` addition. This extra fringe is to ensure that the STL is slighly larger than the bounding box that will be set on the microscale solver (needed in OpenFOAM to avoid numerical issues). + + + # For WFIP2 region + # - blend to flat + #refloc = (45.638004, -120.642973, 495) # biglow PS12 met mast + refloc=(refLat,refLon,refHeight) + xmin,xmax = -left-ds/2,right+ds/2 + ymin,ymax = -bottom-ds/2,top+ds/2 + fringe_flat=150 + shiftFlatToZero=True + fringe_w = 3000 + fringe_s = 3000 + fringe_n = 3000 + fringe_e = 3000 + case = f'wfip_xm{abs(int(xmin))}to{int(xmax)}_ym{abs(int(ymin))}to{int(ymax)}_blendFlat3N3S3E3W_ff{fringe_flat}' + + # - blend to WRF + # refloc = (45.638004, -120.642973, 495) # biglow PS12 met mast + # xmin,xmax = -15000-ds/2, 15720+ds/2 + # ymin,ymax = -5000-ds/2, 15160+ds/2 + # fringe_flat=0 + # shiftFlatToZero=False + # fringe_w = 3000 + # fringe_s = 3000 + # fringe_n = 3000 + # fringe_e = 3000 + # case = f'wfip_xm{abs(int(xmin))}to{int(xmax)}_ym{abs(int(ymin))}to{int(ymax)}_blendWRF3N3S3E3W' + + + # ## 2. Create output surface + + # In[11]: + + + x1 = np.arange(xmin, xmax+ds, ds) + y1 = np.arange(ymin, ymax+ds, ds) + xsurf,ysurf = np.meshgrid(x1, y1, indexing='ij') + + + # In[12]: + + + print('The output bounding box is') + print('xmin: ',xsurf[0,0], '\nxmax: ',xsurf[-1,-1]) + print('ymin: ',ysurf[0,0], '\nymax: ',ysurf[-1,-1]) + + + # ## 3. Get the high-resolution terrain + + # In[13]: + + + # Terrain region to clip from the digital elevation model (DEM) + srtm_bounds = west, south, east, north = (refloc[1]-0.5, refloc[0]-0.4, refloc[1]+0.62, refloc[0]+0.42) + + # this will be downloaded: + srtm_output=f'{outdir}/{case}.tif' # need absolute path for GDAL + + + # In[14]: + + + srtm = SRTM(srtm_bounds, fpath=srtm_output, product=product) + + + # In[15]: + + + #get_ipython().run_line_magic('time', 'srtm.download()') + # CPU times: user 3.53 ms, sys: 12.7 ms, total: 16.2 ms + # Wall time: 8.74 s + + + # In[16]: + srtm.download() + x,y,z = srtm.to_terrain() + #get_ipython().run_cell_magic('time', '', "# original SRTM terrain stored as 'z'\nx,y,z = srtm.to_terrain()\n") + + + # In[17]: + + + # get reference location to use as origin + xref,yref,_,_ = utm.from_latlon(*refloc[:2], force_zone_number=srtm.zone_number) + + + # In[18]: + + + vmin,vmax = 1500,2500 + + fig,ax = plt.subplots(figsize=(12,8)) + cm = ax.pcolormesh(x-xref, y-yref, z, cmap='terrain')#,vmin=vmin,vmax=vmax) + cb = fig.colorbar(cm,ax=ax) + cb.set_label('elevation [m]',fontsize='x-large') + ax.tick_params(labelsize='large') + ax.set_xlabel('easting [m]') + ax.set_ylabel('northing [m]') + ax.set_title(f'{product} DEM projection') + ax.axis('scaled') + + # bounding box for microscale region + les = Rectangle((xmin,ymin), xmax-xmin, ymax-ymin, edgecolor='r', lw=3, facecolor='0.5', alpha=0.5) + ax.add_patch(les) + #plt.show() + + # ### 3.1 Downscale to output grid + + # In[19]: + + + interpfun = RectBivariateSpline(x[:,0]-xref, y[0,:]-yref, z) + + + # In[20]: + + + # resampled SRTM data stored in 'zsrtm' + zsrtm = interpfun(x1,y1,grid=True) + + + + # In[21]: + + + fig,ax = plt.subplots(figsize=(12,8)) + cm = ax.pcolormesh(xsurf, ysurf, zsrtm, cmap='terrain')#,vmin=vmin,vmax=vmax) + cb = fig.colorbar(cm,ax=ax) + cb.set_label('elevation [m]',fontsize='x-large') + ax.tick_params(labelsize='large') + ax.set_xlabel('easting [m]') + ax.set_ylabel('northing [m]') + ax.set_title(f'{product} terrain height') + ax.axis('scaled') + + fig.savefig(f'{outdir}/elevation_srtm_{case}.png',dpi=150,bbox_inches='tight') + + + # ## 4. Get the low-resolution terrain from the mesoscale + # This part is only relevant if the user chose to blen the high-resolution SRTM terrain data with WRF + + # In[22]: + + + # Open the dataset + if getWRFdata is True: + if os.path.isfile(wrfout) is True: + wrf = xr.open_dataset(wrfout) + wrf['HGT'] + else: + print('WRF input does not exist') + sys.exit(1) + + + # In[23]: + + + if getWRFdata is True: + # wrf fields + hgt = wrf['HGT'][0,:,:] + xlat = wrf.coords['XLAT'][0,:,:] + xlon = wrf.coords['XLONG'][0,:,:] + + + # In[24]: + + + if getWRFdata is True: + get_ipython().run_line_magic('time', 'output_lat, output_lon = srtm.to_latlon(xsurf.ravel()+xref, ysurf.ravel()+yref)') + # CPU times: user 3.38 s, sys: 157 ms, total: 3.54 s + # Wall time: 3.54 s + + + # In[25]: + + + if getWRFdata is True: + # interpolate to wrf surface elevation based on lat/lon (stored as 'zwrf') + xi = np.stack((output_lat.ravel(),output_lon.ravel()),axis=-1) + points = np.stack((xlat.values.ravel(),xlon.values.ravel()),axis=-1) + values = hgt.values.ravel() + zi = griddata(points,values,xi) + zwrf = zi.reshape(xsurf.shape) + # CPU times: user 3.14 s, sys: 931 ms, total: 4.07 s + # Wall time: 2.57 s + + + # In[26]: + + + if getWRFdata is True: + fig,ax = plt.subplots(figsize=(12,8)) + cm = ax.pcolormesh(xsurf, ysurf, zwrf, cmap='terrain')#,vmin=vmin,vmax=vmax) + cb = fig.colorbar(cm,ax=ax) + cb.set_label('elevation [m]',fontsize='x-large') + ax.tick_params(labelsize='large') + ax.set_xlabel('easting [m]') + ax.set_ylabel('northing [m]') + ax.set_title('WRF terrain height') + ax.axis('scaled') + + fig.savefig(f'elevation_wrf_{os.path.basename(wrfout)}.png',dpi=150,bbox_inches='tight') + + + # ## 5. Blend surface definitions + + # In[27]: + + + # check distance from west boundary + blend_w = np.ones(xsurf.shape) + if fringe_w > 0: + blend_w = np.minimum(np.maximum((xsurf-xmin-fringe_flat)/fringe_w, 0), 1) + + + # In[28]: + + + # check distance from east boundary + blend_e = np.ones(xsurf.shape) + if fringe_e > 0: + blend_e = np.minimum(np.maximum((xmax-xsurf-fringe_flat)/fringe_e, 0), 1) + + + # In[29]: + + + # check distance from south boundary + blend_s = np.ones(xsurf.shape) + if fringe_s > 0: + blend_s = np.minimum(np.maximum((ysurf-ymin-fringe_flat)/fringe_s, 0), 1) + + + # In[30]: + + + # check distance from north boundary + blend_n = np.ones(xsurf.shape) + if fringe_n > 0: + blend_n = np.minimum(np.maximum((ymax-ysurf-fringe_flat)/fringe_n, 0), 1) + + + # In[31]: + + + # combine blending functions + blend = blend_w * blend_e * blend_s * blend_n + + + # In[32]: + + + fig,ax = plt.subplots(figsize=(12,8)) + cm = ax.pcolormesh(xsurf, ysurf, blend, cmap='magma') + cb = fig.colorbar(cm,ax=ax) + ax.tick_params(labelsize='large') + ax.set_xlabel('easting [m]') + ax.set_ylabel('northing [m]') + ax.set_title('blending function') + ax.axis('scaled') + + + # In[33]: + + + # create flat surface to be blended + # SRTM data is unlikely to be around the z=0 mark, so get the average + z0 = np.amin(zsrtm) #0 #np.mean(zsrtm) + zflat = np.full(zsrtm.shape,z0) + + + # In[34]: + + + # surface to blend + if getWRFdata is True: + zlowres = zwrf + else: + zlowres = zflat + + + # In[35]: + + + # now, blend the high/low resolution elevations + zblend = blend*zsrtm + (1-blend)*zlowres + + + # In[36]: + + + fig,ax = plt.subplots(figsize=(12,8)) + cm = ax.pcolormesh(xsurf, ysurf, zblend, cmap='terrain')#,vmin=vmin,vmax=vmax) + cb = fig.colorbar(cm,ax=ax) + cb.set_label('elevation [m]',fontsize='x-large') + ax.tick_params(labelsize='large') + ax.set_xlabel('easting [m]') + ax.set_ylabel('northing [m]') + ax.set_title('blended terrain height') + ax.axis('scaled') + fig.savefig(f'{outdir}/elevation_blended_{case}.png',dpi=150,bbox_inches='tight') + + + # # 6. Shift terrain + # Shifts the terrain data so that the flat borders are at $z=0$ + + # In[37]: + + + if shiftFlatToZero: + zTerrainRef=zblend[0,0] + zblend = zblend - zblend[0,0] + case = case + '_flatz0' + + + # In[38]: + + + if shiftFlatToZero: + fig,ax = plt.subplots(figsize=(12,8)) + cm = ax.pcolormesh(xsurf, ysurf, zblend, cmap='terrain')#,vmin=vmin,vmax=vmax) + cb = fig.colorbar(cm,ax=ax) + cb.set_label('elevation [m]',fontsize='x-large') + ax.tick_params(labelsize='large') + ax.set_xlabel('easting [m]') + ax.set_ylabel('northing [m]') + ax.set_title('shifted terrain height') + ax.axis('scaled') + fig.savefig(f'{outdir}/elevation_blended_{case}.png',dpi=150,bbox_inches='tight') + + + # ## 6. Write out terrain surface STL + stlout = f'{outdir}/terrain.stl' + # output 'zblend' surface - can skip blending step and just output 'zsrtm' + Npts = np.prod(xsurf.shape) + stlpoints = np.stack((xsurf.ravel(), + ysurf.ravel(), + zblend.ravel()), # <-- output surface here + axis=-1) + + stlindices = np.reshape(np.arange(Npts), xsurf.shape) + Nx,Ny = xsurf.shape + Nfaces = (Nx-1)*(Ny-1)*2 + + surf = mesh.Mesh(np.zeros(Nfaces, dtype=mesh.Mesh.dtype)) + iface = 0 + for i in range(Nx-1): + for j in range(Ny-1): + surf.vectors[iface,0,:] = stlpoints[stlindices[i,j],:] + surf.vectors[iface,1,:] = stlpoints[stlindices[i+1,j],:] + surf.vectors[iface,2,:] = stlpoints[stlindices[i+1,j+1],:] + surf.vectors[iface+1,0,:] = stlpoints[stlindices[i+1,j+1],:] + surf.vectors[iface+1,1,:] = stlpoints[stlindices[i,j+1],:] + surf.vectors[iface+1,2,:] = stlpoints[stlindices[i,j],:] + iface += 2 + assert (iface == Nfaces) + #get_ipython().run_cell_magic('time', '', 'Nx,Ny = xsurf.shape\nNfaces = (Nx-1)*(Ny-1)*2\n\nsurf = mesh.Mesh(np.zeros(Nfaces, dtype=mesh.Mesh.dtype))\n\n#\n# manually define triangular faces for this simple quad mesh\n#\n# for iface, f in enumerate(faces):\n# for dim in range(3):\n# surf.vectors[iface][dim] = vertices[f[dim],:]\niface = 0 \nfor i in range(Nx-1):\n for j in range(Ny-1):\n surf.vectors[iface,0,:] = stlpoints[stlindices[i,j],:]\n surf.vectors[iface,1,:] = stlpoints[stlindices[i+1,j],:]\n surf.vectors[iface,2,:] = stlpoints[stlindices[i+1,j+1],:]\n surf.vectors[iface+1,0,:] = stlpoints[stlindices[i+1,j+1],:]\n surf.vectors[iface+1,1,:] = stlpoints[stlindices[i,j+1],:]\n surf.vectors[iface+1,2,:] = stlpoints[stlindices[i,j],:]\n iface += 2\nassert (iface == Nfaces)\n# CPU times: user 27.5 s, sys: 182 ms, total: 27.7 s\n# Wall time: 27.7 s\n') + dpath = os.path.dirname(stlout) + if (not dpath == '') and (not os.path.isdir(dpath)): + os.makedirs(dpath) + print('Created',dpath) + + surf.save(stlout) + # surf.save(stlout, mode=mesh.stl.ASCII) # if ASCII STL is needed + print('Saved',stlout) + print(zblend[0,0]) + return xref,yref,zTerrainRef,srtm + + + + + + diff --git a/tools/terrain/backendInterface.py b/tools/terrain/backendInterface.py new file mode 100644 index 0000000000..e941d29617 --- /dev/null +++ b/tools/terrain/backendInterface.py @@ -0,0 +1,836 @@ +''' +!----------------------------------------------------------------! +AMR - Wind back-end for cases with terrain ! +!----------------------------------------------------------------! +''' + +import yaml +from pathlib import Path +from terrain import SRTM +import numpy as np + + +class amrBackend(): + def __init__(self,yamlFile): + self.yamlFilePath = Path(yamlFile) + self.yamlFile=yaml.safe_load(self.yamlFilePath.open()) + self.createCase() + + def createCase(self): + self.caseParent=self.yamlFile['caseParent'] + self.caseName=self.yamlFile['caseFolder'] + self.caseType=self.yamlFile['caseType'] + self.caseInitial=self.yamlFile['caseInitial'] + caseDir=Path(self.caseParent,self.caseName) + self.caseDir=caseDir.as_posix() + caseDir.mkdir(parents=True,exist_ok=True) + casePrecursor=Path(self.caseParent,self.caseName,"precursor") + self.casePrecursor=casePrecursor.as_posix() + casePrecursor.mkdir(parents=True,exist_ok=True) + if(self.caseType=="terrain"): + caseTerrain=Path(self.caseParent,self.caseName,"terrain") + self.caseTerrain=caseTerrain.as_posix() + caseTerrain.mkdir(parents=True,exist_ok=True) + elif(self.caseType=="terrainTurbine"): + caseTerrain=Path(self.caseParent,self.caseName,"terrainTurbine") + self.caseTerrain=caseTerrain.as_posix() + caseTerrain.mkdir(parents=True,exist_ok=True) + self.caseDomainType=self.yamlFile['domainType'] + # if(self.caseDomainType=="corners"): + # pass + self.caseNorth=self.yamlFile['north'] + self.caseSouth=self.yamlFile['south'] + self.caseEast=self.yamlFile['east'] + self.caseWest=self.yamlFile['west'] + # else: + self.caseCenterLat=self.yamlFile["centerLat"] + self.caseCenterLon=self.yamlFile["centerLon"] + self.refHeight=self.yamlFile["refHeight"] + # self.caseNorth=self.caseCenterLat+self.yamlFile['north'] + # self.caseSouth=self.caseCenterLat-self.yamlFile['south'] + # self.caseEast=self.caseCenterLon+self.yamlFile['east'] + # self.caseWest=self.caseCenterLon-self.yamlFile['west'] + + def createDomain(self): + # bounds = self.caseWest, self.caseSouth, self.caseEast, self.caseNorth + # self.terrainResolution=self.yamlFile['terrainSize'] + # dx = dy = self.terrainResolution + # product = 'SRTM1' + # try: + # tmpName=Path(self.caseParent,self.caseName,"terrain.tif") + # tmpName.unlink() + # print("Deleting file")ß + # except: + # pass + # srtm_output = Path(self.caseParent,self.caseName,"terrain.tif") + # self.srtm = SRTM(bounds,fpath=srtm_output.as_posix(),product=product) + # self.srtm.download() + # x1,x2,x3 = self.srtm.to_terrain(dx,dy) + # self.purgeCorner=self.yamlFile['purgeCorners'] + # cornerCut=self.purgeCorner + #self.terrainX1=x1[cornerCut:x1.shape[0]-cornerCut,cornerCut:x1.shape[1]-cornerCut] + #self.terrainX2=x2[cornerCut:x2.shape[0]-cornerCut,cornerCut:x2.shape[1]-cornerCut] + #self.terrainX3=x3[cornerCut:x3.shape[0]-cornerCut,cornerCut:x3.shape[1]-cornerCut] + import SRTM_to_STL_example as converter + self.xref,self.yref,self.zRef,self.srtm=converter.SRTM_Converter(Path(self.caseParent,self.caseName).as_posix(),self.caseCenterLat,self.caseCenterLon,self.refHeight, \ + self.caseWest,self.caseEast,self.caseSouth,self.caseNorth) + stlFile=Path(self.caseParent,self.caseName,"terrain.stl").as_posix() + import pyvista as pv + mesh=pv.read(stlFile) + x1=mesh.points[:,0] + x2=mesh.points[:,1] + x3=mesh.points[:,2] + self.terrainX1=x1[:] + self.terrainX2=x2[:] + self.terrainX3=x3[:] + #self.zRef=np.amin(self.terrainX3) + #meanZ3=np.mean(self.terrainX3.flatten(order='F')) + #print("Mean Height:",meanZ3) + + def createAMRFiles(self): + self.amrPrecursorFile=Path(self.caseParent,self.caseName,"precursor","precursor.inp").open("w") + self.amrPrecursorFile.write("# Generating the precursor file\n") + self.createPrecursorFiles() + if(self.caseType=='terrain'): + self.amrTerrainFile=Path(self.caseParent,self.caseName,"terrain","terrain.inp").open("w") + self.amrTerrainFile.write("# Generating the terrain file\n") + self.createTerrainFiles("terrain") + self.closeAMRFiles() + elif(self.caseType=='terrainTurbine'): + self.amrTerrainFile=Path(self.caseParent,self.caseName,"terrainTurbine","terrainTurbine.inp").open("w") + self.amrTerrainFile.write("# Generating the terrain file\n") + self.createTerrainFiles("terrainTurbine") + self.closeAMRFiles() + # Turbine files are not properly written + self.createTurbineFiles() + self.plotTurbines() + + def createPrecursorFiles(self): + print("Creating precursor") + self.createAMRGeometry(self.amrPrecursorFile,1) + self.createAMRGrid(self.amrPrecursorFile) + self.createAMRTime(self.amrPrecursorFile) + self.createSolverInfo(self.amrPrecursorFile) + self.createAMRTransport(self.amrPrecursorFile) + self.createAMRTurbulence(self.amrPrecursorFile) + self.createAMRABLData(self.amrPrecursorFile,0,1) + self.createAMRSourceTerm(self.amrPrecursorFile) + self.createAMRBC(self.amrPrecursorFile) + self.createAMRTolerance(self.amrPrecursorFile) + print(" Done creating precursor") + + def createTerrainFiles(self,folder): + print("Creating Terrain Files") + self.createAMRGeometry(self.amrTerrainFile,-1) + self.createAMRGrid(self.amrTerrainFile) + self.createAMRTime(self.amrTerrainFile) + if(self.caseType=='terrainTurbine'): + self.createSolverInfo(self.amrTerrainFile,1,1) + else: + self.createSolverInfo(self.amrTerrainFile,1) + self.createAMRTransport(self.amrTerrainFile) + self.createAMRTurbulence(self.amrTerrainFile) + self.createAMRABLData(self.amrTerrainFile,1,0) + if(self.caseType=='terrainTurbine'): + self.createAMRSourceTerm(self.amrTerrainFile,1,1) + else: + self.createAMRSourceTerm(self.amrTerrainFile,1) + self.createAMRBC(self.amrTerrainFile,1) + self.createAMRTolerance(self.amrTerrainFile,1) + self.writeTerrainData(folder) + self.writeRestart(self.amrTerrainFile) + self.createAMRPrecursorSampling(self.amrPrecursorFile) + # Terrain Monitoring and Refining + self.metMastRefinement(self.amrTerrainFile) + #self.metMastMonitoring(self.amrTerrainFile) + + def createAMRGeometry(self,target,periodic=-1): + target.write("# Geometry\n") + minX=np.amin(self.terrainX1) + minY=np.amin(self.terrainX2) + minZ=np.amin(self.terrainX3) + maxX=np.amax(self.terrainX1) + maxY=np.amax(self.terrainX2) + terrainZMax=np.amax(self.terrainX3) + # Add 3 km for Rayleigh + maxZ=terrainZMax+2000+3000 + target.write("geometry.prob_lo \t\t\t = %g %g %g \n"%(minX,minY,minZ)) + target.write("geometry.prob_hi \t\t\t = %g %g %g \n"%(maxX,maxY,maxZ)) + if(periodic==1): + target.write("geometry.is_periodic \t\t\t = 1 1 0\n") + else: + target.write("geometry.is_periodic \t\t\t = 0 0 0\n") + + def createAMRGrid(self,target): + self.caseCellSize=self.yamlFile['cellSize'] + nx=int((np.amax(self.terrainX1)-np.amin(self.terrainX1))/self.caseCellSize) + while (nx%8 !=0): + nx=nx+1 + ny=int((np.amax(self.terrainX2)-np.amin(self.terrainX2))/self.caseCellSize) + while (ny%8 !=0): + ny=ny+1 + # Keeping the vertical height to account for gravity waves + terrainZMax=np.amax(self.terrainX3) + # Add 3 km for Rayleigh + zDomainHeight=terrainZMax+2000+3000 + print("Terrain Maximum Height:",terrainZMax) + print("Domain Height:",zDomainHeight) + self.caseverticalAR=self.yamlFile['verticalAR'] + nz=self.caseverticalAR*int(zDomainHeight/self.caseCellSize) + while (nz%8 !=0): + nz=nz+1 + print("dx,dz",self.caseCellSize,zDomainHeight/nz) + target.write("# Grid \n") + target.write("amr.n_cell \t\t\t = %g %g %g\n"%(nx,ny,nz)) + target.write("amr.max_level \t\t\t = 0\n") + + def createAMRTime(self,target): + self.timeMethod=self.yamlFile['timeMethod'] + if(self.timeMethod=="step"): + self.timeSteps=self.yamlFile["numOfSteps"] + else: + pass # Need to add parameters for physical time + self.plotOutput=self.yamlFile['plotOutput'] + self.restartOutput=self.yamlFile['restartOutput'] + target.write("time.stop_time \t\t\t = -1\n") + target.write("time.max_step \t\t\t = %g\n"%(self.timeSteps)) + target.write("time.initial_dt \t\t\t = 0.1\n") + target.write("time.fixed_dt \t\t\t = -1\n") + target.write("time.cfl \t\t\t = 0.9\n") + target.write('time.plot_interval \t\t\t = %g\n'%(self.plotOutput)) + target.write("time.checkpoint_interval \t\t\t = %g\n"%(self.restartOutput)) + + def createSolverInfo(self,target,terrain=-1,turbine=-1): + self.caseWindspeedX=self.yamlFile['windX'] + self.caseWindspeedY=self.yamlFile['windY'] + self.caseWindspeedZ=self.yamlFile['windZ'] + target.write("# incflo \n") + if(terrain==1 and turbine==1): + target.write("incflo.physics \t\t\t = ABL TerrainDrag Actuator\n") + elif(terrain==1): + target.write("incflo.physics \t\t\t = ABL TerrainDrag\n") + elif(turbine==1): + target.write("incflo.physics \t\t\t = ABL Actuator\n") + else: + target.write("incflo.physics \t\t\t = ABL\n") + target.write("incflo.density \t\t\t = 1.225\n") + target.write("incflo.gravity \t\t\t = 0. 0. -9.81 # Gravitational force (3D)\n") + target.write("incflo.velocity \t\t\t = %g %g %g \n"%(self.caseWindspeedX,self.caseWindspeedY,self.caseWindspeedZ)) + target.write("incflo.verbose \t\t\t = 0\n") + target.write("incflo.initial_iterations \t\t\t = 8\n") + target.write("incflo.do_initial_proj \t\t\t = true\n") + target.write("incflo.constant_density \t\t\t = true\n") + target.write("incflo.use_godunov \t\t\t = true\n") + target.write('incflo.godunov_type \t\t\t = "weno_z"\n') + target.write("incflo.diffusion_type \t\t\t = 2\n") + + def createAMRTransport(self,target): + target.write("# transport equation parameters \n") + target.write("transport.model \t\t\t = ConstTransport\n") + target.write("transport.viscosity \t\t\t = 1e-5\n") + target.write("transport.laminar_prandtl \t\t\t = 0.7\n") + target.write("transport.turbulent_prandtl \t\t\t = 0.333\n") + + def createAMRTurbulence(self,target): + target.write("# turbulence equation parameters \n") + target.write("turbulence.model \t\t\t = Kosovic\n") + target.write("Kosovic.refMOL \t\t\t = -1e30\n") + + def createAMRABLData(self,target,iomode=-1,fluctuations=1): + self.refTemperature=self.yamlFile["refTemperature"] + self.refRoughness=self.yamlFile["refRoughness"] + self.refHeatFlux=self.yamlFile["refHeatflux"] + target.write("# Atmospheric boundary layer\n") + if(fluctuations==1): + UPeriod=int((np.amax(self.terrainX1)-np.amin(self.terrainX1))/200) + VPeriod=int((np.amax(self.terrainX1)-np.amin(self.terrainX1))/200) + target.write("ABL.Uperiods \t\t\t = %g\n"%(UPeriod)) + target.write("ABL.Vperiods \t\t\t = %g\n"%(VPeriod)) + target.write("ABL.cutoff_height \t\t\t = 50.0\n") + target.write("ABL.deltaU \t\t\t = 1.0\n") + target.write("ABL.deltaV \t\t\t = 1.0\n") + target.write("ABL.perturb_ref_height \t\t\t = 50.0\n") + target.write("ABL.perturb_velocity \t\t\t = true\n") + target.write("ABL.perturb_temperature \t\t\t = false\n") + target.write("ABL.kappa \t\t\t = .41\n") + target.write("ABL.normal_direction \t\t\t = 2\n") + target.write("ABL.reference_temperature \t\t\t = %g\n"%(self.refTemperature)) + target.write("ABL.stats_output_format \t\t\t = netcdf\n") + target.write("ABL.surface_roughness_z0 \t\t\t = %g\n"%(self.refRoughness)) + # Write Heights + target.write("ABL.temperature_heights = 0 ") #750 850 1850 2850 3850 4850\n") + invLayer=750 + target.write(" %g %g "%(np.amax(self.terrainX3),np.amax(self.terrainX3)+invLayer)) + invLayerWidth=100 + target.write(" %g "%(np.amax(self.terrainX3)+invLayer+invLayerWidth)) + zstart=np.amax(self.terrainX3)+invLayer+invLayerWidth+1000 + while(zstart<10000): + target.write(" %g "%(zstart)) + zstart+=1000 + #target.write("ABL.temperature_values \t\t\t = 300 300 308 311 314 317 321\n") + target.write("\n") + TRef=300 + target.write("ABL.temperature_values = %g "%(TRef)) + invLayer=750 + target.write(" %g %g "%(TRef,TRef)) + invStrength=8 + target.write(" %g "%(TRef+invStrength)) + zstart=np.amax(self.terrainX3)+invLayer+invLayerWidth+1000 + lapseRate=3.0 # Per km + TRef=TRef+invStrength+lapseRate + zstart=np.amax(self.terrainX3)+invLayer+invLayerWidth+1000 + while(zstart<10000): + target.write(" %g "%(TRef)) + zstart+=1000 + TRef+=3 + target.write("\n") + target.write("ABL.wall_shear_stress_type \t\t\t = local\n") + target.write("ABL.surface_temp_flux \t\t\t = %g\n"%(self.refHeatFlux)) + if(iomode==0): + target.write('ABL.bndry_file \t\t\t = "bndry_files"\n') + target.write("ABL.bndry_write_frequency \t\t\t = 100\n") + target.write("ABL.bndry_io_mode \t\t\t = 0\n") + if(self.caseWindspeedX>=0 and self.caseWindspeedY>=0): + target.write("ABL.bndry_planes \t\t\t = xlo ylo \n") + elif(self.caseWindspeedX>=0 and self.caseWindspeedY<0): + target.write("ABL.bndry_planes \t\t\t = xlo yhi \n") + if(self.caseWindspeedX<0 and self.caseWindspeedY>=0): + target.write("ABL.bndry_planes \t\t\t = xhi ylo \n") + elif(self.caseWindspeedX<0 and self.caseWindspeedY<0): + target.write("ABL.bndry_planes \t\t\t = xhi yhi \n") + # Guessing a start time far enough + M=np.sqrt(self.caseWindspeedX**2+self.caseWindspeedY**2) + dt=0.9*self.caseCellSize/M + startTime=0.25*(self.timeSteps/dt) + target.write("ABL.bndry_output_start_time \t\t\t = %g\n"%(startTime)) + target.write("ABL.bndry_var_names \t\t\t = velocity temperature\n") + target.write("ABL.bndry_output_format \t\t\t = native\n") + elif(iomode==1): + target.write('ABL.bndry_file \t\t\t = "../precursor/bndry_files"\n') + target.write("ABL.bndry_io_mode \t\t\t = 1\n") + target.write("ABL.bndry_var_names \t\t\t = velocity temperature\n") + target.write("ABL.bndry_output_format \t\t\t = native\n") + + def createAMRSourceTerm(self,target,terrain=-1,turbine=-1): + target.write("# Source\n") + refLat=self.yamlFile["refLat"] + refPeriod=self.yamlFile["refPeriod"] + if(terrain==1 and turbine==1): + target.write("ICNS.source_terms \t\t\t = BoussinesqBuoyancy CoriolisForcing GeostrophicForcing RayleighDamping NonLinearSGSTerm DragForcing ActuatorForcing \n") + elif(terrain==1): + target.write("ICNS.source_terms \t\t\t = BoussinesqBuoyancy CoriolisForcing GeostrophicForcing RayleighDamping NonLinearSGSTerm DragForcing\n") + else: + target.write("ICNS.source_terms \t\t\t = BoussinesqBuoyancy CoriolisForcing GeostrophicForcing RayleighDamping NonLinearSGSTerm\n") + target.write("BoussinesqBuoyancy.reference_temperature \t\t\t = %g\n"%(self.refTemperature)) + target.write("BoussinesqBuoyancy.thermal_expansion_coeff \t\t\t = %g\n"%(1.0/self.refTemperature)) + target.write("CoriolisForcing.east_vector \t\t\t = 1.0 0.0 0.0 \n") + target.write("CoriolisForcing.north_vector \t\t\t = 0.0 1.0 0.0 \n") + target.write("CoriolisForcing.latitude \t\t\t = %g \n"%(refLat)) + target.write("CoriolisForcing.rotational_time_period \t\t\t = %g \n"%(refPeriod)) + target.write("GeostrophicForcing.geostrophic_wind \t\t\t = %g %g %g\n"%(self.caseWindspeedX,self.caseWindspeedY,self.caseWindspeedZ)) + target.write("RayleighDamping.reference_velocity \t\t\t = %g %g %g\n"%(self.caseWindspeedX,self.caseWindspeedY,self.caseWindspeedZ)) + target.write("RayleighDamping.length_sloped_damping \t\t\t = 500\n") + target.write("RayleighDamping.length_complete_damping \t\t\t = 2500\n") + target.write("RayleighDamping.time_scale \t\t\t = 20.0\n") + + def createAMRBC(self,target,inflowOutflow=-1): + target.write("# BC \n") + if(inflowOutflow==1): + if(self.caseWindspeedX>=0): + target.write('xlo.type \t\t\t = "mass_inflow"\n') + target.write("xlo.density \t\t\t = 1.225\n") + target.write("xlo.temperature \t\t\t = 300\n") + target.write('xhi.type \t\t\t = "pressure_outflow"\n') + else: + target.write('xhi.type \t\t\t = "mass_inflow"\n') + target.write("xhi.density \t\t\t = 1.225\n") + target.write("xhi.temperature \t\t\t = 300\n") + target.write('xlo.type \t\t\t = "pressure_outflow"\n') + if(self.caseWindspeedY>=0): + target.write('ylo.type \t\t\t = "mass_inflow"\n') + target.write("ylo.density \t\t\t = 1.225\n") + target.write("ylo.temperature \t\t\t = 300\n") + target.write('yhi.type \t\t\t = "pressure_outflow"\n') + else: + target.write('yhi.type \t\t\t = "mass_inflow"\n') + target.write("yhi.density \t\t\t = 1.225\n") + target.write("yhi.temperature \t\t\t = 300\n") + target.write('ylo.type \t\t\t = "pressure_outflow"\n') + target.write('zhi.type \t\t\t = "slip_wall"\n') + target.write('zhi.temperature_type \t\t\t = "fixed_gradient"\n') + target.write("zhi.temperature \t\t\t = 0.003\n") + target.write('zlo.type \t\t\t = "wall_model"\n') + + def createAMRTolerance(self,target,modify=-1): + #if(modify==1): + if(self.caseverticalAR==3 or self.caseverticalAR==4): + self.smoothing=8 + elif(self.caseverticalAR>4 and self.caseverticalAR<=8): + self.smoothing=16 + elif(self.caseverticalAR>8 and self.caseverticalAR<=16): + self.smoothing=64 + if(self.caseverticalAR>=3): + target.write("mac_proj.num_pre_smooth \t\t\t = %g \n"%(self.smoothing)) + target.write("mac_proj.num_post_smooth \t\t\t = %g \n"%(self.smoothing)) + target.write("mac_proj.mg_rtol \t\t\t = 1.0e-4 \n") + target.write("mac_proj.mg_atol \t\t\t = 1.0e-8 \n") + target.write("mac_proj.maxiter \t\t\t = 360 \n") + if(self.caseverticalAR>=3): + target.write("nodal_proj.num_pre_smooth \t\t\t = %g \n"%(self.smoothing)) + target.write("nodal_proj.num_post_smooth \t\t\t = %g \n"%(self.smoothing)) + target.write("nodal_proj.mg_rtol \t\t\t = 1.0e-4 \n") + target.write("nodal_proj.mg_atol \t\t\t = 1.0e-8 \n") + target.write("diffusion.mg_rtol \t\t\t = 1.0e-6 \n") + target.write("diffusion.mg_atol \t\t\t = 1.0e-8 \n") + target.write("temperature_diffusion.mg_rtol \t\t\t = 1.0e-6 \n") + target.write("temperature_diffusion.mg_atol \t\t\t = 1.0e-8 \n") + target.write("nodal_proj.maxiter \t\t\t = 360 \n") + + def createAMRPrecursorSampling(self,target): + pass + # x1=self.terrainX1.flatten(order='F') + # x2=self.terrainX2.flatten(order='F') + # x3=self.terrainX3.flatten(order='F') + # target.write("# Cloud \n") + # target.write("sampling.labels \t\t\t = height80m \n") + # target.write("sampling.height80m.type \t\t\t = ProbeSampler \n") + # target.write('sampling.height80m.probe_location_file \t\t\t = "height80m.txt" \n') + # height80File=Path(self.caseParent,self.caseName,"precursor","height80m.txt").open("w") + # height80File.write("%g\n"%(len(self.smoothTerrainX1))) + # for i in range(0,len(self.terrainX1)): + # height80File.write("%g %g %g \n"%(self.smoothTerrainX1[i],self.smoothTerrainX2[i],self.smoothTerrainX3[i]+80)) + # height80File.close() + + def metMastRefinement(self,target): + # Read Met Mast + latList=self.yamlFile['metMastLat'] + lonList=self.yamlFile['metMastLon'] + metMastHeight=self.yamlFile['metMastHeight'] + print(latList,len(latList)) + xref=[] + yref=[] + zlower=[] + zmast=[] + for i in range(0,len(latList)): + if(i==0): + target.write("tagging.labels = metMastGrid1%g metMastGrid2%g metMastGrid3%g "%(i+1,i+1,i+1)) + else: + target.write(" metMastGrid1%g metMastGrid2%g metMastGrid3%g "%(i+1,i+1,i+1)) + xtemp,ytemp=self.srtm.to_xy(latList[i],lonList[i]) + print(xtemp,ytemp) + xref.append(xtemp-self.xref) + yref.append(ytemp-self.yref) + zmast.append(metMastHeight[i]-self.zRef) + target.write("\n") + print(xref,self.xref) + print(yref,self.yref) + # Now Write Refinemements + import pyvista as pv + for i in range(0,len(latList)): + xstart=xref[i]-4000 + ystart=yref[i]-4000 + zstart=self.interp(xref[i],yref[i]) + zdist=zmast[i]-zstart + print(zmast[i],zstart,zdist,self.zRef) + target.write("tagging.metMastGrid1%g.type \t\t\t = GeometryRefinement\n"%(i+1)) + target.write("tagging.metMastGrid1%g.shapes \t\t\t = metMast%g\n"%(i+1,i+1)) + target.write("tagging.metMastGrid1%g.level \t\t\t = 0\n"%(i+1)) + target.write("tagging.metMastGrid1%g.metMastGrid1%g.type \t\t\t = box\n"%(i+1,i+1)) + target.write("tagging.metMastGrid1%g.metMastGrid1%g.origin = %g %g %g \n"%(i+1,i+1,xstart,ystart,zstart-64)) + target.write("tagging.metMastGrid1%g.metMastGrid1%g.xaxis = %g %g %g\n"%(i+1,i+1,8000,0,0)) + target.write("tagging.metMastGrid1%g.metMastGrid1%g.yaxis = %g %g %g\n"%(i+1,i+1,0,8000,0)) + target.write("tagging.metMastGrid1%g.metMastGrid1%g.zaxis = %g %g %g\n"%(i+1,i+1,0,0,zdist+400)) + xstart=xref[i]-2000 + ystart=yref[i]-2000 + target.write("tagging.metMastGrid2%g.type \t\t\t = GeometryRefinement\n"%(i+1)) + target.write("tagging.metMastGrid2%g.shapes \t\t\t = metMastGrid2%g\n"%(i+1,i+1)) + target.write("tagging.metMastGrid2%g.min_level \t\t\t = 0\n"%(i+1)) + target.write("tagging.metMastGrid2%g.max_level \t\t\t = 1\n"%(i+1)) + target.write("tagging.metMastGrid2%g.metMastGrid2%g.type \t\t\t = box\n"%(i+1,i+1)) + target.write("tagging.metMastGrid2%g.metMastGrid2%g.origin = %g %g %g \n"%(i+1,i+1,xstart,ystart,zstart-32)) + target.write("tagging.metMastGrid2%g.metMastGrid2%g.xaxis = %g %g %g\n"%(i+1,i+1,4000,0,0)) + target.write("tagging.metMastGrid2%g.metMastGrid2%g.yaxis = %g %g %g\n"%(i+1,i+1,0,4000,0)) + target.write("tagging.metMastGrid2%g.metMastGrid2%g.zaxis = %g %g %g\n"%(i+1,i+1,0,0,zdist+200)) + xstart=xref[i]-1000 + ystart=yref[i]-1000 + target.write("tagging.metMastGrid3%g.type \t\t\t = GeometryRefinement\n"%(i+1)) + target.write("tagging.metMastGrid3%g.shapes \t\t\t = metMastGrid3%g\n"%(i+1,i+1)) + target.write("tagging.metMastGrid3%g.min_level \t\t\t = 0\n"%(i+1)) + target.write("tagging.metMastGrid3%g.max_level \t\t\t = 2\n"%(i+1)) + target.write("tagging.metMastGrid3%g.metMastGrid3%g.type \t\t\t = box\n"%(i+1,i+1)) + target.write("tagging.metMastGrid3%g.metMastGrid3%g.origin = %g %g %g \n"%(i+1,i+1,xstart,ystart,zstart-16)) + target.write("tagging.metMastGrid3%g.metMastGrid3%g.xaxis = %g %g %g\n"%(i+1,i+1,2000,0,0)) + target.write("tagging.metMastGrid3%g.metMastGrid3%g.yaxis = %g %g %g\n"%(i+1,i+1,0,2000,0)) + target.write("tagging.metMastGrid3%g.metMastGrid3%g.zaxis = %g %g %g\n"%(i+1,i+1,0,0,zdist+100)) + # Write Boxes + mesh1=pv.Box(bounds=(xref[i]-4000,xref[i]+4000,yref[i]-4000,yref[i]+4000,zstart-64,zstart+zdist+400)) + fileName=Path(self.caseParent,self.caseName,"metMastGrid1"+str(i+1)+".vtk").as_posix() + mesh1.save(fileName) + mesh1=pv.Box(bounds=(xref[i]-2000,xref[i]+2000,yref[i]-2000,yref[i]+2000,zstart-32,zstart+zdist+200)) + fileName=Path(self.caseParent,self.caseName,"metMastGrid2"+str(i+1)+".vtk").as_posix() + mesh1.save(fileName) + mesh1=pv.Box(bounds=(xref[i]-1000,xref[i]+1000,yref[i]-1000,yref[i]+1000,zstart-16,zstart+zdist+100)) + fileName=Path(self.caseParent,self.caseName,"metMastGrid2"+str(i+1)+".vtk").as_posix() + mesh1.save(fileName) + + def closeAMRFiles(self): + self.amrPrecursorFile.close() + try: + self.amrTerrainFile.close() + except: + pass + + def writeTerrainData(self,folder): + print("Writing Terrain Data") + x1=self.terrainX1.flatten(order='F') + x2=self.terrainX2.flatten(order='F') + x3=self.terrainX3.flatten(order='F') + x=np.arange(np.amin(x1),np.amax(x1),self.caseCellSize) + y=np.arange(np.amin(x2),np.amax(x2),self.caseCellSize) + from scipy.interpolate import NearestNDInterpolator + self.interp = NearestNDInterpolator(list(zip(x1,x2)),x3) + xterrain,yterrain=np.meshgrid(x,y) + zterrain = self.interp(xterrain,yterrain) + import matplotlib.pylab as plt + plt.contourf(xterrain,yterrain,zterrain) + x1=xterrain.flatten(order='F') + x2=yterrain.flatten(order='F') + x3=zterrain.flatten(order='F') + target=Path(self.caseParent,self.caseName,folder,"terrain.amrwind").open("w") + for i in range(0,len(x1)): + target.write("%g %g %g\n"%(x1[i],x2[i],x3[i])) + target.close() + data=np.column_stack([x1,x2,x3]) + import pyvista as pv + mesh=pv.PolyData(data) + mesh['elevation']=data[:,2] + mesh.save(Path(self.caseParent,self.caseName,folder,"terrainPoints.vtk").as_posix()) + #xterrain,yterrain=np.meshgrid(x,y) + # for i in range(0,xterrain.shape[0]): + # for j in range(0,xterrain.shape[1]): + # error=100000000 + # for k in range(0,len(x1)): + # error=np.sqrt((xterrain[i,j]-x1[k])**2+(yterrain[i,j]-x2[k])**2) + # if(errorxmin and lat[i]ymin and lon[i]0): + distance=tempDistance + if(distance0.25*xmin and xc<0.75*xmax and yc>0.25*ymin and yc<0.75*ymax): +# smoothData.points[i]=mesh.points[i] +# tempmesh=smoothData +# print("Bounds:",bounds) +# smoothData.save("smoothTerrain.vtk") +# #smoothData=mesh +# target=open("terrain.amrwind","w") +# for i in range(0,data.shape[0]): +# target.write("%g %g %g\n"%(smoothData.points[i,0],smoothData.points[i,1],smoothData.points[i,2]-np.amin(smoothData.points[i,2]))) +# target.close() diff --git a/tools/terrain/terrain.py b/tools/terrain/terrain.py new file mode 100644 index 0000000000..d5dc2c090b --- /dev/null +++ b/tools/terrain/terrain.py @@ -0,0 +1,884 @@ +""" +Tools for working with terrain + +Notes +----- +For SRTM data download (in GeoTIFF (.tif) format: +- install with `conda install -c conda-forge gdal` or `pip install gdal` +- install with `conda install -c conda-forge elevation` or `pip install elevation` +- check with `eio selfcheck` + +For processing downloaded GeoTIFF data: +- install with `conda install -c conda-forge rasterio` or `pip install rasterio` +- note: like the elevation package, this also depends on gdal +""" +import sys,os,glob +import numpy as np +import xarray as xr +from scipy.interpolate import RectBivariateSpline, griddata + +import elevation +import rasterio +from rasterio import transform, warp +from rasterio.crs import CRS + +# hard-coded here because ElementTree doesn't appear to have any +# straightforward way to access the xmlns root attributes +ISO_namespace = { + 'gmd': 'http://www.isotc211.org/2005/gmd', + 'gco': 'http://www.isotc211.org/2005/gco', +} + + +class Terrain(object): + + latlon_crs = CRS.from_dict(init='epsg:4326') + + def __init__(self,latlon_bounds,fpath='terrain.tif'): + """Create container for manipulating GeoTIFF data in the + specified region + + Usage + ===== + latlon_bounds : list or tuple + Latitude/longitude corresponding to west, south, east, and + north bounds, used to define the source transformation. + fpath : str, optional + Where to save downloaded GeoTIFF (*.tif) data. + """ + self.bounds = list(latlon_bounds) + self._get_utm_crs() # from bounds + self.tiffdata = fpath + self.have_terrain = False + if not hasattr(self,'have_metadata'): + # set attribute if it hasn't been set already + self.have_metadata = False + + def _get_utm_crs(self,datum='WGS84',ellps='WGS84'): + """Get coordinate system from zone number associated with the + longitude of the northwest corner + + Parameters + ========== + datum : str, optional + Origin of destination coordinate system, used to describe + PROJ.4 string; default is WGS84. + ellps : str, optional + Ellipsoid defining the shape of the earth in the destination + coordinate system, used to describe PROJ.4 string; default + is WGS84. + """ + #west, south, east, north = self.bounds + self.zone_number = int((self.bounds[0] + 180) / 6) + 1 + proj = '+proj=utm +zone={:d} '.format(self.zone_number) \ + + '+datum={:s} +units=m +no_defs '.format(datum) \ + + '+ellps={:s} +towgs84=0,0,0'.format(ellps) + self.utm_crs = CRS.from_proj4(proj) + + def _get_bounds_from_metadata(self): + """This is a stub""" + assert self.have_metadata + raise NotImplementedError() + + def to_terrain(self,dx,dy=None,resampling=warp.Resampling.bilinear): + """Load geospatial raster data and reproject onto specified grid + + Usage + ===== + dx,dy : float + Grid spacings [m]. If dy is not specified, then uniform + spacing is assumed. + resampling : warp.Resampling value, optional + See `list(warp.Resampling)`. + """ + if dy is None: + dy = dx + + # load raster + if not os.path.isfile(self.tiffdata): + raise FileNotFoundError('Need to download()') + dem_raster = rasterio.open(self.tiffdata) + + # get source coordinate reference system, transform + west, south, east, north = self.bounds + src_height, src_width = dem_raster.shape + src_crs = dem_raster.crs + src_transform = transform.from_bounds(*self.bounds, src_width, src_height) + src = dem_raster.read(1) + + # calculate destination coordinate reference system, transform + dst_crs = self.utm_crs + print('Projecting from',src_crs,'to',dst_crs) + # - get origin (the _upper_ left corner) from bounds + orix,oriy = self.to_xy(north,west) + origin = (orix, oriy) + self.origin = origin + dst_transform = transform.from_origin(*origin, dx, dy) + # - get extents from lower right corner + SE_x,SE_y = self.to_xy(south,east) + Lx = SE_x - orix + Ly = oriy - SE_y + Nx = int(Lx / dx) + Ny = int(Ly / dy) + + # reproject to uniform grid in the UTM CRS + dem_array = np.empty((Ny, Nx)) + warp.reproject(src, dem_array, + src_transform=src_transform, src_crs=src_crs, + dst_transform=dst_transform, dst_crs=dst_crs, + resampling=resampling) + utmx = orix + np.arange(0, Nx*dx, dx) + utmy = oriy + np.arange((-Ny+1)*dy, dy, dy) + self.x,self.y = np.meshgrid(utmx,utmy,indexing='ij') + self.z = np.flipud(dem_array).T + + self.zfun = RectBivariateSpline(utmx,utmy,self.z) + self.have_terrain = True + + return self.x, self.y, self.z + + def to_latlon(self,x,y): + """Transform uniform grid to lat/lon space""" + if not hasattr(x, '__iter__'): + assert ~hasattr(x, '__iter__') + x = [x] + y = [y] + xlon, xlat = warp.transform(self.utm_crs, + self.latlon_crs, + x, y) + try: + shape = x.shape + except AttributeError: + xlat = xlat[0] + xlon = xlon[0] + else: + xlat = np.reshape(xlat, shape) + xlon = np.reshape(xlon, shape) + return xlat,xlon + + def to_xy(self,lat,lon,xref=None,yref=None): + """Transform lat/lon to UTM space""" + if not hasattr(lat, '__iter__'): + assert ~hasattr(lat, '__iter__') + lat = [lat] + lon = [lon] + x,y = warp.transform(self.latlon_crs, + self.utm_crs, + lon, lat) + try: + shape = lon.shape + except AttributeError: + x = x[0] + y = y[0] + else: + x = np.reshape(x, shape) + y = np.reshape(y, shape) + if xref is not None: + x -= xref + if yref is not None: + y -= yref + return x,y + + def xtransect(self,xy=None,latlon=None,wdir=270.0,xrange=(None,None)): + """Get terrain transect along x for a slice aligned with the + specified wind direction and going through a specified reference + point (defined by xy or latlon) + + Usage + ===== + xy : list or tuple + Reference location in the UTM coordinate reference system [m] + latlon : list-like + Reference location in latitude and longitude [deg] + wdir : float + Wind direction with which the slice is aligned [deg] + xrange : list or tuple, optional + Range of x values over which slice (or None to use min/max) + """ + assert self.have_terrain, 'Need to call to_terrain()' + assert ((xy is not None) ^ (latlon is not None)), 'Specify xy or latlon' + if xy: + refloc = xy + elif latlon: + x,y = self.to_xy(*latlon) + refloc = (x,y) + ang = 270 - wdir + print('Slice through',refloc,'at',ang,'deg') + ang *= np.pi/180. + + # direction specific code + imin = 0 if (xrange[0] is None) else np.where(self.x <= xrange[0])[0][-1] + imax = None if (xrange[1] is None) else np.where(self.x > xrange[1])[0][0] + x = self.x[imin:imax,0] + y = np.tan(ang) * (x-refloc[0]) + refloc[1] + z = self.zfun(x,y,grid=False) + + return x-refloc[0], z + + def ytransect(self,xy=None,latlon=None,wdir=180.0,yrange=(None,None)): + """Get terrain transect along x for a slice aligned with the + specified wind direction and going through a specified reference + point (defined by xy or latlon) + + Usage + ===== + xy : list or tuple + Reference location in the UTM coordinate reference system [m] + latlon : list-like + Reference location in latitude and longitude [deg] + wdir : float + Wind direction with which the slice is aligned [deg] + xrange : list or tuple, optional + Range of x values over which slice (or None to use min/max) + """ + assert self.have_terrain, 'Need to call to_terrain()' + assert ((xy is not None) ^ (latlon is not None)), 'Specify xy or latlon' + if xy: + refloc = xy + elif latlon: + x,y = self.to_xy(*latlon) + refloc = (x,y) + ang = 180 - wdir + print('Slice through',refloc,'at',ang,'deg') + ang *= np.pi/180. + + # direction specific code + jmin = 0 if (yrange[0] is None) else np.where(self.y <= yrange[0])[1][-1] + jmax = None if (yrange[1] is None) else np.where(self.y > yrange[1])[1][0] + y = self.y[0,jmin:jmax] + x = refloc[0] - np.tan(ang) * (y-refloc[1]) + z = self.zfun(x,y,grid=False) + + return y-refloc[1], z + + +class SRTM(Terrain): + """Class for working with Shuttle Radar Topography Mission (SRTM) data""" + data_products = { + 'SRTM1': 30.0, + 'SRTM3': 90.0, + } + + def __init__(self,latlon_bounds,fpath='terrain.tif',product='SRTM3', + margin=0.05): + """Create container for SRTM data in the specified region + + Usage + ===== + latlon_bounds : list or tuple + Latitude/longitude corresponding to west, south, east, and + north bounds, used to define the source transformation. + fpath : str, optional + Where to save downloaded GeoTIFF (*.tif) data. + product : str, optional + Data product name, SRTM1 or SRTM3 (corresponding to 30- and + 90-m DEM). + margin : float, optional + Decimal degree margin added to the bounds (default is 3") + when clipping the downloaded elevation data. + """ + latlon_bounds = list(latlon_bounds) + if margin is not None: + latlon_bounds[0] -= margin + latlon_bounds[1] -= margin + latlon_bounds[2] += margin + latlon_bounds[3] += margin + super().__init__(latlon_bounds,fpath=fpath) + assert (product in self.data_products.keys()), \ + 'product should be one of '+str(list(self.data_products.keys())) + self.product = product + self.margin = margin + + def download(self,cleanup=True): + """Download the SRTM data in GeoTIFF format""" + dpath = os.path.dirname(self.tiffdata) + if not os.path.isdir(dpath): + print('Creating path',dpath) + os.makedirs(dpath) + escapedpath = self.tiffdata.replace('\ ',' ').replace(' ','\ ') + try: + elevation.clip(self.bounds, product=self.product, output=escapedpath) + except: + info = sys.exc_info() + print(info[0]) + print(info[1]) + print('') + print('Note: Have elevation and gdal been installed properly?') + if cleanup: + elevation.clean() + + def to_terrain(self,dx=None,dy=None,resampling=warp.Resampling.bilinear): + """Load geospatial raster data and reproject onto specified grid + + Usage + ===== + dx,dy : float + Grid spacings [m]. If dy is not specified, then uniform + spacing is assumed. + resampling : warp.Resampling value, optional + See `list(warp.Resampling)`. + """ + if dx is None: + dx = self.data_products[self.product] + print('Output grid at ds=',dx) + if dy is None: + dy = dx + return super().to_terrain(dx, dy=dy, resampling=resampling) + + +class USGS(Terrain): + """Class for working with the US Geological Survey's 3D Elevation + Program (3DEP). Note that there is no API so the tif data must be + manually downloaded from the USGS. + """ + + def __init__(self,latlon_bounds=None,fpath='terrain.tif'): + """Create container for 3DEP data in the specified region + + Usage + ===== + latlon_bounds : list or tuple, optional + Latitude/longitude corresponding to west, south, east, and + north bounds, used to define the source transformation. If + not specified, then it will be read from a metadata file + with the same name. + fpath : str + Location of downloaded GeoTIFF (*.tif) data. + """ + self._read_metadata(fpath) + if latlon_bounds is None: + latlon_bounds = self._get_bounds_from_metadata() + print('Bounds:',latlon_bounds) + super().__init__(latlon_bounds,fpath=fpath) + + def _read_metadata(self,fpath): + from xml.etree import ElementTree + xmlfile = os.path.splitext(fpath)[0] + '.xml' + try: + metadata = ElementTree.parse(xmlfile).getroot() + except IOError: + self.have_metadata = False + else: + if not metadata.tag.endswith('MD_Metadata'): + assert metadata.tag in ['metadata','gmd:MD_Metadata','modsCollection'] + if metadata.tag == 'metadata': + # legacy metadata + print('Source CRS datum:',metadata.find('./spref/horizsys/geodetic/horizdn').text) + elif metadata.tag == 'modsCollection': + # MODS XML + print(metadata.find('./mods/titleInfo/title').text) + raise NotImplementedError('MODS XML detected -- use ISO XML instead') + else: + # ISO XML + title = metadata.find( + '/'.join([ + 'gmd:identificationInfo', + 'gmd:MD_DataIdentification', + 'gmd:citation', + 'gmd:CI_Citation', + 'gmd:title', + 'gco:CharacterString', + ]), + ISO_namespace + ).text + print(title) + self.have_metadata = True + self.metadata = metadata + + def _get_bounds_from_metadata(self): + assert self.have_metadata + if self.metadata.tag == 'metadata': + # legacy metadata + bounding = self.metadata.find('./idinfo/spdom/bounding') + bounds = [ + float(bounding.find(bcdir+'bc').text) + for bcdir in ['west','south','east','north'] + ] + else: + # ISO XML + extent = self.metadata.find( + 'gmd:identificationInfo/gmd:MD_DataIdentification/gmd:extent', + ISO_namespace + ) + bbox = extent.find( + 'gmd:EX_Extent/gmd:geographicElement/gmd:EX_GeographicBoundingBox', + ISO_namespace + ) + bounds = [ + float(bbox.find(f'gmd:{bound}/gco:Decimal',ISO_namespace).text) + for bound in [ + 'westBoundLongitude', + 'southBoundLatitude', + 'eastBoundLongitude', + 'northBoundLatitude', + ] + ] + return bounds + + def download(self): + """This is just a stub""" + print('Data must be manually downloaded!') + print('Go to https://apps.nationalmap.gov/downloader/#/,') + print('select "Data > Elevation Products (3DEP)"') + print('and then click "Find Products"') + + +def combine_raster_data(filelist,dtype=Terrain,latlon_bounds=None, + output='output.tif'): + """Combine multiple raster datasets into a single GeoTIFF file + + Usage + ===== + filelist : list or glob str + List of downloaded GeoTIFF (*.tif) data. + dtype : Terrain or derived class, optional + Used to provide helper functions if needed. + latlon_bounds : list of (list or tuple), optional + Each list or tuple of latitude/longitude corresponds to west, + south, east, and north bounds, and are used to define the bounds + of the combined raster. If not specified, then try to read these + bounds from metadata. + output : str + Location of combined GeoTIFF (*.tif) data. + """ + if not isinstance(filelist, list): + filelist = glob.glob(filelist) + print('Files:',filelist) + assert len(filelist) > 1, 'Did not find enough files to combine' + if latlon_bounds is None: + latlon_bounds = len(filelist) * [None] + else: + assert len(latlon_bounds)==len(filelist), 'Not enough specified bounds' + + terraindata = [ + dtype(bounds,fpath) for bounds,fpath in zip(latlon_bounds,filelist) + ] + + # merge rasters + from rasterio.merge import merge + merged, out_transform = merge([ + rasterio.open(data.tiffdata) for data in terraindata + ]) + + # write out merged dataset + profile = rasterio.open(filelist[0]).profile + print('Raster profile:',profile) + with rasterio.open(output,'w',**profile) as dst: + dst.write(merged) + + # get global bounds + bounds = np.empty((len(filelist),4)) + for i,data in enumerate(terraindata): + bounds[i,:] = data.bounds + bounds_min = bounds.min(axis=0) + bounds_max = bounds.max(axis=0) + return [bounds_min[0],bounds_min[1],bounds_max[2],bounds_max[3]] + +def calc_slope(x,y,z): + """Calculate local terrain slope based on project grid + + Notes: + - Uses neighborhood method (weighted second-order difference, based on + 3x3 stencil) + - Slopes are not calculated at edge points (i.e., locations where a 3x3 + stencil cannot be formed) + + Usage + ===== + x,y,z : numpy array + Equally sized 2-D arrays; if not specified, then the full terrain + will be used + """ + dx = x[1,0] - x[0,0] + dy = y[0,1] - y[0,0] + slope = np.empty_like(z) + slope[:,:] = np.nan + z1 = z[ :-2, 2: ] # upper left + z2 = z[ 1:-1, 2: ] # upper middle + z3 = z[ 2: , 2: ] # upper right + z4 = z[ :-2, 1:-1] # center left + #z5 = z[ 1:-1, 1:-1] # center + z6 = z[ 2: , 1:-1] # center right + z7 = z[ :-2, :-2] # lower left + z8 = z[ 1:-1, :-2] # lower middle + z9 = z[ 2: , :-2] # lower right + dz_dx = ((z3 + 2*z6 + z9) - (z1 + 2*z4 + z7)) / (8*dx) + dz_dy = ((z1 + 2*z2 + z3) - (z7 + 2*z8 + z9)) / (8*dy) + rise_run = np.sqrt(dz_dx**2 + dz_dy**2) + slope[1:-1,1:-1] = np.degrees(np.arctan(rise_run)) + return slope + + +def calcTRI(hgt,window=None,footprint=None): + ''' + Terrain Ruggedness Index + Riley, S. J., DeGloria, S. D., & Elliot, R. (1999). Index that + quantifies topographic heterogeneity. intermountain Journal + of sciences, 5(1-4), 23-27. + + hgt : array + Array of heights over which TRI will be calculated + window : int + Length of window in x and y direction. Must be odd. + ''' + import xarray as xr + from scipy.ndimage.filters import generic_filter + + # Window setup: + if footprint is not None: + assert window is None, 'Must specify either window or footprint' + window = np.shape(footprint)[0] + + assert (window/2.0) - np.floor(window/2.0) != 0.0, 'window must be odd...' + Hwindow = int(np.floor(window/2)) + + # Type and dimension check: + if isinstance(hgt,(xr.Dataset,xr.DataArray,xr.Variable)): + hgt = hgt.data + assert len(np.shape(hgt)) == 2, 'hgt must be 2-dimensional. Currently has {} dimensions'.format(len(np.shape(hgt))) + + ny,nx = np.shape(hgt) + + def tri_filt(x): + middle_ind = int(len(x)/2) + return((sum((x - x[middle_ind])**2.0))**0.5) + + if footprint is None: + tri = generic_filter(hgt,tri_filt, size = (window,window)) + else: + tri = generic_filter(hgt,tri_filt, footprint=footprint) + + return tri + + +def calcVRM(hgt,res,window=None,footprint=None,fill_depressions=True,return_slope_aspect=False): + ''' + Vector Ruggedness Measure + Sappington, J. M., Longshore, K. M., & Thompson, D. B. (2007). + Quantifying landscape ruggedness for animal habitat analysis: + a case study using bighorn sheep in the Mojave Desert. The + Journal of wildlife management, 71(5), 1419-1426. + + hgt : array + Array of heights over which TRI will be calculated + res : int or float + Resolution of the underlying hgt array. Should be constant in x and y + Needed for proper slope calculation + window : int + Length of window in x and y direction. Must be odd. + ''' + import richdem as rd + import xarray as xr + from scipy.ndimage.filters import generic_filter + + # Window setup: + if footprint is not None: + assert window is None, 'Must specify either window or footprint' + window = np.shape(footprint)[0] + + assert (window/2.0) - np.floor(window/2.0) != 0.0, 'window must be odd...' + Hwndw = int(np.floor(window/2)) + + # Type and dimension check: + if isinstance(hgt,(xr.Dataset,xr.DataArray,xr.Variable)): + hgt = hgt.data + assert len(np.shape(hgt)) == 2, 'hgt must be 2-dimensional. Currently has {} dimensions'.format(len(np.shape(hgt))) + ny,nx = np.shape(hgt) + + # Determine scale based on resolution of hgt array + zscale = 1/res + + # Get slope and aspect: + hgt_rd = rd.rdarray(hgt, no_data=-9999) + if fill_depressions: + rd.FillDepressions(hgt_rd, in_place=True) + slope = rd.TerrainAttribute(hgt_rd, attrib='slope_degrees',zscale=zscale) + aspect = rd.TerrainAttribute(hgt_rd, attrib='aspect') + + # Calculate vectors: + vrm = np.zeros((ny,nx)) + rugz = np.cos(np.deg2rad(slope)) + rugdxy = np.sin(np.deg2rad(slope)) + rugx = rugdxy*np.cos(np.deg2rad(aspect)) + rugy = rugdxy*np.sin(np.deg2rad(aspect)) + + def vrm_filt(x): + return(sum(x)**2) + + if footprint is None: + vrmX = generic_filter(rugx,vrm_filt, size = (window,window)) + vrmY = generic_filter(rugy,vrm_filt, size = (window,window)) + vrmZ = generic_filter(rugz,vrm_filt, size = (window,window)) + else: + vrmX = generic_filter(rugx,vrm_filt, footprint=footprint) + vrmY = generic_filter(rugy,vrm_filt, footprint=footprint) + vrmZ = generic_filter(rugz,vrm_filt, footprint=footprint) + + + if footprint is not None: + num_points = len(footprint[footprint != 0.0]) + else: + num_points = float(window**2) + vrm = 1.0 - np.sqrt(vrmX + vrmY + vrmZ)/num_points + if return_slope_aspect: + return vrm,slope,aspect + else: + return vrm + + +def calcSx(xx, yy, zagl, A, dmax, method='linear', verbose=False): + ''' + Sx is a measure of topographic shelter or exposure relative to a particular + wind direction. Calculates a whole map for all points (xi, yi) in the domain. + For each (xi, yi) pair, it uses all v points (xv, yv) upwind of (xi, yi) in + the A wind direction, up to dmax. + + Winstral, A., Marks D. "Simulating wind fields and snow redistribution using + terrain-based parameters to model snow accumulation and melt over a semi- + arid mountain catchment" Hydrol. Process. 16, 3585–3603 (2002) + + Usage + ===== + xx, yy : array + meshgrid arrays of the region extent coordinates. + zagl: arrayi, xr.DataArray + Elevation map of the region + A: float + Wind direction (deg, wind direction convention) + dmax: float + Upwind extent of the search + method: string + griddata interpolation method. Options are 'nearest', 'linear', 'cubic'. + Recommended linear or cubic. + ''' + + # get resolution (assumes uniform resolution) + res = xx[1,0] - xx[0,0] + npoints = 1+int(dmax/res) + if dmax < res: + raise ValueError('dmax needs to be larger or equal to the resolution of the grid') + + # Get upstream direction + A = A%360 + if A==0: upstreamDirX=0; upstreamDirY=-1 + elif A==90: upstreamDirX=-1; upstreamDirY=0 + elif A==180: upstreamDirX=0; upstreamDirY=1 + elif A==270: upstreamDirX=1; upstreamDirY=0 + elif A>0 and A<90: upstreamDirX=-1; upstreamDirY=-1 + elif A>90 and A<180: upstreamDirX=-1; upstreamDirY=1 + elif A>180 and A<270: upstreamDirX=1; upstreamDirY=1 + elif A>270 and A<360: upstreamDirX=1; upstreamDirY=-1 + + # change angle notation + ang = np.deg2rad(270-A) + + # array for interpolation using griddata + points = np.array( (xx.flatten(), yy.flatten()) ).T + if isinstance(zagl, xr.DataArray): + zagl = zagl.values + values = zagl.flatten() + + # create rotated grid. This way we sample into a interpolated grid that has the exact points we need + xmin = min(xx[:,0]); xmax = max(xx[:,0]) + ymin = min(yy[0,:]); ymax = max(yy[0,:]) + if A%90 == 0: + # if flow is aligned, we don't need a new grid + xrot = xx[:,0] + yrot = yy[0,:] + xxrot = xx + yyrot = yy + elevrot = zagl + else: + xrot = np.arange(xmin, xmax+0.1, abs(res*np.cos(ang))) + yrot = np.arange(ymin, ymax+0.1, abs(res*np.sin(ang))) + xxrot, yyrot = np.meshgrid(xrot, yrot, indexing='ij') + elevrot = griddata( points, values, (xxrot, yyrot), method=method ) + + # create empty rotated Sx array + Sxrot = np.empty(np.shape(elevrot)); Sxrot[:,:] = np.nan + + for i, xi in enumerate(xrot): + if verbose: print(f'Computing Sx... {100*(i+1)/len(xrot):.1f}% ', end='\r') + for j, yi in enumerate(yrot): + + # Get elevation profile along the direction asked + isel = np.linspace(i-upstreamDirX*npoints+upstreamDirX, i, npoints, dtype=int) + jsel = np.linspace(j-upstreamDirY*npoints+upstreamDirY, j, npoints, dtype=int) + try: + xsel = xrot[isel] + ysel = yrot[jsel] + elev = elevrot[isel,jsel] + except IndexError: + # At the borders, can't get a valid positions + xsel = np.zeros(np.size(isel)) + ysel = np.zeros(np.size(jsel)) + elev = np.zeros(np.size(isel)) + + # elevation of (xi, yi), for convenience + elevi = elev[-1] + + Sxrot[i,j] = np.nanmax(np.rad2deg( np.arctan( (elev[:-1] - elevi)/(((xsel[:-1]-xi)**2 + (ysel[:-1]-yi)**2)**0.5) ) )) + + # interpolate results back to original grid + pointsrot = np.array( (xxrot.flatten(), yyrot.flatten()) ).T + Sx = griddata( pointsrot, Sxrot.flatten(), (xx, yy), method=method ) + + return Sx + + +def calcSxmean(xx, yy, zagl, A, dmax, method='nearest', verbose=False): + + Asweep = np.linspace(A-15, A+15, 7)%360 + Sxmean = np.mean([calcSx(xx, yy, zagl, a, dmax, method, verbose=verbose) for a in Asweep ], axis=0) + + return Sxmean + + +def calcSb(xx, yy, zagl, A, sepdist=60): + ''' + Sb is a measure of upwind slope break and can be used to delineate zones of + possible flow separation. This function follows the definition of Sx0 from + the reference listed below and uses 1000m separation. + + Winstral, A., Marks D. "Simulating wind fields and snow redistribution using + terrain-based parameters to model snow accumulation and melt over a semi- + arid mountain catchment" Hydrol. Process. 16, 3585–3603 (2002) + + Usage + ===== + xx, yy : array + meshgrid arrays of the region extent coordinates. + zagl: array + Elevation map of the region + A: float + Wind direction (deg, wind direction convention) + sepdist : float, default 60 + Separation between between two regional Sx calculations. + Suggested value: 60 m. + ''' + + # local Sx + Sx1 = calcSx(xx, yy, zagl, A, dmax=sepdist) + + # outlying Sx. Computing it at (xo, yo), and not at (xi, yi) + xxo = xx - sepdist*np.cos(np.deg2rad(270-A)) + yyo = yy - sepdist*np.sin(np.deg2rad(270-A)) + points = np.array( (xx.flatten(), yy.flatten()) ).T + values = zagl.flatten() + zaglo = griddata( points, values, (xxo,yyo), method='linear' ) + Sx0 = calcSx(xxo, yyo, zaglo, A, dmax=1000) + + Sb = Sx1 - Sx0 + + return Sb + +def calcSbmean(xx, yy, zagl, A, sepdist): + + Asweep = np.linspace(A-15, A+15, 7)%360 + Sbmean = np.mean([calcSb(xx, yy, zagl, a, sepdist) for a in Asweep ], axis=0) + + return Sbmean + + +def calcTPI(xx, yy, zagl, r): + ''' + Topographic Position Index + + Reu, J, et al. Application of the topographic position index to heterogeneous + landscapes. Geomorphology, 186, 39-49 (2013) + ''' + from scipy.signal import convolve2d + + # get resolution (assumes uniform resolution) + res = xx[1,0] - xx[0,0] + rpoints = int(r/res) + if r < res: + raise ValueError('Averaging radium needs to be larger the resolution of the grid') + + y,x = np.ogrid[-rpoints:rpoints+1, -rpoints:rpoints+1] + kernel = x**2+y**2 <= rpoints**2 + + zaglmean = convolve2d(zagl, kernel*1, mode='same', boundary='fill', fillvalue=0) + zaglmean = zaglmean/np.sum(kernel*1) + + return zagl - zaglmean + + +def extract_elevation_from_stl(stlpath, x, y, interp_method = 'cubic'): + from stl import mesh + + x = [x] if isinstance(x, (int,float)) else x + y = [y] if isinstance(y, (int,float)) else y + + assert len(x)==len(y), 'x and y need to have the same dimenension' + + try: + msh = mesh.Mesh.from_file(stlpath) + except FileNotFoundError: + print('File does not exist.') + + xstl = msh.vectors[:,:,0].ravel() + ystl = msh.vectors[:,:,1].ravel() + zstl = msh.vectors[:,:,2].ravel() + + points = np.stack((xstl,ystl), axis=-1) + xi = np.stack((x,y), axis=-1) + elev = griddata(points, zstl, xi, method=interp_method) + + if len(x)==1: + return np.array(list(zip(x,y,elev))[0]) + else: + return np.array(list(zip(x,y,elev))) + + +def readSTL(stlpath, stlres=None, method='cubic'): + ''' + Function to read in an STL and get result in an orthogonal grid. + The resolution is optional, but check the warnings if you don't + pass one. + If a down- or upsampling of a STL is needed, then pass the desired + resolution and ignore the warnings. + + Usage + ===== + stlpath: str + Path to STL file, including its extension + stlres: int, float + Resolution of the underlying grid that the data will be + interpolated to + method: str, optional + Interpolation method. Options: 'nearest', 'linear', 'cubic' + Default is cubic + ''' + + from stl import mesh + + try: + msh = mesh.Mesh.from_file(stlpath) + except FileNotFoundError: + print('File does not exist.') + + xstl = msh.vectors[:,:,0].ravel() + ystl = msh.vectors[:,:,1].ravel() + zstl = msh.vectors[:,:,2].ravel() + + # STLs are complex and the computation below may not always get the proper resolution + apparentres = xstl[1]-xstl[0] + if stlres==None: + print(f'Using {apparentres} m resolution obtained from the STL. This resolution may not be entirely ' + 'accurate. If not, please provide a proper value using the `stlres` parameter.') + elif stlres != apparentres: + print(f'The {stlres} m resolution provided does not match what the function thinks the resolution is, {apparentres} ' + 'm, based on the STL. This apparent resolution may not be entirely accurate. Trust yours, but verify.') + + xmin = min(xstl); xmax = max(xstl) + ymin = min(ystl); ymax = max(ystl) + + xx, yy = np.meshgrid(np.arange(xmin,xmax+0.1, stlres), np.arange(ymin, ymax+0.1, stlres), indexing='ij') + + points = np.array( (xstl, ystl) ).T + values = zstl.flatten() + z = griddata( points, values, (xx, yy), method=method ) + + return xx, yy, z + From 383ce04eb5847584a0328bc9b77e5b77aa155163 Mon Sep 17 00:00:00 2001 From: hgopalan Date: Tue, 2 Jul 2024 11:55:10 -0600 Subject: [PATCH 19/77] Updates for the clang format --- .../icns/source_terms/DragForcing.H | 33 ++- .../icns/source_terms/DragForcing.cpp | 195 +++++++------ .../source_terms/DragTempForcing.H | 17 +- .../source_terms/DragTempForcing.cpp | 34 +-- amr-wind/physics/TerrainDrag.H | 55 ++-- amr-wind/physics/TerrainDrag.cpp | 266 ++++++++++-------- amr-wind/turbulence/LES/Kosovic.cpp | 23 +- 7 files changed, 329 insertions(+), 294 deletions(-) diff --git a/amr-wind/equation_systems/icns/source_terms/DragForcing.H b/amr-wind/equation_systems/icns/source_terms/DragForcing.H index 4d53abca96..411a895530 100644 --- a/amr-wind/equation_systems/icns/source_terms/DragForcing.H +++ b/amr-wind/equation_systems/icns/source_terms/DragForcing.H @@ -18,7 +18,7 @@ class DragForcing : public MomentumSource::Register public: static std::string identifier() { return "DragForcing"; } - explicit DragForcing(const CFDSim& sim); + explicit DragForcing(const CFDSim& sim); ~DragForcing() override; @@ -27,24 +27,23 @@ public: const amrex::MFIter& mfi, const amrex::Box& bx, const FieldState fstate, - const amrex::Array4& src_term) const override; + const amrex::Array4& src_term) const override; - private: - const CFDSim& m_sim; - const amrex::AmrCore&m_mesh; - const Field& m_velocity; - Field& m_terrainBlank; - Field& m_terrainDrag; - Field& m_terrainz0; - amrex::Gpu::DeviceVector gpu_vel_ht; - amrex::Gpu::DeviceVector gpu_vel_vals; - amrex::Real m_drag{100.0}; - amrex::Real m_spongeStrength{1.0}; - amrex::Real m_spongeDensity{1.0}; - amrex::Real m_spongeDistanceX{1000}; - amrex::Real m_spongeDistanceY{1000}; - amrex::Real m_verificationMode{0}; + const CFDSim& m_sim; + const amrex::AmrCore& m_mesh; + const Field& m_velocity; + Field& m_terrainBlank; + Field& m_terrainDrag; + Field& m_terrainz0; + amrex::Gpu::DeviceVector gpu_vel_ht; + amrex::Gpu::DeviceVector gpu_vel_vals; + amrex::Real m_drag{100.0}; + amrex::Real m_spongeStrength{1.0}; + amrex::Real m_spongeDensity{1.0}; + amrex::Real m_spongeDistanceX{1000}; + amrex::Real m_spongeDistanceY{1000}; + amrex::Real m_verificationMode{0}; }; } // namespace amr_wind::pde::icns diff --git a/amr-wind/equation_systems/icns/source_terms/DragForcing.cpp b/amr-wind/equation_systems/icns/source_terms/DragForcing.cpp index e8abf86946..2a5c73f9df 100644 --- a/amr-wind/equation_systems/icns/source_terms/DragForcing.cpp +++ b/amr-wind/equation_systems/icns/source_terms/DragForcing.cpp @@ -8,33 +8,36 @@ namespace amr_wind::pde::icns { DragForcing::DragForcing(const CFDSim& sim) - :m_sim(sim), - m_mesh(sim.mesh()), - m_velocity(sim.repo().get_field("velocity")), - m_terrainBlank(sim.repo().get_field("terrainBlank")), - m_terrainDrag(sim.repo().get_field("terrainDrag")), - m_terrainz0(sim.repo().get_field("terrainz0")) + : m_sim(sim) + , m_mesh(sim.mesh()) + , m_velocity(sim.repo().get_field("velocity")) + , m_terrainBlank(sim.repo().get_field("terrainBlank")) + , m_terrainDrag(sim.repo().get_field("terrainDrag")) + , m_terrainz0(sim.repo().get_field("terrainz0")) { - auto& phy_mgr = m_sim.physics_manager(); - if (phy_mgr.contains("ABL")) { - const auto& abl = m_sim.physics_manager().get(); - const VelPlaneAveraging& fa_velocity=abl.abl_statistics().vel_profile_coarse(); - gpu_vel_ht.resize(fa_velocity.line_centroids().size()); - gpu_vel_vals.resize(fa_velocity.line_average().size()); - amrex::Gpu::copy(amrex::Gpu::hostToDevice, fa_velocity.line_centroids().begin(), - fa_velocity.line_centroids().end(), gpu_vel_ht.begin()); - amrex::Gpu::copy(amrex::Gpu::hostToDevice, fa_velocity.line_average().begin(), - fa_velocity.line_average().end(), gpu_vel_vals.begin()); - } - amrex::ParmParse pp("DragForcing"); - pp.query("dragCoefficient", m_drag); - pp.query("spongeStrength",m_spongeStrength); - pp.query("spongeDensity",m_spongeDensity); - pp.query("spongeDistanceX",m_spongeDistanceX); - pp.query("spongeDistanceY",m_spongeDistanceY); - pp.query("verificationMode",m_verificationMode); + auto& phy_mgr = m_sim.physics_manager(); + if (phy_mgr.contains("ABL")) { + const auto& abl = m_sim.physics_manager().get(); + const VelPlaneAveraging& fa_velocity = + abl.abl_statistics().vel_profile_coarse(); + gpu_vel_ht.resize(fa_velocity.line_centroids().size()); + gpu_vel_vals.resize(fa_velocity.line_average().size()); + amrex::Gpu::copy( + amrex::Gpu::hostToDevice, fa_velocity.line_centroids().begin(), + fa_velocity.line_centroids().end(), gpu_vel_ht.begin()); + amrex::Gpu::copy( + amrex::Gpu::hostToDevice, fa_velocity.line_average().begin(), + fa_velocity.line_average().end(), gpu_vel_vals.begin()); + } + amrex::ParmParse pp("DragForcing"); + pp.query("dragCoefficient", m_drag); + pp.query("spongeStrength", m_spongeStrength); + pp.query("spongeDensity", m_spongeDensity); + pp.query("spongeDistanceX", m_spongeDistanceX); + pp.query("spongeDistanceY", m_spongeDistanceY); + pp.query("verificationMode", m_verificationMode); } - + DragForcing::~DragForcing() = default; void DragForcing::operator()( @@ -45,80 +48,92 @@ void DragForcing::operator()( const amrex::Array4& src_term) const { const auto& vel = - m_velocity.state(field_impl::dof_state(fstate))(lev).const_array(mfi); + m_velocity.state(field_impl::dof_state(fstate))(lev).const_array(mfi); const auto blank = m_terrainBlank(lev).const_array(mfi); const auto drag = m_terrainDrag(lev).const_array(mfi); - const auto terrainz0=m_terrainz0(lev).const_array(mfi); + const auto terrainz0 = m_terrainz0(lev).const_array(mfi); const auto& geom_vec = m_mesh.Geom(); - const auto& geom = geom_vec[lev]; + const auto& geom = geom_vec[lev]; const auto& dx = geom.CellSize(); const auto& prob_lo = geom.ProbLoArray(); const auto& prob_hi = geom.ProbHiArray(); - const amrex::Real gpu_drag=m_drag; - const amrex::Real gpu_spongeStrength=m_spongeStrength; - const amrex::Real gpu_spongeDensity=m_spongeDensity; - const amrex::Real gpu_startX=prob_hi[0]-m_spongeDistanceX; - const amrex::Real gpu_startY=prob_hi[1]-m_spongeDistanceY; - const amrex::Real gpu_verificationMode=m_verificationMode; + const amrex::Real gpu_drag = m_drag; + const amrex::Real gpu_spongeStrength = m_spongeStrength; + const amrex::Real gpu_spongeDensity = m_spongeDensity; + const amrex::Real gpu_startX = prob_hi[0] - m_spongeDistanceX; + const amrex::Real gpu_startY = prob_hi[1] - m_spongeDistanceY; + const amrex::Real gpu_verificationMode = m_verificationMode; // Copy Data const auto* local_gpu_vel_ht = gpu_vel_ht.data(); - const auto* local_gpu_vel_vals=gpu_vel_vals.data(); - const amrex::Real vsize=gpu_vel_ht.size(); + const auto* local_gpu_vel_vals = gpu_vel_vals.data(); + const amrex::Real vsize = gpu_vel_ht.size(); amrex::ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept { - const amrex::Real x1 = prob_lo[0] + (i + 0.5) * dx[0]; - const amrex::Real x2 = prob_lo[1] + (j + 0.5) * dx[1]; - const amrex::Real x3 = prob_lo[2] + (k + 0.5) * dx[2]; - amrex::Real xdamping=0; - amrex::Real ydamping=0; - if(x1>gpu_startX){ - amrex::Real xi=(x1 - gpu_startX) / (prob_hi[0] - gpu_startX); - xdamping=(1-gpu_verificationMode)*gpu_spongeStrength * xi * xi ; - } - if(x2>gpu_startY){ - amrex::Real yi=(x2 - gpu_startY) / (prob_hi[1] - gpu_startY); - ydamping=(1-gpu_verificationMode)*gpu_spongeStrength * yi * yi; - } - amrex::Real Cd=gpu_drag/dx[0]; - amrex::Real gpu_spongeVelX=0.0; - amrex::Real gpu_spongeVelY=0.0; - amrex::Real gpu_spongeVelZ=0.0; - amrex::Real residual=1000; - amrex::Real height_error=0.0; - for(int ii=0;ii gpu_startX) { + amrex::Real xi = (x1 - gpu_startX) / (prob_hi[0] - gpu_startX); + xdamping = + (1 - gpu_verificationMode) * gpu_spongeStrength * xi * xi; + } + if (x2 > gpu_startY) { + amrex::Real yi = (x2 - gpu_startY) / (prob_hi[1] - gpu_startY); + ydamping = + (1 - gpu_verificationMode) * gpu_spongeStrength * yi * yi; + } + amrex::Real Cd = gpu_drag / dx[0]; + amrex::Real gpu_spongeVelX = 0.0; + amrex::Real gpu_spongeVelY = 0.0; + amrex::Real gpu_spongeVelZ = 0.0; + amrex::Real residual = 1000; + amrex::Real height_error = 0.0; + for (int ii = 0; ii < vsize; ++ii) { + height_error = std::abs(x3 - local_gpu_vel_ht[ii]); + if (height_error < residual) { + residual = height_error; + gpu_spongeVelX = local_gpu_vel_vals[3 * ii]; + gpu_spongeVelY = local_gpu_vel_vals[3 * ii + 1]; + gpu_spongeVelZ = local_gpu_vel_vals[3 * ii + 2]; + } + } + // Terrain Drag + amrex::Real Dxz = 0.0; + amrex::Real Dyz = 0.0; + const amrex::Real ux1 = vel(i, j, k, 0); + const amrex::Real uy1 = vel(i, j, k, 1); + const amrex::Real uz1 = vel(i, j, k, 2); + const amrex::Real m = std::sqrt(ux1 * ux1 + uy1 * uy1 + uz1 * uz1); + if (drag(i, j, k) == 1) { + const amrex::Real m1 = std::sqrt(ux1 * ux1 + uy1 * uy1); + const amrex::Real ux2 = vel(i, j, k - 1, 0); + const amrex::Real uy2 = vel(i, j, k - 1, 1); + const amrex::Real m2 = std::sqrt(ux2 * ux2 + uy2 * uy2); + const amrex::Real kappa = 0.41; + const amrex::Real z0 = std::max(terrainz0(i, j, k), 1e-4); + const amrex::Real ustar = (1 - gpu_verificationMode) * + std::abs(m2 - m1) * kappa / + std::log((x3 + z0) / z0); + Dxz = -ustar * ustar * ux1 / + (1e-5 + std::sqrt(ux1 * ux1 + uy1 * uy1)) / dx[2]; + Dyz = -ustar * ustar * uy1 / + (1e-5 + std::sqrt(ux1 * ux1 + uy1 * uy1)) / dx[2]; + } + // Adjusting Cd for momentum + amrex::Real CdM = std::min(Cd / (m + 1e-5), 1000.0); + src_term(i, j, k, 0) -= + (CdM * m * ux1 * blank(i, j, k) + Dxz * drag(i, j, k) + + (xdamping + ydamping) * + (ux1 - gpu_spongeDensity * gpu_spongeVelX)); + src_term(i, j, k, 1) -= + (CdM * m * uy1 * blank(i, j, k) + Dyz * drag(i, j, k) + + (xdamping + ydamping) * + (uy1 - gpu_spongeDensity * gpu_spongeVelY)); + src_term(i, j, k, 2) -= + (CdM * m * uz1 * blank(i, j, k) + + (xdamping + ydamping) * + (uz1 - gpu_spongeDensity * gpu_spongeVelZ)); }); } diff --git a/amr-wind/equation_systems/temperature/source_terms/DragTempForcing.H b/amr-wind/equation_systems/temperature/source_terms/DragTempForcing.H index b252111bed..02ab5f7a2b 100644 --- a/amr-wind/equation_systems/temperature/source_terms/DragTempForcing.H +++ b/amr-wind/equation_systems/temperature/source_terms/DragTempForcing.H @@ -18,7 +18,7 @@ class DragTempForcing : public TemperatureSource::Register public: static std::string identifier() { return "DragTempForcing"; } - explicit DragTempForcing(const CFDSim& sim); + explicit DragTempForcing(const CFDSim& sim); ~DragTempForcing() override; @@ -27,16 +27,15 @@ public: const amrex::MFIter& mfi, const amrex::Box& bx, const FieldState fstate, - const amrex::Array4& src_term) const override; + const amrex::Array4& src_term) const override; - private: - const CFDSim& m_sim; - const amrex::AmrCore&m_mesh; - Field& m_temperature; - Field& m_terrainBlank; - amrex::Real m_drag{10.0}; - amrex::Real m_verificationMode{0}; + const CFDSim& m_sim; + const amrex::AmrCore& m_mesh; + Field& m_temperature; + Field& m_terrainBlank; + amrex::Real m_drag{10.0}; + amrex::Real m_verificationMode{0}; }; } // namespace amr_wind::pde::temperature diff --git a/amr-wind/equation_systems/temperature/source_terms/DragTempForcing.cpp b/amr-wind/equation_systems/temperature/source_terms/DragTempForcing.cpp index f4dcf04d98..833c31523d 100644 --- a/amr-wind/equation_systems/temperature/source_terms/DragTempForcing.cpp +++ b/amr-wind/equation_systems/temperature/source_terms/DragTempForcing.cpp @@ -5,20 +5,19 @@ #include "AMReX_Gpu.H" #include "AMReX_Random.H" - namespace amr_wind::pde::temperature { DragTempForcing::DragTempForcing(const CFDSim& sim) - :m_sim(sim), - m_mesh(sim.mesh()), - m_temperature(sim.repo().get_field("temperature")), - m_terrainBlank(sim.repo().get_field("terrainBlank")) + : m_sim(sim) + , m_mesh(sim.mesh()) + , m_temperature(sim.repo().get_field("temperature")) + , m_terrainBlank(sim.repo().get_field("terrainBlank")) { - amrex::ParmParse pp("DragTempForcing"); - pp.query("dragCoefficient", m_drag); - pp.query("verificationMode",m_verificationMode); + amrex::ParmParse pp("DragTempForcing"); + pp.query("dragCoefficient", m_drag); + pp.query("verificationMode", m_verificationMode); } - + DragTempForcing::~DragTempForcing() = default; void DragTempForcing::operator()( @@ -28,17 +27,18 @@ void DragTempForcing::operator()( const FieldState fstate, const amrex::Array4& src_term) const { - const auto temperature=m_temperature(lev).const_array(mfi); - const auto blank = m_terrainBlank(lev).const_array(mfi); + const auto temperature = m_temperature(lev).const_array(mfi); + const auto blank = m_terrainBlank(lev).const_array(mfi); const auto& geom_vec = m_mesh.Geom(); - const auto& geom = geom_vec[lev]; + const auto& geom = geom_vec[lev]; const auto& dx = geom.CellSize(); - const amrex::Real gpu_drag=m_drag; - const amrex::Real gpu_verificationMode=m_verificationMode; - const amrex::Real gpu_TRef=300.0; + const amrex::Real gpu_drag = m_drag; + const amrex::Real gpu_verificationMode = m_verificationMode; + const amrex::Real gpu_TRef = 300.0; amrex::ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept { - amrex::Real Cd=gpu_drag/dx[0]; - src_term(i, j, k, 0) -= (Cd*(temperature(i,j,k,0)-gpu_TRef)*blank(i,j,k)); + amrex::Real Cd = gpu_drag / dx[0]; + src_term(i, j, k, 0) -= + (Cd * (temperature(i, j, k, 0) - gpu_TRef) * blank(i, j, k)); }); } diff --git a/amr-wind/physics/TerrainDrag.H b/amr-wind/physics/TerrainDrag.H index 53e4b519fe..b413a662e5 100644 --- a/amr-wind/physics/TerrainDrag.H +++ b/amr-wind/physics/TerrainDrag.H @@ -7,10 +7,7 @@ namespace amr_wind::terraindrag { -namespace { - - -} // namespace +namespace {} // namespace /** Terraindrag Flow physics * \ingroup physics @@ -25,36 +22,38 @@ public: ~TerrainDrag() override = default; - void initialize_fields(int /*level*/, const amrex::Geometry& /*geom*/) override{} - - void pre_init_actions() override; - - void post_init_actions() override; + void + initialize_fields(int /*level*/, const amrex::Geometry& /*geom*/) override + {} + + void pre_init_actions() override; + + void post_init_actions() override; void post_regrid_actions() override {} - void pre_advance_work() override{} + void pre_advance_work() override {} - void post_advance_work() override{} + void post_advance_work() override {} - // amrex::Real computeTerrainHeight(const amrex::Real x1,const amrex::Real x2) const; + // amrex::Real computeTerrainHeight(const amrex::Real x1,const + // amrex::Real x2) const; private: - CFDSim& m_sim; - const FieldRepo& m_repo; - const amrex::AmrCore& m_mesh; - Field& m_velocity; - // Blanking Field for Terrain or Buildings - Field& m_terrainBlank; - // Terrain Drag Force Term - Field& m_terrainDrag; - // Reading the Terrain Coordinates from file - amrex::Vector m_xterrain,m_yterrain,m_zterrain; - // Roughness Field - Field& m_terrainz0; - // Reading the Roughness Coordinates from file - Not Fully there yet - // Need updates to ABLWallFunction in future - amrex::Vector m_xrough,m_yrough,m_z0rough; - + CFDSim& m_sim; + const FieldRepo& m_repo; + const amrex::AmrCore& m_mesh; + Field& m_velocity; + // Blanking Field for Terrain or Buildings + Field& m_terrainBlank; + // Terrain Drag Force Term + Field& m_terrainDrag; + // Reading the Terrain Coordinates from file + amrex::Vector m_xterrain, m_yterrain, m_zterrain; + // Roughness Field + Field& m_terrainz0; + // Reading the Roughness Coordinates from file - Not Fully there yet + // Need updates to ABLWallFunction in future + amrex::Vector m_xrough, m_yrough, m_z0rough; }; } // namespace amr_wind::terraindrag diff --git a/amr-wind/physics/TerrainDrag.cpp b/amr-wind/physics/TerrainDrag.cpp index 417c142914..cbe7d94cb2 100644 --- a/amr-wind/physics/TerrainDrag.cpp +++ b/amr-wind/physics/TerrainDrag.cpp @@ -9,9 +9,7 @@ namespace amr_wind::terraindrag { -namespace { - -} // namespace +namespace {} // namespace TerrainDrag::TerrainDrag(CFDSim& sim) : m_sim(sim) @@ -22,134 +20,154 @@ TerrainDrag::TerrainDrag(CFDSim& sim) , m_terrainDrag(sim.repo().declare_field("terrainDrag", 1, 1, 1)) , m_terrainz0(sim.repo().declare_field("terrainz0", 1, 1, 1)) { - std::string terrainfile("terrain.amrwind"); - std::ifstream file(terrainfile, std::ios::in); - if (!file.good()) { - amrex::Abort("Cannot find terrain.amrwind file"); - } - amrex::Real value1,value2,value3; - while(file>>value1>>value2>>value3){ - m_xterrain.push_back(value1); - m_yterrain.push_back(value2); - m_zterrain.push_back(value3); - } - file.close(); - // No checks for the file as it is optional currently - std::string roughnessfile("terrain.roughness"); - std::ifstream file1(roughnessfile, std::ios::in); - while(file1>>value1>>value2>>value3){ - m_xrough.push_back(value1); - m_yrough.push_back(value2); - m_z0rough.push_back(value3); - } - file1.close(); - m_sim.io_manager().register_io_var("terrainDrag"); - m_sim.io_manager().register_io_var("terrainBlank"); - m_sim.io_manager().register_io_var("terrainz0"); + std::string terrainfile("terrain.amrwind"); + std::ifstream file(terrainfile, std::ios::in); + if (!file.good()) { + amrex::Abort("Cannot find terrain.amrwind file"); + } + amrex::Real value1, value2, value3; + while (file >> value1 >> value2 >> value3) { + m_xterrain.push_back(value1); + m_yterrain.push_back(value2); + m_zterrain.push_back(value3); + } + file.close(); + // No checks for the file as it is optional currently + std::string roughnessfile("terrain.roughness"); + std::ifstream file1(roughnessfile, std::ios::in); + while (file1 >> value1 >> value2 >> value3) { + m_xrough.push_back(value1); + m_yrough.push_back(value2); + m_z0rough.push_back(value3); + } + file1.close(); + m_sim.io_manager().register_io_var("terrainDrag"); + m_sim.io_manager().register_io_var("terrainBlank"); + m_sim.io_manager().register_io_var("terrainz0"); } - void TerrainDrag::post_init_actions() +void TerrainDrag::post_init_actions() { - BL_PROFILE("amr-wind::" + this->identifier() + "::post_init_actions"); - //using namespace utils; - const auto& geom_vec = m_sim.repo().mesh().Geom(); - const int nlevels = m_sim.repo().num_active_levels(); - for (int level = 0; level < nlevels; ++level) { + BL_PROFILE("amr-wind::" + this->identifier() + "::post_init_actions"); + // using namespace utils; + const auto& geom_vec = m_sim.repo().mesh().Geom(); + const int nlevels = m_sim.repo().num_active_levels(); + for (int level = 0; level < nlevels; ++level) { const auto& geom = geom_vec[level]; - const auto& dx = geom.CellSizeArray(); - const auto& prob_lo = geom.ProbLoArray(); - auto& velocity = m_velocity(level); - auto& blanking = m_terrainBlank(level); - auto& terrainz0=m_terrainz0(level); - auto& drag=m_terrainDrag(level); - // copy terrain data to gpu - amrex::Gpu::DeviceVector gpu_xterrain(m_xterrain.size()); - amrex::Gpu::DeviceVector gpu_yterrain(m_xterrain.size()); - amrex::Gpu::DeviceVector gpu_zterrain(m_xterrain.size()); - amrex::Gpu::copy(amrex::Gpu::hostToDevice, m_xterrain.begin(), m_xterrain.end(), gpu_xterrain.begin()); - amrex::Gpu::copy(amrex::Gpu::hostToDevice, m_yterrain.begin(), m_yterrain.end(), gpu_yterrain.begin()); - amrex::Gpu::copy(amrex::Gpu::hostToDevice, m_zterrain.begin(), m_zterrain.end(), gpu_zterrain.begin()); - const auto* xterrain_ptr = gpu_xterrain.data(); - const auto* yterrain_ptr = gpu_yterrain.data(); - const auto* zterrain_ptr = gpu_zterrain.data(); - // Copy Roughness to gpu - amrex::Gpu::DeviceVector gpu_xrough(m_xrough.size()); - amrex::Gpu::DeviceVector gpu_yrough(m_xrough.size()); - amrex::Gpu::DeviceVector gpu_z0rough(m_xrough.size()); - amrex::Gpu::copy(amrex::Gpu::hostToDevice, m_xrough.begin(), m_xrough.end(), gpu_xrough.begin()); - amrex::Gpu::copy(amrex::Gpu::hostToDevice, m_yrough.begin(), m_yrough.end(), gpu_yrough.begin()); - amrex::Gpu::copy(amrex::Gpu::hostToDevice, m_z0rough.begin(), m_z0rough.end(), gpu_z0rough.begin()); - const auto* xrough_ptr = gpu_xrough.data(); - const auto* yrough_ptr = gpu_yrough.data(); - const auto* z0rough_ptr = gpu_z0rough.data(); - for (amrex::MFIter mfi(velocity); mfi.isValid(); ++mfi) { - const auto& vbx = mfi.validbox(); - auto levelBlanking = blanking.array(mfi); - auto levelDrag=drag.array(mfi); - auto levelz0=terrainz0.array(mfi); - const amrex::Real terrainSize=m_xterrain.size(); - const amrex::Real roughnessSize=m_xrough.size(); - amrex::ParallelFor( - vbx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept { - // compute the source term - const amrex::Real x1 = prob_lo[0] + (i + 0.5) * dx[0]; - const amrex::Real x2 = prob_lo[1] + (j + 0.5) * dx[1]; - const amrex::Real x3 = prob_lo[2] + (k + 0.5) * dx[2]; - // Terrain Height - amrex::Real residual=10000; - amrex::Real terrainHt=0.0; - for(int ii=0;iiterrainHt && k>0 && levelBlanking(i,j,k-1,0)==1){ - levelDrag(i,j,k,0)=1.0; - } - - }); + const auto& dx = geom.CellSizeArray(); + const auto& prob_lo = geom.ProbLoArray(); + auto& velocity = m_velocity(level); + auto& blanking = m_terrainBlank(level); + auto& terrainz0 = m_terrainz0(level); + auto& drag = m_terrainDrag(level); + // copy terrain data to gpu + amrex::Gpu::DeviceVector gpu_xterrain(m_xterrain.size()); + amrex::Gpu::DeviceVector gpu_yterrain(m_xterrain.size()); + amrex::Gpu::DeviceVector gpu_zterrain(m_xterrain.size()); + amrex::Gpu::copy( + amrex::Gpu::hostToDevice, m_xterrain.begin(), m_xterrain.end(), + gpu_xterrain.begin()); + amrex::Gpu::copy( + amrex::Gpu::hostToDevice, m_yterrain.begin(), m_yterrain.end(), + gpu_yterrain.begin()); + amrex::Gpu::copy( + amrex::Gpu::hostToDevice, m_zterrain.begin(), m_zterrain.end(), + gpu_zterrain.begin()); + const auto* xterrain_ptr = gpu_xterrain.data(); + const auto* yterrain_ptr = gpu_yterrain.data(); + const auto* zterrain_ptr = gpu_zterrain.data(); + // Copy Roughness to gpu + amrex::Gpu::DeviceVector gpu_xrough(m_xrough.size()); + amrex::Gpu::DeviceVector gpu_yrough(m_xrough.size()); + amrex::Gpu::DeviceVector gpu_z0rough(m_xrough.size()); + amrex::Gpu::copy( + amrex::Gpu::hostToDevice, m_xrough.begin(), m_xrough.end(), + gpu_xrough.begin()); + amrex::Gpu::copy( + amrex::Gpu::hostToDevice, m_yrough.begin(), m_yrough.end(), + gpu_yrough.begin()); + amrex::Gpu::copy( + amrex::Gpu::hostToDevice, m_z0rough.begin(), m_z0rough.end(), + gpu_z0rough.begin()); + const auto* xrough_ptr = gpu_xrough.data(); + const auto* yrough_ptr = gpu_yrough.data(); + const auto* z0rough_ptr = gpu_z0rough.data(); + for (amrex::MFIter mfi(velocity); mfi.isValid(); ++mfi) { + const auto& vbx = mfi.validbox(); + auto levelBlanking = blanking.array(mfi); + auto levelDrag = drag.array(mfi); + auto levelz0 = terrainz0.array(mfi); + const amrex::Real terrainSize = m_xterrain.size(); + const amrex::Real roughnessSize = m_xrough.size(); + amrex::ParallelFor( + vbx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept { + // compute the source term + const amrex::Real x1 = prob_lo[0] + (i + 0.5) * dx[0]; + const amrex::Real x2 = prob_lo[1] + (j + 0.5) * dx[1]; + const amrex::Real x3 = prob_lo[2] + (k + 0.5) * dx[2]; + // Terrain Height + amrex::Real residual = 10000; + amrex::Real terrainHt = 0.0; + for (int ii = 0; ii < terrainSize; ++ii) { + const amrex::Real radius = std::sqrt( + std::pow(x1 - xterrain_ptr[ii], 2) + + std::pow(x2 - yterrain_ptr[ii], 2)); + if (radius < residual) { + residual = radius; + terrainHt = zterrain_ptr[ii]; + } + if (radius < dx[0]) { + break; + } + } + const amrex::Real turnOn = (x3 <= terrainHt) ? 1.0 : 0.0; + levelBlanking(i, j, k, 0) = turnOn; + residual = 10000; + amrex::Real roughz0 = 0.1; + for (int ii = 0; ii < roughnessSize; ++ii) { + const amrex::Real radius = std::sqrt( + std::pow(x1 - xrough_ptr[ii], 2) + + std::pow(x2 - yrough_ptr[ii], 2)); + if (radius < residual) { + residual = radius; + roughz0 = z0rough_ptr[ii]; + } + if (radius < dx[0]) { + break; + } + } + levelz0(i, j, k, 0) = roughz0; + }); + amrex::ParallelFor( + vbx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept { + // Terrain Height + amrex::Real residual = 10000; + amrex::Real terrainHt = 0.0; + const amrex::Real x1 = prob_lo[0] + (i + 0.5) * dx[0]; + const amrex::Real x2 = prob_lo[1] + (j + 0.5) * dx[1]; + const amrex::Real x3 = prob_lo[2] + (k + 0.5) * dx[2]; + for (int ii = 0; ii < terrainSize; ++ii) { + const amrex::Real radius = std::sqrt( + std::pow(x1 - xterrain_ptr[ii], 2) + + std::pow(x2 - yterrain_ptr[ii], 2)); + if (radius < residual) { + residual = radius; + terrainHt = zterrain_ptr[ii]; + } + } + levelDrag(i, j, k, 0) = 0.0; + if (x3 > terrainHt && k > 0 && + levelBlanking(i, j, k - 1, 0) == 1) { + levelDrag(i, j, k, 0) = 1.0; + } + }); + } } - } } - void TerrainDrag::pre_init_actions() - { +void TerrainDrag::pre_init_actions() +{ BL_PROFILE("amr-wind::" + this->identifier() + "::pre_init_actions"); +} - } - } // namespace amr_wind::terraindrag diff --git a/amr-wind/turbulence/LES/Kosovic.cpp b/amr-wind/turbulence/LES/Kosovic.cpp index 614a4f0a6c..59e930f3a2 100644 --- a/amr-wind/turbulence/LES/Kosovic.cpp +++ b/amr-wind/turbulence/LES/Kosovic.cpp @@ -55,10 +55,10 @@ void Kosovic::update_turbulent_viscosity( const auto& geom_vec = repo.mesh().Geom(); const amrex::Real Cs_sqr = this->m_Cs * this->m_Cs; bool is_terrain = this->m_sim.repo().field_exists("terrainBlank"); - Field* m_terrainBlank= &mu_turb; + Field* m_terrainBlank = &mu_turb; if (is_terrain) { - m_terrainBlank = &this->m_sim.repo().get_field("terrainBlank"); - } + m_terrainBlank = &this->m_sim.repo().get_field("terrainBlank"); + } // Populate strainrate into the turbulent viscosity arrays to avoid creating // a temporary buffer fvm::strainrate(mu_turb, vel); @@ -86,7 +86,7 @@ void Kosovic::update_turbulent_viscosity( const auto& mu_arr = mu_turb(lev).array(mfi); const auto& rho_arr = den(lev).const_array(mfi); const auto& divNijLevel = (this->m_divNij)(lev).array(mfi); - const auto& blank_arr = (*m_terrainBlank)(lev).array(mfi); + const auto& blank_arr = (*m_terrainBlank)(lev).array(mfi); amrex::ParallelFor( bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept { const amrex::Real rho = rho_arr(i, j, k); @@ -104,17 +104,22 @@ void Kosovic::update_turbulent_viscosity( smag_factor + std::pow(fmu, locSurfaceRANSExp) * ransL) + (1 - locSurfaceFactor) * smag_factor; - const amrex::Real blankTerrain = (is_terrain)? 1-blank_arr(i,j,k,0):1.0; - mu_arr(i, j, k) *= rho * viscosityScale * turnOff * blankTerrain; + const amrex::Real blankTerrain = + (is_terrain) ? 1 - blank_arr(i, j, k, 0) : 1.0; + mu_arr(i, j, k) *= + rho * viscosityScale * turnOff * blankTerrain; amrex::Real stressScale = locSurfaceFactor * (std::pow(1 - fmu, locSurfaceRANSExp) * smag_factor * 0.25 * locC1 + std::pow(fmu, locSurfaceRANSExp) * ransL) + (1 - locSurfaceFactor) * smag_factor * 0.25 * locC1; - divNijLevel(i, j, k, 0) *= rho * stressScale * turnOff * blankTerrain; - divNijLevel(i, j, k, 1) *= rho * stressScale * turnOff * blankTerrain; - divNijLevel(i, j, k, 2) *= rho * stressScale * turnOff * blankTerrain; + divNijLevel(i, j, k, 0) *= + rho * stressScale * turnOff * blankTerrain; + divNijLevel(i, j, k, 1) *= + rho * stressScale * turnOff * blankTerrain; + divNijLevel(i, j, k, 2) *= + rho * stressScale * turnOff * blankTerrain; }); } } From 2e7d011be4e174a69521aa1a422e5cb15518e087 Mon Sep 17 00:00:00 2001 From: hgopalan Date: Tue, 2 Jul 2024 12:16:41 -0600 Subject: [PATCH 20/77] Removing the unused variables for Temperature --- .../temperature/source_terms/DragTempForcing.H | 3 --- .../temperature/source_terms/DragTempForcing.cpp | 6 +----- 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/amr-wind/equation_systems/temperature/source_terms/DragTempForcing.H b/amr-wind/equation_systems/temperature/source_terms/DragTempForcing.H index 02ab5f7a2b..1a69a04865 100644 --- a/amr-wind/equation_systems/temperature/source_terms/DragTempForcing.H +++ b/amr-wind/equation_systems/temperature/source_terms/DragTempForcing.H @@ -30,12 +30,9 @@ public: const amrex::Array4& src_term) const override; private: - const CFDSim& m_sim; - const amrex::AmrCore& m_mesh; Field& m_temperature; Field& m_terrainBlank; amrex::Real m_drag{10.0}; - amrex::Real m_verificationMode{0}; }; } // namespace amr_wind::pde::temperature diff --git a/amr-wind/equation_systems/temperature/source_terms/DragTempForcing.cpp b/amr-wind/equation_systems/temperature/source_terms/DragTempForcing.cpp index 833c31523d..1e7957f54b 100644 --- a/amr-wind/equation_systems/temperature/source_terms/DragTempForcing.cpp +++ b/amr-wind/equation_systems/temperature/source_terms/DragTempForcing.cpp @@ -8,14 +8,11 @@ namespace amr_wind::pde::temperature { DragTempForcing::DragTempForcing(const CFDSim& sim) - : m_sim(sim) - , m_mesh(sim.mesh()) - , m_temperature(sim.repo().get_field("temperature")) + : m_temperature(sim.repo().get_field("temperature")) , m_terrainBlank(sim.repo().get_field("terrainBlank")) { amrex::ParmParse pp("DragTempForcing"); pp.query("dragCoefficient", m_drag); - pp.query("verificationMode", m_verificationMode); } DragTempForcing::~DragTempForcing() = default; @@ -33,7 +30,6 @@ void DragTempForcing::operator()( const auto& geom = geom_vec[lev]; const auto& dx = geom.CellSize(); const amrex::Real gpu_drag = m_drag; - const amrex::Real gpu_verificationMode = m_verificationMode; const amrex::Real gpu_TRef = 300.0; amrex::ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept { amrex::Real Cd = gpu_drag / dx[0]; From 673d25f91426a87b0b174fffb08c2f7129c1766e Mon Sep 17 00:00:00 2001 From: hgopalan Date: Tue, 2 Jul 2024 12:23:42 -0600 Subject: [PATCH 21/77] Formatting --- .../temperature/source_terms/DragTempForcing.H | 1 + .../temperature/source_terms/DragTempForcing.cpp | 3 ++- tools/terrain/SRTM_to_STL_example.py | 4 ++-- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/amr-wind/equation_systems/temperature/source_terms/DragTempForcing.H b/amr-wind/equation_systems/temperature/source_terms/DragTempForcing.H index 1a69a04865..7497f4fe0c 100644 --- a/amr-wind/equation_systems/temperature/source_terms/DragTempForcing.H +++ b/amr-wind/equation_systems/temperature/source_terms/DragTempForcing.H @@ -30,6 +30,7 @@ public: const amrex::Array4& src_term) const override; private: + const amrex::AmrCore& m_mesh; Field& m_temperature; Field& m_terrainBlank; amrex::Real m_drag{10.0}; diff --git a/amr-wind/equation_systems/temperature/source_terms/DragTempForcing.cpp b/amr-wind/equation_systems/temperature/source_terms/DragTempForcing.cpp index 1e7957f54b..7dc3020f6d 100644 --- a/amr-wind/equation_systems/temperature/source_terms/DragTempForcing.cpp +++ b/amr-wind/equation_systems/temperature/source_terms/DragTempForcing.cpp @@ -8,7 +8,8 @@ namespace amr_wind::pde::temperature { DragTempForcing::DragTempForcing(const CFDSim& sim) - : m_temperature(sim.repo().get_field("temperature")) + : m_mesh(sim.mesh()) + , m_temperature(sim.repo().get_field("temperature")) , m_terrainBlank(sim.repo().get_field("terrainBlank")) { amrex::ParmParse pp("DragTempForcing"); diff --git a/tools/terrain/SRTM_to_STL_example.py b/tools/terrain/SRTM_to_STL_example.py index cc756d895c..e64f654839 100644 --- a/tools/terrain/SRTM_to_STL_example.py +++ b/tools/terrain/SRTM_to_STL_example.py @@ -32,13 +32,13 @@ def SRTM_Converter(outputDir,refLat,refLon,refHeight,left,right,bottom,top): # The following cell should be modified by the user, following the examples given. The cell contains information about the actual location to be saved. # - # The `refloc` variable is the location coresponding to (0,0) in SOWFA. + # The `refloc` variable is the location corresponding to (0,0) in SOWFA. # # Set the fringe on each side of the domain. This fringe region will used to blend the high-resolution SRTM domain data with either i) low-reosolution WRF (mesoscale) digital elevation model (DEM), or ii) flat. # # If `getWRFdata` above is `True`, then blending to mesoscale will occur; otherwise, the domain will be blended to flat. If blending to flat, the user can specify an extra fringe region of completely flat domain (`fringe_flat`). Additionally, if blending to flat, the terrain surface data can be shifted vertically such that the flat region is at $z=0$ by setting `shiftFlatToZero` to `True`. # - # With respect to the bounding box, it is nice to have the boundaries exactly where the mesh would go because of the blending. For instance, a 5x5 km domain needs to match all the levels of cells: 20, 40, 80, 160 m. Essentially, 5000/160 needs to be an integer number, the same way 5000/80 needs to be as well. However, we only really need to match the coarsest resolution because they are multiple. Finally, an extra fringe of width `ds` (the resolution set above) is added, half on each side. The desired bounding box should go into the `xmin`,`xmax`,`ymin`,`ymax` variables, ignoring the `ds` addition. This extra fringe is to ensure that the STL is slighly larger than the bounding box that will be set on the microscale solver (needed in OpenFOAM to avoid numerical issues). + # With respect to the bounding box, it is nice to have the boundaries exactly where the mesh would go because of the blending. For instance, a 5x5 km domain needs to match all the levels of cells: 20, 40, 80, 160 m. Essentially, 5000/160 needs to be an integer number, the same way 5000/80 needs to be as well. However, we only really need to match the coarsest resolution because they are multiple. Finally, an extra fringe of width `ds` (the resolution set above) is added, half on each side. The desired bounding box should go into the `xmin`,`xmax`,`ymin`,`ymax` variables, ignoring the `ds` addition. This extra fringe is to ensure that the STL is slightly larger than the bounding box that will be set on the microscale solver (needed in OpenFOAM to avoid numerical issues). # For WFIP2 region From 7e8a3dbaee9f8431084b36d75c4f9f4d08b9e0d3 Mon Sep 17 00:00:00 2001 From: hgopalan Date: Tue, 2 Jul 2024 12:29:18 -0600 Subject: [PATCH 22/77] fstate commented out --- .../equation_systems/temperature/source_terms/DragTempForcing.H | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/amr-wind/equation_systems/temperature/source_terms/DragTempForcing.H b/amr-wind/equation_systems/temperature/source_terms/DragTempForcing.H index 7497f4fe0c..d47e2e2a40 100644 --- a/amr-wind/equation_systems/temperature/source_terms/DragTempForcing.H +++ b/amr-wind/equation_systems/temperature/source_terms/DragTempForcing.H @@ -26,7 +26,7 @@ public: const int lev, const amrex::MFIter& mfi, const amrex::Box& bx, - const FieldState fstate, + const FieldState /*fstate*/, const amrex::Array4& src_term) const override; private: From 287d4b1d6967dd4563a2d0ab27d282e724b91faf Mon Sep 17 00:00:00 2001 From: hgopalan Date: Tue, 2 Jul 2024 12:30:20 -0600 Subject: [PATCH 23/77] fstate --- .../temperature/source_terms/DragTempForcing.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/amr-wind/equation_systems/temperature/source_terms/DragTempForcing.cpp b/amr-wind/equation_systems/temperature/source_terms/DragTempForcing.cpp index 7dc3020f6d..6093042df0 100644 --- a/amr-wind/equation_systems/temperature/source_terms/DragTempForcing.cpp +++ b/amr-wind/equation_systems/temperature/source_terms/DragTempForcing.cpp @@ -22,7 +22,7 @@ void DragTempForcing::operator()( const int lev, const amrex::MFIter& mfi, const amrex::Box& bx, - const FieldState fstate, + const FieldState /*fstate*/, const amrex::Array4& src_term) const { const auto temperature = m_temperature(lev).const_array(mfi); From 37abe4be44aa7ada83281234a287c52cf5015e52 Mon Sep 17 00:00:00 2001 From: hgopalan Date: Tue, 2 Jul 2024 13:04:54 -0600 Subject: [PATCH 24/77] Lint-clang-tidy formatting --- amr-wind/equation_systems/icns/source_terms/DragForcing.cpp | 4 ++-- amr-wind/physics/TerrainDrag.cpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/amr-wind/equation_systems/icns/source_terms/DragForcing.cpp b/amr-wind/equation_systems/icns/source_terms/DragForcing.cpp index 2a5c73f9df..21ae0dc142 100644 --- a/amr-wind/equation_systems/icns/source_terms/DragForcing.cpp +++ b/amr-wind/equation_systems/icns/source_terms/DragForcing.cpp @@ -15,7 +15,7 @@ DragForcing::DragForcing(const CFDSim& sim) , m_terrainDrag(sim.repo().get_field("terrainDrag")) , m_terrainz0(sim.repo().get_field("terrainz0")) { - auto& phy_mgr = m_sim.physics_manager(); + const auto& phy_mgr = m_sim.physics_manager(); if (phy_mgr.contains("ABL")) { const auto& abl = m_sim.physics_manager().get(); const VelPlaneAveraging& fa_velocity = @@ -66,7 +66,7 @@ void DragForcing::operator()( // Copy Data const auto* local_gpu_vel_ht = gpu_vel_ht.data(); const auto* local_gpu_vel_vals = gpu_vel_vals.data(); - const amrex::Real vsize = gpu_vel_ht.size(); + int vsize = gpu_vel_ht.size(); amrex::ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept { const amrex::Real x1 = prob_lo[0] + (i + 0.5) * dx[0]; const amrex::Real x2 = prob_lo[1] + (j + 0.5) * dx[1]; diff --git a/amr-wind/physics/TerrainDrag.cpp b/amr-wind/physics/TerrainDrag.cpp index cbe7d94cb2..73259cd490 100644 --- a/amr-wind/physics/TerrainDrag.cpp +++ b/amr-wind/physics/TerrainDrag.cpp @@ -97,8 +97,8 @@ void TerrainDrag::post_init_actions() auto levelBlanking = blanking.array(mfi); auto levelDrag = drag.array(mfi); auto levelz0 = terrainz0.array(mfi); - const amrex::Real terrainSize = m_xterrain.size(); - const amrex::Real roughnessSize = m_xrough.size(); + int terrainSize = m_xterrain.size(); + int roughnessSize = m_xrough.size(); amrex::ParallelFor( vbx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept { // compute the source term From 41beae080832ed9948b94cc3823a711543367e45 Mon Sep 17 00:00:00 2001 From: hgopalan Date: Tue, 2 Jul 2024 13:09:54 -0600 Subject: [PATCH 25/77] Minnor commend changes --- .../equation_systems/icns/source_terms/DragForcing.H | 8 ++++---- .../temperature/source_terms/DragTempForcing.H | 12 ++++++------ 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/amr-wind/equation_systems/icns/source_terms/DragForcing.H b/amr-wind/equation_systems/icns/source_terms/DragForcing.H index 411a895530..a7680fe4eb 100644 --- a/amr-wind/equation_systems/icns/source_terms/DragForcing.H +++ b/amr-wind/equation_systems/icns/source_terms/DragForcing.H @@ -7,11 +7,11 @@ namespace amr_wind::pde::icns { -/** Adds the non-linear terms from the Kosovic Model to Momentum Equation.. +/** Adds the forcing term to include the presence of immersed boundary * - * \ingroup icns_src NonLinearSGS + * \ingroup icns_src * - * \sa NonLinearSGS + * */ class DragForcing : public MomentumSource::Register { @@ -48,4 +48,4 @@ private: } // namespace amr_wind::pde::icns -#endif /* NONLINEARSGSTERM_H */ +#endif diff --git a/amr-wind/equation_systems/temperature/source_terms/DragTempForcing.H b/amr-wind/equation_systems/temperature/source_terms/DragTempForcing.H index d47e2e2a40..74faa3b746 100644 --- a/amr-wind/equation_systems/temperature/source_terms/DragTempForcing.H +++ b/amr-wind/equation_systems/temperature/source_terms/DragTempForcing.H @@ -1,5 +1,5 @@ -#ifndef DRAGFORCING_H -#define DRAGFORCING_H +#ifndef DRAGTEMPFORCING_H +#define DRAGTEMPFORCING_H #include "amr-wind/equation_systems/temperature/TemperatureSource.H" #include "amr-wind/core/SimTime.H" @@ -7,11 +7,11 @@ namespace amr_wind::pde::temperature { -/** Adds the non-linear terms from the Kosovic Model to Temperature Equation.. +/** Adding the source term to momentum equation to account for immersed boundary. * - * \ingroup temperature_src NonLinearSGS + * \ingroup temperature_src * - * \sa NonLinearSGS + * */ class DragTempForcing : public TemperatureSource::Register { @@ -38,4 +38,4 @@ private: } // namespace amr_wind::pde::temperature -#endif /* NONLINEARSGSTERM_H */ +#endif From b270562b58c03f07d836ca095fbab4323aab86f1 Mon Sep 17 00:00:00 2001 From: hgopalan Date: Tue, 2 Jul 2024 13:12:51 -0600 Subject: [PATCH 26/77] Clang Formatting --- .../equation_systems/icns/source_terms/DragForcing.H | 8 ++++---- .../temperature/source_terms/DragTempForcing.H | 9 +++++---- amr-wind/physics/TerrainDrag.H | 2 -- 3 files changed, 9 insertions(+), 10 deletions(-) diff --git a/amr-wind/equation_systems/icns/source_terms/DragForcing.H b/amr-wind/equation_systems/icns/source_terms/DragForcing.H index a7680fe4eb..7018ad0a3e 100644 --- a/amr-wind/equation_systems/icns/source_terms/DragForcing.H +++ b/amr-wind/equation_systems/icns/source_terms/DragForcing.H @@ -7,11 +7,11 @@ namespace amr_wind::pde::icns { -/** Adds the forcing term to include the presence of immersed boundary +/** Adds the forcing term to include the presence of immersed boundary + * + * \ingroup icns_src * - * \ingroup icns_src * - * */ class DragForcing : public MomentumSource::Register { @@ -48,4 +48,4 @@ private: } // namespace amr_wind::pde::icns -#endif +#endif diff --git a/amr-wind/equation_systems/temperature/source_terms/DragTempForcing.H b/amr-wind/equation_systems/temperature/source_terms/DragTempForcing.H index 74faa3b746..6e6017acd9 100644 --- a/amr-wind/equation_systems/temperature/source_terms/DragTempForcing.H +++ b/amr-wind/equation_systems/temperature/source_terms/DragTempForcing.H @@ -7,11 +7,12 @@ namespace amr_wind::pde::temperature { -/** Adding the source term to momentum equation to account for immersed boundary. +/** Adding the source term to momentum equation to account for immersed + * boundary. + * + * \ingroup temperature_src * - * \ingroup temperature_src * - * */ class DragTempForcing : public TemperatureSource::Register { @@ -38,4 +39,4 @@ private: } // namespace amr_wind::pde::temperature -#endif +#endif diff --git a/amr-wind/physics/TerrainDrag.H b/amr-wind/physics/TerrainDrag.H index b413a662e5..4f88103631 100644 --- a/amr-wind/physics/TerrainDrag.H +++ b/amr-wind/physics/TerrainDrag.H @@ -36,8 +36,6 @@ public: void post_advance_work() override {} - // amrex::Real computeTerrainHeight(const amrex::Real x1,const - // amrex::Real x2) const; private: CFDSim& m_sim; const FieldRepo& m_repo; From 702b7624d19ee0bc7108f605bca5993cc39d24cf Mon Sep 17 00:00:00 2001 From: hgopalan Date: Tue, 2 Jul 2024 13:28:45 -0600 Subject: [PATCH 27/77] Updating int to const unsigned --- amr-wind/equation_systems/icns/source_terms/DragForcing.cpp | 2 +- amr-wind/physics/TerrainDrag.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/amr-wind/equation_systems/icns/source_terms/DragForcing.cpp b/amr-wind/equation_systems/icns/source_terms/DragForcing.cpp index 21ae0dc142..34658a0ddc 100644 --- a/amr-wind/equation_systems/icns/source_terms/DragForcing.cpp +++ b/amr-wind/equation_systems/icns/source_terms/DragForcing.cpp @@ -66,7 +66,7 @@ void DragForcing::operator()( // Copy Data const auto* local_gpu_vel_ht = gpu_vel_ht.data(); const auto* local_gpu_vel_vals = gpu_vel_vals.data(); - int vsize = gpu_vel_ht.size(); + const unsigned vsize = gpu_vel_ht.size(); amrex::ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept { const amrex::Real x1 = prob_lo[0] + (i + 0.5) * dx[0]; const amrex::Real x2 = prob_lo[1] + (j + 0.5) * dx[1]; diff --git a/amr-wind/physics/TerrainDrag.cpp b/amr-wind/physics/TerrainDrag.cpp index 73259cd490..39d9e80e32 100644 --- a/amr-wind/physics/TerrainDrag.cpp +++ b/amr-wind/physics/TerrainDrag.cpp @@ -97,8 +97,8 @@ void TerrainDrag::post_init_actions() auto levelBlanking = blanking.array(mfi); auto levelDrag = drag.array(mfi); auto levelz0 = terrainz0.array(mfi); - int terrainSize = m_xterrain.size(); - int roughnessSize = m_xrough.size(); + const unsigned terrainSize = m_xterrain.size(); + const unsigned roughnessSize = m_xrough.size(); amrex::ParallelFor( vbx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept { // compute the source term From 6ba2347ecee570d66c875bc680202f853e38a879 Mon Sep 17 00:00:00 2001 From: hgopalan Date: Tue, 2 Jul 2024 13:30:06 -0600 Subject: [PATCH 28/77] Clang --- amr-wind/physics/TerrainDrag.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/amr-wind/physics/TerrainDrag.cpp b/amr-wind/physics/TerrainDrag.cpp index 39d9e80e32..6aba33f8cc 100644 --- a/amr-wind/physics/TerrainDrag.cpp +++ b/amr-wind/physics/TerrainDrag.cpp @@ -97,7 +97,7 @@ void TerrainDrag::post_init_actions() auto levelBlanking = blanking.array(mfi); auto levelDrag = drag.array(mfi); auto levelz0 = terrainz0.array(mfi); - const unsigned terrainSize = m_xterrain.size(); + const unsigned terrainSize = m_xterrain.size(); const unsigned roughnessSize = m_xrough.size(); amrex::ParallelFor( vbx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept { From 2e4e7809b08ade9abc481646b3cbbfab6b8a8076 Mon Sep 17 00:00:00 2001 From: hgopalan Date: Tue, 2 Jul 2024 13:33:11 -0600 Subject: [PATCH 29/77] integer issues --- amr-wind/equation_systems/icns/source_terms/DragForcing.cpp | 2 +- amr-wind/physics/TerrainDrag.cpp | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/amr-wind/equation_systems/icns/source_terms/DragForcing.cpp b/amr-wind/equation_systems/icns/source_terms/DragForcing.cpp index 34658a0ddc..eee0d9ade9 100644 --- a/amr-wind/equation_systems/icns/source_terms/DragForcing.cpp +++ b/amr-wind/equation_systems/icns/source_terms/DragForcing.cpp @@ -89,7 +89,7 @@ void DragForcing::operator()( amrex::Real gpu_spongeVelZ = 0.0; amrex::Real residual = 1000; amrex::Real height_error = 0.0; - for (int ii = 0; ii < vsize; ++ii) { + for (const unsigned ii = 0; ii < vsize; ++ii) { height_error = std::abs(x3 - local_gpu_vel_ht[ii]); if (height_error < residual) { residual = height_error; diff --git a/amr-wind/physics/TerrainDrag.cpp b/amr-wind/physics/TerrainDrag.cpp index 6aba33f8cc..97775ab1a4 100644 --- a/amr-wind/physics/TerrainDrag.cpp +++ b/amr-wind/physics/TerrainDrag.cpp @@ -108,7 +108,7 @@ void TerrainDrag::post_init_actions() // Terrain Height amrex::Real residual = 10000; amrex::Real terrainHt = 0.0; - for (int ii = 0; ii < terrainSize; ++ii) { + for (const unsigned ii = 0; ii < terrainSize; ++ii) { const amrex::Real radius = std::sqrt( std::pow(x1 - xterrain_ptr[ii], 2) + std::pow(x2 - yterrain_ptr[ii], 2)); @@ -124,7 +124,7 @@ void TerrainDrag::post_init_actions() levelBlanking(i, j, k, 0) = turnOn; residual = 10000; amrex::Real roughz0 = 0.1; - for (int ii = 0; ii < roughnessSize; ++ii) { + for (const unsigned ii = 0; ii < roughnessSize; ++ii) { const amrex::Real radius = std::sqrt( std::pow(x1 - xrough_ptr[ii], 2) + std::pow(x2 - yrough_ptr[ii], 2)); @@ -146,7 +146,7 @@ void TerrainDrag::post_init_actions() const amrex::Real x1 = prob_lo[0] + (i + 0.5) * dx[0]; const amrex::Real x2 = prob_lo[1] + (j + 0.5) * dx[1]; const amrex::Real x3 = prob_lo[2] + (k + 0.5) * dx[2]; - for (int ii = 0; ii < terrainSize; ++ii) { + for (const unsigned ii = 0; ii < terrainSize; ++ii) { const amrex::Real radius = std::sqrt( std::pow(x1 - xterrain_ptr[ii], 2) + std::pow(x2 - yterrain_ptr[ii], 2)); From c5549c34673494e6d5a0c405eb4b5869060a61d6 Mon Sep 17 00:00:00 2001 From: hgopalan Date: Tue, 2 Jul 2024 13:34:32 -0600 Subject: [PATCH 30/77] Formatting --- amr-wind/physics/TerrainDrag.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/amr-wind/physics/TerrainDrag.cpp b/amr-wind/physics/TerrainDrag.cpp index 97775ab1a4..fa1e5ba109 100644 --- a/amr-wind/physics/TerrainDrag.cpp +++ b/amr-wind/physics/TerrainDrag.cpp @@ -124,7 +124,7 @@ void TerrainDrag::post_init_actions() levelBlanking(i, j, k, 0) = turnOn; residual = 10000; amrex::Real roughz0 = 0.1; - for (const unsigned ii = 0; ii < roughnessSize; ++ii) { + for (const unsigned ii = 0; ii < roughnessSize; ++ii) { const amrex::Real radius = std::sqrt( std::pow(x1 - xrough_ptr[ii], 2) + std::pow(x2 - yrough_ptr[ii], 2)); From 25840f0c6d4e5678b7734475a9a935d9f85a7ea7 Mon Sep 17 00:00:00 2001 From: hgopalan Date: Tue, 2 Jul 2024 13:36:38 -0600 Subject: [PATCH 31/77] unsigned --- amr-wind/equation_systems/icns/source_terms/DragForcing.cpp | 2 +- amr-wind/physics/TerrainDrag.cpp | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/amr-wind/equation_systems/icns/source_terms/DragForcing.cpp b/amr-wind/equation_systems/icns/source_terms/DragForcing.cpp index eee0d9ade9..c7067ecd66 100644 --- a/amr-wind/equation_systems/icns/source_terms/DragForcing.cpp +++ b/amr-wind/equation_systems/icns/source_terms/DragForcing.cpp @@ -89,7 +89,7 @@ void DragForcing::operator()( amrex::Real gpu_spongeVelZ = 0.0; amrex::Real residual = 1000; amrex::Real height_error = 0.0; - for (const unsigned ii = 0; ii < vsize; ++ii) { + for (unsigned ii = 0; ii < vsize; ++ii) { height_error = std::abs(x3 - local_gpu_vel_ht[ii]); if (height_error < residual) { residual = height_error; diff --git a/amr-wind/physics/TerrainDrag.cpp b/amr-wind/physics/TerrainDrag.cpp index fa1e5ba109..dca57d437d 100644 --- a/amr-wind/physics/TerrainDrag.cpp +++ b/amr-wind/physics/TerrainDrag.cpp @@ -108,7 +108,7 @@ void TerrainDrag::post_init_actions() // Terrain Height amrex::Real residual = 10000; amrex::Real terrainHt = 0.0; - for (const unsigned ii = 0; ii < terrainSize; ++ii) { + for (unsigned ii = 0; ii < terrainSize; ++ii) { const amrex::Real radius = std::sqrt( std::pow(x1 - xterrain_ptr[ii], 2) + std::pow(x2 - yterrain_ptr[ii], 2)); @@ -124,7 +124,7 @@ void TerrainDrag::post_init_actions() levelBlanking(i, j, k, 0) = turnOn; residual = 10000; amrex::Real roughz0 = 0.1; - for (const unsigned ii = 0; ii < roughnessSize; ++ii) { + for (unsigned ii = 0; ii < roughnessSize; ++ii) { const amrex::Real radius = std::sqrt( std::pow(x1 - xrough_ptr[ii], 2) + std::pow(x2 - yrough_ptr[ii], 2)); @@ -146,7 +146,7 @@ void TerrainDrag::post_init_actions() const amrex::Real x1 = prob_lo[0] + (i + 0.5) * dx[0]; const amrex::Real x2 = prob_lo[1] + (j + 0.5) * dx[1]; const amrex::Real x3 = prob_lo[2] + (k + 0.5) * dx[2]; - for (const unsigned ii = 0; ii < terrainSize; ++ii) { + for (unsigned ii = 0; ii < terrainSize; ++ii) { const amrex::Real radius = std::sqrt( std::pow(x1 - xterrain_ptr[ii], 2) + std::pow(x2 - yterrain_ptr[ii], 2)); From 34416ccff8eee2ecd97d63fab020cab99fc8c14c Mon Sep 17 00:00:00 2001 From: hgopalan Date: Tue, 2 Jul 2024 14:05:29 -0600 Subject: [PATCH 32/77] clang-tidy error for unsigned int --- .../equation_systems/icns/source_terms/DragForcing.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/amr-wind/equation_systems/icns/source_terms/DragForcing.cpp b/amr-wind/equation_systems/icns/source_terms/DragForcing.cpp index c7067ecd66..eb5f676bfa 100644 --- a/amr-wind/equation_systems/icns/source_terms/DragForcing.cpp +++ b/amr-wind/equation_systems/icns/source_terms/DragForcing.cpp @@ -93,9 +93,12 @@ void DragForcing::operator()( height_error = std::abs(x3 - local_gpu_vel_ht[ii]); if (height_error < residual) { residual = height_error; - gpu_spongeVelX = local_gpu_vel_vals[3 * ii]; - gpu_spongeVelY = local_gpu_vel_vals[3 * ii + 1]; - gpu_spongeVelZ = local_gpu_vel_vals[3 * ii + 2]; + const unsigned ix = 3*ii; + const unsigned iy = 3*ii+1; + const unsigned iz = 3*ii+2; + gpu_spongeVelX = local_gpu_vel_vals[ix]; + gpu_spongeVelY = local_gpu_vel_vals[iy]; + gpu_spongeVelZ = local_gpu_vel_vals[iz]; } } // Terrain Drag From 45b6b3f2a217427c76f97830c446d23bca48f11d Mon Sep 17 00:00:00 2001 From: hgopalan Date: Tue, 2 Jul 2024 14:07:41 -0600 Subject: [PATCH 33/77] Clang Format --- amr-wind/equation_systems/icns/source_terms/DragForcing.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/amr-wind/equation_systems/icns/source_terms/DragForcing.cpp b/amr-wind/equation_systems/icns/source_terms/DragForcing.cpp index eb5f676bfa..eaadaa83aa 100644 --- a/amr-wind/equation_systems/icns/source_terms/DragForcing.cpp +++ b/amr-wind/equation_systems/icns/source_terms/DragForcing.cpp @@ -93,9 +93,9 @@ void DragForcing::operator()( height_error = std::abs(x3 - local_gpu_vel_ht[ii]); if (height_error < residual) { residual = height_error; - const unsigned ix = 3*ii; - const unsigned iy = 3*ii+1; - const unsigned iz = 3*ii+2; + const unsigned ix = 3 * ii; + const unsigned iy = 3 * ii + 1; + const unsigned iz = 3 * ii + 2; gpu_spongeVelX = local_gpu_vel_vals[ix]; gpu_spongeVelY = local_gpu_vel_vals[iy]; gpu_spongeVelZ = local_gpu_vel_vals[iz]; From 2e22d481abc1eb158f31d8d44acb48fa43ec3118 Mon Sep 17 00:00:00 2001 From: hgopalan Date: Tue, 2 Jul 2024 14:37:17 -0600 Subject: [PATCH 34/77] Removing comment --- amr-wind/physics/TerrainDrag.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/amr-wind/physics/TerrainDrag.cpp b/amr-wind/physics/TerrainDrag.cpp index dca57d437d..94b96c3184 100644 --- a/amr-wind/physics/TerrainDrag.cpp +++ b/amr-wind/physics/TerrainDrag.cpp @@ -49,7 +49,6 @@ TerrainDrag::TerrainDrag(CFDSim& sim) void TerrainDrag::post_init_actions() { BL_PROFILE("amr-wind::" + this->identifier() + "::post_init_actions"); - // using namespace utils; const auto& geom_vec = m_sim.repo().mesh().Geom(); const int nlevels = m_sim.repo().num_active_levels(); for (int level = 0; level < nlevels; ++level) { From a9e2595d1676e5472e585d09500d4aa15221d98e Mon Sep 17 00:00:00 2001 From: hgopalan Date: Wed, 3 Jul 2024 11:17:58 -0600 Subject: [PATCH 35/77] Added a test case for Terrain --- test/CMakeLists.txt | 1 + test/test_files/terrainbox/README | 6 ++ test/test_files/terrainbox/computeError.py | 13 +++++ test/test_files/terrainbox/createTerrain.py | 15 +++++ test/test_files/terrainbox/terrainBox.inp | 63 +++++++++++++++++++++ 5 files changed, 98 insertions(+) create mode 100644 test/test_files/terrainbox/README create mode 100644 test/test_files/terrainbox/computeError.py create mode 100644 test/test_files/terrainbox/createTerrain.py create mode 100644 test/test_files/terrainbox/terrainBox.inp diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index c368057145..cebc575090 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -242,6 +242,7 @@ add_test_re(burggraf_flow) add_test_re(abl_godunov_rayleigh_damping) add_test_re(rankine) add_test_re(rankine-sym) +add_test_re(terrainbox) if(NOT AMR_WIND_ENABLE_CUDA) add_test_re(ctv_godunov_plm) diff --git a/test/test_files/terrainbox/README b/test/test_files/terrainbox/README new file mode 100644 index 0000000000..27999b9031 --- /dev/null +++ b/test/test_files/terrainbox/README @@ -0,0 +1,6 @@ +This is a simple test case to verify the terrain setup. A box is created and a freestream velocity +is specified. Diffusion is turned off. The flow field is sampled inside the terrain region. The sampled +velocity should be a very small value (this method drives the cell center value towards zero). + +The createTerrain.py file can be used to change the size of the box and resolution. computeError.py file +returns the mean value inside the box. diff --git a/test/test_files/terrainbox/computeError.py b/test/test_files/terrainbox/computeError.py new file mode 100644 index 0000000000..e1aa123832 --- /dev/null +++ b/test/test_files/terrainbox/computeError.py @@ -0,0 +1,13 @@ +from netCDF4 import Dataset +import numpy as np + +data=Dataset("post_processing/sampling00000.nc") + +velocityX=data['volume1']['velocityx'] +velocityY=data['volume1']['velocityy'] +velocityZ=data['volume1']['velocityz'] +blank=data['volume1']['terrainBlank'] +for i in range(0,velocityX.shape[0]-1): + print(np.mean(velocityX[i][:]),np.mean(velocityY[i][:]),np.mean(velocityZ[i][:])) + + diff --git a/test/test_files/terrainbox/createTerrain.py b/test/test_files/terrainbox/createTerrain.py new file mode 100644 index 0000000000..d1ddf62267 --- /dev/null +++ b/test/test_files/terrainbox/createTerrain.py @@ -0,0 +1,15 @@ +import numpy as np + +x=np.linspace(0,1000,201) +y=np.linspace(0,1000,201) + +target=open("terrain.amrwind","w") +for i in range(0,len(x)): + for j in range(0,len(y)): + if(x[i]>=400 and x[i]<=600 and y[j]>=400 and y[j]<=600): + z=200 + else: + z=0 + target.write("%g %g %g\n"%(x[i],y[j],z)) +target.close() + diff --git a/test/test_files/terrainbox/terrainBox.inp b/test/test_files/terrainbox/terrainBox.inp new file mode 100644 index 0000000000..28d7467ff4 --- /dev/null +++ b/test/test_files/terrainbox/terrainBox.inp @@ -0,0 +1,63 @@ +#¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨# +# SIMULATION STOP # +#.......................................# +time.stop_time = -100.0 # Max (simulated) time to evolve +time.max_step = 1000 # Max number of time steps + +#¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨# +# TIME STEP COMPUTATION # +#.......................................# +time.fixed_dt = -1 # Use this constant dt if > 0 +time.cfl = 0.9 # CFL factor + +#¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨# +# INPUT AND OUTPUT # +#.......................................# +time.plot_interval = 1000000 # Steps between plot files +time.checkpoint_interval = -1 # Steps between checkpoint files + +#¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨# +# PHYSICS # +#.......................................# +ConstValue.density.value = 1.0 +ConstValue.velocity.value = 1.0 0.0 0.0 + +incflo.use_godunov = 1 +incflo.diffusion_type = 2 +incflo.do_initial_proj = 0 +incflo.initial_iterations = 0 +transport.viscosity = 1.0e-15 +transport.laminar_prandtl = 0.7 +transport.turbulent_prandtl = 0.3333 +turbulence.model = Laminar + +incflo.physics = FreeStream TerrainDrag +ICNS.source_terms = DragForcing +DragForcing.verificationMode = 1 +amr.n_cell = 56 56 104 # Grid cells at coarsest AMRlevel +amr.max_level = 0 # Max AMR level in hierarchy +geometry.prob_lo = 0 0 0 +geometry.prob_hi = 1024 1024 1024 +geometry.is_periodic = 0 0 0 # Periodicity x y z (0/1) + +# Boundary conditions +xlo.type = "mass_inflow" +xlo.density = 1.0 +xlo.velocity = 1.0 0.0 0.0 +xhi.type = "pressure_outflow" +ylo.type = "slip_wall" +yhi.type = "slip_wall" +zlo.type = "slip_wall" +zhi.type = "slip_wall" + +incflo.verbose = 0 # incflo_level +nodal_proj.verbose = 0 + + +incflo.post_processing = sampling +sampling.labels = volume1 +sampling.fields = velocity terrainBlank +sampling.volume1.type = VolumeSampler +sampling.volume1.hi = 600 600 200 +sampling.volume1.lo = 400 400 0 +sampling.volume1.num_points = 10 10 20 From 74b163e8705932eea0a68d938be7367555a5137a Mon Sep 17 00:00:00 2001 From: hgopalan Date: Wed, 3 Jul 2024 14:49:35 -0600 Subject: [PATCH 36/77] Removed unnecessary initialization of blanking fields and converted terrain-related fields to int fields --- .../icns/source_terms/DragForcing.H | 3 --- .../icns/source_terms/DragForcing.cpp | 16 ++++++++++------ .../temperature/source_terms/DragTempForcing.H | 2 +- .../temperature/source_terms/DragTempForcing.cpp | 11 ++++++++--- amr-wind/physics/TerrainDrag.H | 4 ++-- amr-wind/physics/TerrainDrag.cpp | 10 +++++----- 6 files changed, 26 insertions(+), 20 deletions(-) diff --git a/amr-wind/equation_systems/icns/source_terms/DragForcing.H b/amr-wind/equation_systems/icns/source_terms/DragForcing.H index 7018ad0a3e..33f08dcd4d 100644 --- a/amr-wind/equation_systems/icns/source_terms/DragForcing.H +++ b/amr-wind/equation_systems/icns/source_terms/DragForcing.H @@ -33,9 +33,6 @@ private: const CFDSim& m_sim; const amrex::AmrCore& m_mesh; const Field& m_velocity; - Field& m_terrainBlank; - Field& m_terrainDrag; - Field& m_terrainz0; amrex::Gpu::DeviceVector gpu_vel_ht; amrex::Gpu::DeviceVector gpu_vel_vals; amrex::Real m_drag{100.0}; diff --git a/amr-wind/equation_systems/icns/source_terms/DragForcing.cpp b/amr-wind/equation_systems/icns/source_terms/DragForcing.cpp index eaadaa83aa..bab343da04 100644 --- a/amr-wind/equation_systems/icns/source_terms/DragForcing.cpp +++ b/amr-wind/equation_systems/icns/source_terms/DragForcing.cpp @@ -11,9 +11,6 @@ DragForcing::DragForcing(const CFDSim& sim) : m_sim(sim) , m_mesh(sim.mesh()) , m_velocity(sim.repo().get_field("velocity")) - , m_terrainBlank(sim.repo().get_field("terrainBlank")) - , m_terrainDrag(sim.repo().get_field("terrainDrag")) - , m_terrainz0(sim.repo().get_field("terrainz0")) { const auto& phy_mgr = m_sim.physics_manager(); if (phy_mgr.contains("ABL")) { @@ -49,9 +46,16 @@ void DragForcing::operator()( { const auto& vel = m_velocity.state(field_impl::dof_state(fstate))(lev).const_array(mfi); - const auto blank = m_terrainBlank(lev).const_array(mfi); - const auto drag = m_terrainDrag(lev).const_array(mfi); - const auto terrainz0 = m_terrainz0(lev).const_array(mfi); + bool is_terrain = this->m_sim.repo().field_exists("terrainBlank"); + if (!is_terrain) { + amrex::Abort("Need terrain blanking variable to use this source term"); + } + const auto m_terrainBlank = &this->m_sim.repo().get_field("terrainBlank"); + const auto& blank = (*m_terrainBlank)(lev).const_array(mfi); + const auto m_terrainDrag = &this->m_sim.repo().get_field("terrainDrag"); + const auto& drag = (*m_terrainDrag)(lev).const_array(mfi); + const auto m_terrainz0 = &this->m_sim.repo().get_field("terrainz0"); + const auto& terrainz0 = (*m_terrainz0)(lev).const_array(mfi); const auto& geom_vec = m_mesh.Geom(); const auto& geom = geom_vec[lev]; const auto& dx = geom.CellSize(); diff --git a/amr-wind/equation_systems/temperature/source_terms/DragTempForcing.H b/amr-wind/equation_systems/temperature/source_terms/DragTempForcing.H index 6e6017acd9..8d3225e982 100644 --- a/amr-wind/equation_systems/temperature/source_terms/DragTempForcing.H +++ b/amr-wind/equation_systems/temperature/source_terms/DragTempForcing.H @@ -31,9 +31,9 @@ public: const amrex::Array4& src_term) const override; private: + const CFDSim& m_sim; const amrex::AmrCore& m_mesh; Field& m_temperature; - Field& m_terrainBlank; amrex::Real m_drag{10.0}; }; diff --git a/amr-wind/equation_systems/temperature/source_terms/DragTempForcing.cpp b/amr-wind/equation_systems/temperature/source_terms/DragTempForcing.cpp index 6093042df0..3aff910288 100644 --- a/amr-wind/equation_systems/temperature/source_terms/DragTempForcing.cpp +++ b/amr-wind/equation_systems/temperature/source_terms/DragTempForcing.cpp @@ -8,9 +8,9 @@ namespace amr_wind::pde::temperature { DragTempForcing::DragTempForcing(const CFDSim& sim) - : m_mesh(sim.mesh()) + : m_sim(sim) + , m_mesh(sim.mesh()) , m_temperature(sim.repo().get_field("temperature")) - , m_terrainBlank(sim.repo().get_field("terrainBlank")) { amrex::ParmParse pp("DragTempForcing"); pp.query("dragCoefficient", m_drag); @@ -26,7 +26,12 @@ void DragTempForcing::operator()( const amrex::Array4& src_term) const { const auto temperature = m_temperature(lev).const_array(mfi); - const auto blank = m_terrainBlank(lev).const_array(mfi); + bool is_terrain = this->m_sim.repo().field_exists("terrainBlank"); + if (!is_terrain) { + amrex::Abort("Need terrain blanking variable to use this source term"); + } + const auto m_terrainBlank = &this->m_sim.repo().get_field("terrainBlank"); + const auto& blank = (*m_terrainBlank)(lev).const_array(mfi); const auto& geom_vec = m_mesh.Geom(); const auto& geom = geom_vec[lev]; const auto& dx = geom.CellSize(); diff --git a/amr-wind/physics/TerrainDrag.H b/amr-wind/physics/TerrainDrag.H index 4f88103631..3436b5b6a6 100644 --- a/amr-wind/physics/TerrainDrag.H +++ b/amr-wind/physics/TerrainDrag.H @@ -42,9 +42,9 @@ private: const amrex::AmrCore& m_mesh; Field& m_velocity; // Blanking Field for Terrain or Buildings - Field& m_terrainBlank; + IntField& m_terrainBlank; // Terrain Drag Force Term - Field& m_terrainDrag; + IntField& m_terrainDrag; // Reading the Terrain Coordinates from file amrex::Vector m_xterrain, m_yterrain, m_zterrain; // Roughness Field diff --git a/amr-wind/physics/TerrainDrag.cpp b/amr-wind/physics/TerrainDrag.cpp index 94b96c3184..2d20677c2d 100644 --- a/amr-wind/physics/TerrainDrag.cpp +++ b/amr-wind/physics/TerrainDrag.cpp @@ -16,8 +16,8 @@ TerrainDrag::TerrainDrag(CFDSim& sim) , m_repo(sim.repo()) , m_mesh(sim.mesh()) , m_velocity(sim.repo().get_field("velocity")) - , m_terrainBlank(sim.repo().declare_field("terrainBlank", 1, 1, 1)) - , m_terrainDrag(sim.repo().declare_field("terrainDrag", 1, 1, 1)) + , m_terrainBlank(sim.repo().declare_int_field("terrainBlank", 1, 1, 1)) + , m_terrainDrag(sim.repo().declare_int_field("terrainDrag", 1, 1, 1)) , m_terrainz0(sim.repo().declare_field("terrainz0", 1, 1, 1)) { std::string terrainfile("terrain.amrwind"); @@ -119,7 +119,7 @@ void TerrainDrag::post_init_actions() break; } } - const amrex::Real turnOn = (x3 <= terrainHt) ? 1.0 : 0.0; + const unsigned turnOn = (x3 <= terrainHt) ? 1 : 0; levelBlanking(i, j, k, 0) = turnOn; residual = 10000; amrex::Real roughz0 = 0.1; @@ -154,10 +154,10 @@ void TerrainDrag::post_init_actions() terrainHt = zterrain_ptr[ii]; } } - levelDrag(i, j, k, 0) = 0.0; + levelDrag(i, j, k, 0) = 0; if (x3 > terrainHt && k > 0 && levelBlanking(i, j, k - 1, 0) == 1) { - levelDrag(i, j, k, 0) = 1.0; + levelDrag(i, j, k, 0) = 1; } }); } From 890e8feebfeddedacbc84f0d9313c5723cae50e3 Mon Sep 17 00:00:00 2001 From: hgopalan Date: Wed, 3 Jul 2024 18:22:57 -0600 Subject: [PATCH 37/77] Added Unit Test --- .../icns/source_terms/DragForcing.cpp | 6 +- .../source_terms/DragTempForcing.cpp | 2 +- amr-wind/physics/TerrainDrag.H | 2 + amr-wind/physics/TerrainDrag.cpp | 12 ++- unit_tests/wind_energy/CMakeLists.txt | 1 + unit_tests/wind_energy/test_abl_terrain.cpp | 84 +++++++++++++++++++ 6 files changed, 101 insertions(+), 6 deletions(-) create mode 100644 unit_tests/wind_energy/test_abl_terrain.cpp diff --git a/amr-wind/equation_systems/icns/source_terms/DragForcing.cpp b/amr-wind/equation_systems/icns/source_terms/DragForcing.cpp index bab343da04..06df716e7d 100644 --- a/amr-wind/equation_systems/icns/source_terms/DragForcing.cpp +++ b/amr-wind/equation_systems/icns/source_terms/DragForcing.cpp @@ -50,11 +50,11 @@ void DragForcing::operator()( if (!is_terrain) { amrex::Abort("Need terrain blanking variable to use this source term"); } - const auto m_terrainBlank = &this->m_sim.repo().get_field("terrainBlank"); + auto* const m_terrainBlank = &this->m_sim.repo().get_field("terrainBlank"); const auto& blank = (*m_terrainBlank)(lev).const_array(mfi); - const auto m_terrainDrag = &this->m_sim.repo().get_field("terrainDrag"); + auto* const m_terrainDrag = &this->m_sim.repo().get_field("terrainDrag"); const auto& drag = (*m_terrainDrag)(lev).const_array(mfi); - const auto m_terrainz0 = &this->m_sim.repo().get_field("terrainz0"); + auto* const m_terrainz0 = &this->m_sim.repo().get_field("terrainz0"); const auto& terrainz0 = (*m_terrainz0)(lev).const_array(mfi); const auto& geom_vec = m_mesh.Geom(); const auto& geom = geom_vec[lev]; diff --git a/amr-wind/equation_systems/temperature/source_terms/DragTempForcing.cpp b/amr-wind/equation_systems/temperature/source_terms/DragTempForcing.cpp index 3aff910288..efddd8bd94 100644 --- a/amr-wind/equation_systems/temperature/source_terms/DragTempForcing.cpp +++ b/amr-wind/equation_systems/temperature/source_terms/DragTempForcing.cpp @@ -30,7 +30,7 @@ void DragTempForcing::operator()( if (!is_terrain) { amrex::Abort("Need terrain blanking variable to use this source term"); } - const auto m_terrainBlank = &this->m_sim.repo().get_field("terrainBlank"); + auto* const m_terrainBlank = &this->m_sim.repo().get_field("terrainBlank"); const auto& blank = (*m_terrainBlank)(lev).const_array(mfi); const auto& geom_vec = m_mesh.Geom(); const auto& geom = geom_vec[lev]; diff --git a/amr-wind/physics/TerrainDrag.H b/amr-wind/physics/TerrainDrag.H index 3436b5b6a6..dfa574b5f1 100644 --- a/amr-wind/physics/TerrainDrag.H +++ b/amr-wind/physics/TerrainDrag.H @@ -36,6 +36,8 @@ public: void post_advance_work() override {} + int returnBlankValue(int i,int j,int k); + private: CFDSim& m_sim; const FieldRepo& m_repo; diff --git a/amr-wind/physics/TerrainDrag.cpp b/amr-wind/physics/TerrainDrag.cpp index 2d20677c2d..749760255d 100644 --- a/amr-wind/physics/TerrainDrag.cpp +++ b/amr-wind/physics/TerrainDrag.cpp @@ -43,7 +43,7 @@ TerrainDrag::TerrainDrag(CFDSim& sim) file1.close(); m_sim.io_manager().register_io_var("terrainDrag"); m_sim.io_manager().register_io_var("terrainBlank"); - m_sim.io_manager().register_io_var("terrainz0"); + m_sim.io_manager().register_io_var("terrainz0"); } void TerrainDrag::post_init_actions() @@ -119,7 +119,7 @@ void TerrainDrag::post_init_actions() break; } } - const unsigned turnOn = (x3 <= terrainHt) ? 1 : 0; + int turnOn = (x3 <= terrainHt) ? 1 : 0; levelBlanking(i, j, k, 0) = turnOn; residual = 10000; amrex::Real roughz0 = 0.1; @@ -169,4 +169,12 @@ void TerrainDrag::pre_init_actions() BL_PROFILE("amr-wind::" + this->identifier() + "::pre_init_actions"); } +int TerrainDrag::returnBlankValue(int i,int j,int k) +{ + int lev=0; + amrex::MFIter mfi(m_terrainBlank(lev)); + const auto& levelBlanking = m_terrainBlank(lev).const_array(mfi); + return levelBlanking(i,j,k); +} + } // namespace amr_wind::terraindrag diff --git a/unit_tests/wind_energy/CMakeLists.txt b/unit_tests/wind_energy/CMakeLists.txt index 27b67c2541..be874a0e37 100644 --- a/unit_tests/wind_energy/CMakeLists.txt +++ b/unit_tests/wind_energy/CMakeLists.txt @@ -8,6 +8,7 @@ target_sources(${amr_wind_unit_test_exe_name} PRIVATE test_abl_stats.cpp test_abl_bc.cpp test_abl_src_timetable.cpp + test_abl_terrain.cpp ) if (AMR_WIND_ENABLE_NETCDF) diff --git a/unit_tests/wind_energy/test_abl_terrain.cpp b/unit_tests/wind_energy/test_abl_terrain.cpp new file mode 100644 index 0000000000..66b4365db5 --- /dev/null +++ b/unit_tests/wind_energy/test_abl_terrain.cpp @@ -0,0 +1,84 @@ +#include "aw_test_utils/MeshTest.H" +#include "aw_test_utils/iter_tools.H" +#include "aw_test_utils/test_utils.H" +#include "amr-wind/physics/TerrainDrag.H" + +namespace { +void write_terrain(const std::string& fname) +{ + std::ofstream os(fname); + // Write terrain height + os << "0.0\t0.0\t0.0\n"; + os << "0.0\t1024.0\t0.0\n"; + os << "448.0\t0.0\t0.0\n"; + os << "448.0\t1024.0\t0.0\n"; + os << "449.0\t0.0\t100.0\n"; + os << "449.0\t1024.0\t100.0\n"; + os << "576.0\t0.0\t100.0\n"; + os << "576.0\t1024.0\t100.0\n"; + os << "577.0\t0.0\t0.0\n"; + os << "577.0\t1024.0\t0.0\n"; + os << "1024.0\t0.0\t0.0\n"; + os << "1024.0\t1024.0\t0.0\n"; +} + +} // namespace + +namespace amr_wind_tests { + + +// Testing the terrain drag reading to ensure that terrain is properly setup +class terrainTest : public MeshTest +{ +protected: + void populate_parameters() override + { + MeshTest::populate_parameters(); + // Make computational domain like ABL mesh + { + amrex::ParmParse pp("amr"); + amrex::Vector ncell{{32,32,16}}; + pp.addarr("n_cell", ncell); + pp.add("blocking_factor", 2); + + } + + { + amrex::ParmParse pp("geometry"); + amrex::Vector probhi{{1024,1024,512}}; + pp.addarr("prob_hi", probhi); + } + + } + std::string terrain_fname = "terrain.amrwind"; +}; + +TEST_F(terrainTest, terrain) +{ + constexpr amrex::Real tol = 0; + + // Write target wind file + write_terrain(terrain_fname); + // Set up simulation parameters and mesh + populate_parameters(); + initialize_mesh(); + // Set up PDEs and physics objects + auto& pde_mgr = sim().pde_manager(); + pde_mgr.register_icns(); + sim().init_physics(); + amrex::ParmParse pp("incflo"); + amrex::Vector physics{"terrainDrag"}; + pp.addarr("physics", physics); + amr_wind::terraindrag::TerrainDrag terrain_drag(sim()); + terrain_drag.post_init_actions(); + int value=100; + // Outside Point + value=terrain_drag.returnBlankValue(5,5,1); + EXPECT_EQ(value,tol); + // Inside Point + value=terrain_drag.returnBlankValue(15,10,1); + EXPECT_EQ(value,1+tol); +} + + +} // namespace amr_wind_tests From 8ac13e1ab51a1b035c7858801915bdbaf3a61bd9 Mon Sep 17 00:00:00 2001 From: hgopalan Date: Wed, 3 Jul 2024 18:26:00 -0600 Subject: [PATCH 38/77] Clang Formatting for Unit Test --- amr-wind/physics/TerrainDrag.H | 2 +- amr-wind/physics/TerrainDrag.cpp | 10 ++++---- unit_tests/wind_energy/test_abl_terrain.cpp | 26 +++++++++------------ 3 files changed, 17 insertions(+), 21 deletions(-) diff --git a/amr-wind/physics/TerrainDrag.H b/amr-wind/physics/TerrainDrag.H index dfa574b5f1..c04ff2b75d 100644 --- a/amr-wind/physics/TerrainDrag.H +++ b/amr-wind/physics/TerrainDrag.H @@ -36,7 +36,7 @@ public: void post_advance_work() override {} - int returnBlankValue(int i,int j,int k); + int returnBlankValue(int i, int j, int k); private: CFDSim& m_sim; diff --git a/amr-wind/physics/TerrainDrag.cpp b/amr-wind/physics/TerrainDrag.cpp index 749760255d..b7fc2def92 100644 --- a/amr-wind/physics/TerrainDrag.cpp +++ b/amr-wind/physics/TerrainDrag.cpp @@ -43,7 +43,7 @@ TerrainDrag::TerrainDrag(CFDSim& sim) file1.close(); m_sim.io_manager().register_io_var("terrainDrag"); m_sim.io_manager().register_io_var("terrainBlank"); - m_sim.io_manager().register_io_var("terrainz0"); + m_sim.io_manager().register_io_var("terrainz0"); } void TerrainDrag::post_init_actions() @@ -169,12 +169,12 @@ void TerrainDrag::pre_init_actions() BL_PROFILE("amr-wind::" + this->identifier() + "::pre_init_actions"); } -int TerrainDrag::returnBlankValue(int i,int j,int k) +int TerrainDrag::returnBlankValue(int i, int j, int k) { - int lev=0; + int lev = 0; amrex::MFIter mfi(m_terrainBlank(lev)); - const auto& levelBlanking = m_terrainBlank(lev).const_array(mfi); - return levelBlanking(i,j,k); + const auto& levelBlanking = m_terrainBlank(lev).const_array(mfi); + return levelBlanking(i, j, k); } } // namespace amr_wind::terraindrag diff --git a/unit_tests/wind_energy/test_abl_terrain.cpp b/unit_tests/wind_energy/test_abl_terrain.cpp index 66b4365db5..cac5d07ba0 100644 --- a/unit_tests/wind_energy/test_abl_terrain.cpp +++ b/unit_tests/wind_energy/test_abl_terrain.cpp @@ -26,29 +26,26 @@ void write_terrain(const std::string& fname) namespace amr_wind_tests { - -// Testing the terrain drag reading to ensure that terrain is properly setup +// Testing the terrain drag reading to ensure that terrain is properly setup class terrainTest : public MeshTest { protected: - void populate_parameters() override + void populate_parameters() override { MeshTest::populate_parameters(); // Make computational domain like ABL mesh { amrex::ParmParse pp("amr"); - amrex::Vector ncell{{32,32,16}}; + amrex::Vector ncell{{32, 32, 16}}; pp.addarr("n_cell", ncell); pp.add("blocking_factor", 2); - } { amrex::ParmParse pp("geometry"); - amrex::Vector probhi{{1024,1024,512}}; + amrex::Vector probhi{{1024, 1024, 512}}; pp.addarr("prob_hi", probhi); } - } std::string terrain_fname = "terrain.amrwind"; }; @@ -71,14 +68,13 @@ TEST_F(terrainTest, terrain) pp.addarr("physics", physics); amr_wind::terraindrag::TerrainDrag terrain_drag(sim()); terrain_drag.post_init_actions(); - int value=100; - // Outside Point - value=terrain_drag.returnBlankValue(5,5,1); - EXPECT_EQ(value,tol); - // Inside Point - value=terrain_drag.returnBlankValue(15,10,1); - EXPECT_EQ(value,1+tol); + int value = 100; + // Outside Point + value = terrain_drag.returnBlankValue(5, 5, 1); + EXPECT_EQ(value, tol); + // Inside Point + value = terrain_drag.returnBlankValue(15, 10, 1); + EXPECT_EQ(value, 1 + tol); } - } // namespace amr_wind_tests From ad847198d4fdc2884a1f855a6d6da0f8ed81ee29 Mon Sep 17 00:00:00 2001 From: Harish Date: Wed, 3 Jul 2024 19:04:02 -0600 Subject: [PATCH 39/77] Update test_abl_terrain.cpp --- unit_tests/wind_energy/test_abl_terrain.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/unit_tests/wind_energy/test_abl_terrain.cpp b/unit_tests/wind_energy/test_abl_terrain.cpp index cac5d07ba0..51b0f54d18 100644 --- a/unit_tests/wind_energy/test_abl_terrain.cpp +++ b/unit_tests/wind_energy/test_abl_terrain.cpp @@ -56,10 +56,8 @@ TEST_F(terrainTest, terrain) // Write target wind file write_terrain(terrain_fname); - // Set up simulation parameters and mesh populate_parameters(); initialize_mesh(); - // Set up PDEs and physics objects auto& pde_mgr = sim().pde_manager(); pde_mgr.register_icns(); sim().init_physics(); From 63968e31f10610469771460903b7b35a0155040f Mon Sep 17 00:00:00 2001 From: hgopalan Date: Sat, 6 Jul 2024 14:44:26 -0600 Subject: [PATCH 40/77] Added a terrain case. --- .../icns/source_terms/DragForcing.H | 1 - .../icns/source_terms/DragForcing.cpp | 48 +++--- .../source_terms/DragTempForcing.H | 1 + .../source_terms/DragTempForcing.cpp | 3 +- amr-wind/physics/TerrainDrag.H | 4 +- amr-wind/physics/TerrainDrag.cpp | 6 +- test/CMakeLists.txt | 2 + .../nrel_precursor/nrel_precursor.inp | 93 ++++++++++++ test/test_files/nrel_terrain/README | 6 + test/test_files/nrel_terrain/nrel_terrain.inp | 93 ++++++++++++ test/test_files/nrel_terrain/nrelterrain.png | Bin 0 -> 301384 bytes tools/terrain/{sampleYaml.yaml => NREL.yaml} | 23 ++- tools/terrain/backendInterface.py | 143 +++++++++++------- tools/terrain/saveTurbines.py | 26 ---- 14 files changed, 327 insertions(+), 122 deletions(-) create mode 100644 test/test_files/nrel_precursor/nrel_precursor.inp create mode 100644 test/test_files/nrel_terrain/README create mode 100644 test/test_files/nrel_terrain/nrel_terrain.inp create mode 100644 test/test_files/nrel_terrain/nrelterrain.png rename tools/terrain/{sampleYaml.yaml => NREL.yaml} (65%) delete mode 100644 tools/terrain/saveTurbines.py diff --git a/amr-wind/equation_systems/icns/source_terms/DragForcing.H b/amr-wind/equation_systems/icns/source_terms/DragForcing.H index 33f08dcd4d..ff74503bad 100644 --- a/amr-wind/equation_systems/icns/source_terms/DragForcing.H +++ b/amr-wind/equation_systems/icns/source_terms/DragForcing.H @@ -40,7 +40,6 @@ private: amrex::Real m_spongeDensity{1.0}; amrex::Real m_spongeDistanceX{1000}; amrex::Real m_spongeDistanceY{1000}; - amrex::Real m_verificationMode{0}; }; } // namespace amr_wind::pde::icns diff --git a/amr-wind/equation_systems/icns/source_terms/DragForcing.cpp b/amr-wind/equation_systems/icns/source_terms/DragForcing.cpp index 06df716e7d..67920dd501 100644 --- a/amr-wind/equation_systems/icns/source_terms/DragForcing.cpp +++ b/amr-wind/equation_systems/icns/source_terms/DragForcing.cpp @@ -12,6 +12,12 @@ DragForcing::DragForcing(const CFDSim& sim) , m_mesh(sim.mesh()) , m_velocity(sim.repo().get_field("velocity")) { + amrex::ParmParse pp("DragForcing"); + pp.query("dragCoefficient", m_drag); + pp.query("spongeStrength", m_spongeStrength); + pp.query("spongeDensity", m_spongeDensity); + pp.query("spongeDistanceX", m_spongeDistanceX); + pp.query("spongeDistanceY", m_spongeDistanceY); const auto& phy_mgr = m_sim.physics_manager(); if (phy_mgr.contains("ABL")) { const auto& abl = m_sim.physics_manager().get(); @@ -25,14 +31,9 @@ DragForcing::DragForcing(const CFDSim& sim) amrex::Gpu::copy( amrex::Gpu::hostToDevice, fa_velocity.line_average().begin(), fa_velocity.line_average().end(), gpu_vel_vals.begin()); + } else { + m_spongeStrength = 0.0; } - amrex::ParmParse pp("DragForcing"); - pp.query("dragCoefficient", m_drag); - pp.query("spongeStrength", m_spongeStrength); - pp.query("spongeDensity", m_spongeDensity); - pp.query("spongeDistanceX", m_spongeDistanceX); - pp.query("spongeDistanceY", m_spongeDistanceY); - pp.query("verificationMode", m_verificationMode); } DragForcing::~DragForcing() = default; @@ -64,9 +65,14 @@ void DragForcing::operator()( const amrex::Real gpu_drag = m_drag; const amrex::Real gpu_spongeStrength = m_spongeStrength; const amrex::Real gpu_spongeDensity = m_spongeDensity; - const amrex::Real gpu_startX = prob_hi[0] - m_spongeDistanceX; - const amrex::Real gpu_startY = prob_hi[1] - m_spongeDistanceY; - const amrex::Real gpu_verificationMode = m_verificationMode; + const amrex::Real gpu_startX = (m_spongeDistanceX > 0) + ? prob_hi[0] - m_spongeDistanceX + : prob_lo[0] - m_spongeDistanceX; + const amrex::Real gpu_startY = (m_spongeDistanceY > 0) + ? prob_hi[1] - m_spongeDistanceY + : prob_lo[1] - m_spongeDistanceY; + const amrex::Real gpu_spongeX = (m_spongeDistanceX > 0) ? 1 : 0; + const amrex::Real gpu_spongeY = (m_spongeDistanceY > 0) ? 1 : 0; // Copy Data const auto* local_gpu_vel_ht = gpu_vel_ht.data(); const auto* local_gpu_vel_vals = gpu_vel_vals.data(); @@ -77,16 +83,16 @@ void DragForcing::operator()( const amrex::Real x3 = prob_lo[2] + (k + 0.5) * dx[2]; amrex::Real xdamping = 0; amrex::Real ydamping = 0; - if (x1 > gpu_startX) { - amrex::Real xi = (x1 - gpu_startX) / (prob_hi[0] - gpu_startX); - xdamping = - (1 - gpu_verificationMode) * gpu_spongeStrength * xi * xi; - } - if (x2 > gpu_startY) { - amrex::Real yi = (x2 - gpu_startY) / (prob_hi[1] - gpu_startY); - ydamping = - (1 - gpu_verificationMode) * gpu_spongeStrength * yi * yi; - } + amrex::Real xi = (gpu_spongeX == 1) + ? (x1 - gpu_startX) / (prob_hi[0] - gpu_startX) + : (gpu_startX - x1) / (gpu_startX - prob_lo[0]); + xi = std::max(xi, 0.0); + xdamping = gpu_spongeStrength * xi * xi; + amrex::Real yi = (gpu_spongeY == 1) + ? (x2 - gpu_startY) / (prob_hi[1] - gpu_startY) + : (gpu_startY - x2) / (gpu_startY - prob_lo[1]); + yi = std::max(yi, 0.0); + ydamping = gpu_spongeStrength * yi * yi; amrex::Real Cd = gpu_drag / dx[0]; amrex::Real gpu_spongeVelX = 0.0; amrex::Real gpu_spongeVelY = 0.0; @@ -119,7 +125,7 @@ void DragForcing::operator()( const amrex::Real m2 = std::sqrt(ux2 * ux2 + uy2 * uy2); const amrex::Real kappa = 0.41; const amrex::Real z0 = std::max(terrainz0(i, j, k), 1e-4); - const amrex::Real ustar = (1 - gpu_verificationMode) * + const amrex::Real ustar = std::min(gpu_spongeStrength, 1.0) * std::abs(m2 - m1) * kappa / std::log((x3 + z0) / z0); Dxz = -ustar * ustar * ux1 / diff --git a/amr-wind/equation_systems/temperature/source_terms/DragTempForcing.H b/amr-wind/equation_systems/temperature/source_terms/DragTempForcing.H index 8d3225e982..084e41ac6d 100644 --- a/amr-wind/equation_systems/temperature/source_terms/DragTempForcing.H +++ b/amr-wind/equation_systems/temperature/source_terms/DragTempForcing.H @@ -35,6 +35,7 @@ private: const amrex::AmrCore& m_mesh; Field& m_temperature; amrex::Real m_drag{10.0}; + amrex::Real m_internalRefT{300.0}; }; } // namespace amr_wind::pde::temperature diff --git a/amr-wind/equation_systems/temperature/source_terms/DragTempForcing.cpp b/amr-wind/equation_systems/temperature/source_terms/DragTempForcing.cpp index efddd8bd94..169a3269f4 100644 --- a/amr-wind/equation_systems/temperature/source_terms/DragTempForcing.cpp +++ b/amr-wind/equation_systems/temperature/source_terms/DragTempForcing.cpp @@ -14,6 +14,7 @@ DragTempForcing::DragTempForcing(const CFDSim& sim) { amrex::ParmParse pp("DragTempForcing"); pp.query("dragCoefficient", m_drag); + pp.query("RefT", m_internalRefT); } DragTempForcing::~DragTempForcing() = default; @@ -36,7 +37,7 @@ void DragTempForcing::operator()( const auto& geom = geom_vec[lev]; const auto& dx = geom.CellSize(); const amrex::Real gpu_drag = m_drag; - const amrex::Real gpu_TRef = 300.0; + const amrex::Real gpu_TRef = m_internalRefT; amrex::ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept { amrex::Real Cd = gpu_drag / dx[0]; src_term(i, j, k, 0) -= diff --git a/amr-wind/physics/TerrainDrag.H b/amr-wind/physics/TerrainDrag.H index c04ff2b75d..6f7c7d27db 100644 --- a/amr-wind/physics/TerrainDrag.H +++ b/amr-wind/physics/TerrainDrag.H @@ -44,9 +44,9 @@ private: const amrex::AmrCore& m_mesh; Field& m_velocity; // Blanking Field for Terrain or Buildings - IntField& m_terrainBlank; + Field& m_terrainBlank; // Terrain Drag Force Term - IntField& m_terrainDrag; + Field& m_terrainDrag; // Reading the Terrain Coordinates from file amrex::Vector m_xterrain, m_yterrain, m_zterrain; // Roughness Field diff --git a/amr-wind/physics/TerrainDrag.cpp b/amr-wind/physics/TerrainDrag.cpp index b7fc2def92..de923d8d2d 100644 --- a/amr-wind/physics/TerrainDrag.cpp +++ b/amr-wind/physics/TerrainDrag.cpp @@ -16,8 +16,8 @@ TerrainDrag::TerrainDrag(CFDSim& sim) , m_repo(sim.repo()) , m_mesh(sim.mesh()) , m_velocity(sim.repo().get_field("velocity")) - , m_terrainBlank(sim.repo().declare_int_field("terrainBlank", 1, 1, 1)) - , m_terrainDrag(sim.repo().declare_int_field("terrainDrag", 1, 1, 1)) + , m_terrainBlank(sim.repo().declare_field("terrainBlank", 1, 1, 1)) + , m_terrainDrag(sim.repo().declare_field("terrainDrag", 1, 1, 1)) , m_terrainz0(sim.repo().declare_field("terrainz0", 1, 1, 1)) { std::string terrainfile("terrain.amrwind"); @@ -174,7 +174,7 @@ int TerrainDrag::returnBlankValue(int i, int j, int k) int lev = 0; amrex::MFIter mfi(m_terrainBlank(lev)); const auto& levelBlanking = m_terrainBlank(lev).const_array(mfi); - return levelBlanking(i, j, k); + return int(levelBlanking(i, j, k)); } } // namespace amr_wind::terraindrag diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index cebc575090..d3f1f2cfde 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -243,6 +243,8 @@ add_test_re(abl_godunov_rayleigh_damping) add_test_re(rankine) add_test_re(rankine-sym) add_test_re(terrainbox) +add_test_re(nrel_precursor) +add_test_re(nrel_terrain) if(NOT AMR_WIND_ENABLE_CUDA) add_test_re(ctv_godunov_plm) diff --git a/test/test_files/nrel_precursor/nrel_precursor.inp b/test/test_files/nrel_precursor/nrel_precursor.inp new file mode 100644 index 0000000000..7e267338da --- /dev/null +++ b/test/test_files/nrel_precursor/nrel_precursor.inp @@ -0,0 +1,93 @@ +# Generating the precursor file +# Geometry +geometry.prob_lo = -10005 -20005 0 +geometry.prob_hi = 10005 20005 4000 +geometry.is_periodic = 1 1 0 +# Grid +amr.n_cell = 160 312 128 +amr.max_level = 0 +time.stop_time = -1 +time.max_step = 5000 +time.initial_dt = 1.0 +time.fixed_dt = -1 +time.cfl = 0.9 +time.plot_interval = 1000 +time.checkpoint_interval = 1000 +# incflo +incflo.physics = ABL +incflo.density = 1.225 +incflo.gravity = 0. 0. -9.81 # Gravitational force (3D) +incflo.velocity = 10 0 0 +incflo.verbose = 0 +incflo.initial_iterations = 8 +incflo.do_initial_proj = true +incflo.constant_density = true +incflo.use_godunov = true +incflo.godunov_type = "weno_z" +incflo.diffusion_type = 2 +# transport equation parameters +transport.model = ConstTransport +transport.viscosity = 1e-5 +transport.laminar_prandtl = 0.7 +transport.turbulent_prandtl = 0.333 +# turbulence equation parameters +turbulence.model = Kosovic +Kosovic.refMOL = -1e30 +# Atmospheric boundary layer +ABL.Uperiods = 100 +ABL.Vperiods = 100 +ABL.cutoff_height = 50.0 +ABL.deltaU = 1.0 +ABL.deltaV = 1.0 +ABL.perturb_ref_height = 50.0 +ABL.perturb_velocity = true +ABL.perturb_temperature = false +ABL.kappa = .41 +ABL.normal_direction = 2 +ABL.reference_temperature = 300 +ABL.stats_output_format = netcdf +ABL.surface_roughness_z0 = 0.1 +ABL.temperature_heights = 0 1000 2000 2100 4000 +ABL.temperature_values = 300 300 300 305 310.7 +ABL.wall_shear_stress_type = local +ABL.surface_temp_flux = 0 +ABL.bndry_file = "bndry_files" +ABL.bndry_write_frequency = 100 +ABL.bndry_io_mode = 0 +ABL.bndry_planes = xlo ylo +ABL.bndry_output_start_time = 108.507 +ABL.bndry_var_names = velocity temperature +ABL.bndry_output_format = native +# Source +ICNS.source_terms = BoussinesqBuoyancy CoriolisForcing GeostrophicForcing RayleighDamping NonLinearSGSTerm +GeostrophicForcing.geostrophic_wind = 10 0 0 +RayleighDamping.force_coord_directions= 0 0 1 +BoussinesqBuoyancy.reference_temperature = 300 +BoussinesqBuoyancy.thermal_expansion_coeff = 0.00333333 +CoriolisForcing.east_vector = 1.0 0.0 0.0 +CoriolisForcing.north_vector = 0.0 1.0 0.0 +CoriolisForcing.latitude = 39.9061 +CoriolisForcing.rotational_time_period = 86164.1 +RayleighDamping.reference_velocity = 10 0 0 +RayleighDamping.length_sloped_damping = 500 +RayleighDamping.length_complete_damping = 1500 +RayleighDamping.time_scale = 20.0 +# BC +zhi.type = "slip_wall" +zhi.temperature_type = "fixed_gradient" +zhi.temperature = 0.003 +zlo.type = "wall_model" +mac_proj.num_pre_smooth = 8 +mac_proj.num_post_smooth = 8 +mac_proj.mg_rtol = 1.0e-4 +mac_proj.mg_atol = 1.0e-8 +mac_proj.maxiter = 360 +nodal_proj.num_pre_smooth = 8 +nodal_proj.num_post_smooth = 8 +nodal_proj.mg_rtol = 1.0e-4 +nodal_proj.mg_atol = 1.0e-8 +diffusion.mg_rtol = 1.0e-6 +diffusion.mg_atol = 1.0e-8 +temperature_diffusion.mg_rtol = 1.0e-6 +temperature_diffusion.mg_atol = 1.0e-8 +nodal_proj.maxiter = 360 diff --git a/test/test_files/nrel_terrain/README b/test/test_files/nrel_terrain/README new file mode 100644 index 0000000000..841d14c502 --- /dev/null +++ b/test/test_files/nrel_terrain/README @@ -0,0 +1,6 @@ +This is the sample terrain case. You need to run "python3.XX backendinterface.py NREL.yaml" in the tools/terrain folder. +The output of the python execution will be a file "terrain.amrwind". This file needs to be copied to this folder before +execution to avoid an error message. + +The python tool backendinterface.py generates both precursor and terrain case folders. Modify the NREL.yaml file to cater +to your needs and generate the cases. The terrain cases are designed to run with the Kosovic turbulence model. \ No newline at end of file diff --git a/test/test_files/nrel_terrain/nrel_terrain.inp b/test/test_files/nrel_terrain/nrel_terrain.inp new file mode 100644 index 0000000000..8d3afaeb2a --- /dev/null +++ b/test/test_files/nrel_terrain/nrel_terrain.inp @@ -0,0 +1,93 @@ +# Generating the terrain file +# Geometry +geometry.prob_lo = -10005 -20005 0 +geometry.prob_hi = 10005 20005 4000 +geometry.is_periodic = 0 0 0 +# Grid +amr.n_cell = 160 312 128 +amr.max_level = 0 +time.stop_time = -1 +time.max_step = 5000 +time.initial_dt = 1.0 +time.fixed_dt = -1 +time.cfl = 0.9 +time.plot_interval = 1000 +time.checkpoint_interval = 1000 +# incflo +incflo.physics = ABL TerrainDrag +incflo.density = 1.225 +incflo.gravity = 0. 0. -9.81 # Gravitational force (3D) +incflo.velocity = 10 0 0 +incflo.verbose = 0 +incflo.initial_iterations = 8 +incflo.do_initial_proj = true +incflo.constant_density = true +incflo.use_godunov = true +incflo.godunov_type = "weno_z" +incflo.diffusion_type = 2 +# transport equation parameters +transport.model = ConstTransport +transport.viscosity = 1e-5 +transport.laminar_prandtl = 0.7 +transport.turbulent_prandtl = 0.333 +# turbulence equation parameters +turbulence.model = Kosovic +Kosovic.refMOL = -1e30 +# Atmospheric boundary layer +ABL.kappa = .41 +ABL.normal_direction = 2 +ABL.reference_temperature = 300 +ABL.stats_output_format = netcdf +ABL.surface_roughness_z0 = 0.1 +ABL.temperature_heights = 0 1000 2000 2100 4000 +ABL.temperature_values = 300 300 300 305 310.7 +ABL.wall_shear_stress_type = local +ABL.surface_temp_flux = 0 +ABL.bndry_file = "../nrel_precursor/bndry_files" +ABL.bndry_io_mode = 1 +ABL.bndry_var_names = velocity temperature +ABL.bndry_output_format = native +# Source +ICNS.source_terms = BoussinesqBuoyancy CoriolisForcing GeostrophicForcing RayleighDamping NonLinearSGSTerm DragForcing +GeostrophicForcing.geostrophic_wind = 10 0 0 +Temperature.source_terms = DragTempForcing +RayleighDamping.force_coord_directions= 0 0 1 +BoussinesqBuoyancy.reference_temperature = 300 +BoussinesqBuoyancy.thermal_expansion_coeff = 0.00333333 +CoriolisForcing.east_vector = 1.0 0.0 0.0 +CoriolisForcing.north_vector = 0.0 1.0 0.0 +CoriolisForcing.latitude = 39.9061 +CoriolisForcing.rotational_time_period = 86164.1 +RayleighDamping.reference_velocity = 10 0 0 +RayleighDamping.length_sloped_damping = 500 +RayleighDamping.length_complete_damping = 1500 +RayleighDamping.time_scale = 20.0 +# BC +xlo.type = "mass_inflow" +xlo.density = 1.225 +xlo.temperature = 300 +xhi.type = "pressure_outflow" +ylo.type = "mass_inflow" +ylo.density = 1.225 +ylo.temperature = 300 +yhi.type = "pressure_outflow" +zhi.type = "slip_wall" +zhi.temperature_type = "fixed_gradient" +zhi.temperature = 0.003 +zlo.type = "wall_model" +mac_proj.num_pre_smooth = 8 +mac_proj.num_post_smooth = 8 +mac_proj.mg_rtol = 1.0e-4 +mac_proj.mg_atol = 1.0e-8 +mac_proj.maxiter = 360 +nodal_proj.num_pre_smooth = 8 +nodal_proj.num_post_smooth = 8 +nodal_proj.mg_rtol = 1.0e-4 +nodal_proj.mg_atol = 1.0e-8 +diffusion.mg_rtol = 1.0e-6 +diffusion.mg_atol = 1.0e-8 +temperature_diffusion.mg_rtol = 1.0e-6 +temperature_diffusion.mg_atol = 1.0e-8 +nodal_proj.maxiter = 360 +#io +io.restart_file = "../nrel_precursor/chk02000" diff --git a/test/test_files/nrel_terrain/nrelterrain.png b/test/test_files/nrel_terrain/nrelterrain.png new file mode 100644 index 0000000000000000000000000000000000000000..963283af0d9b30738562d57dd787ae4475586c99 GIT binary patch literal 301384 zcmb??WmuKb*6pUGltw@h5D}2>mJ(39yQG!wk`ho-Iz&>CZjestMnJlxyCpYq*Nflz z&b|Nd^BAyUzk9`8V~#QBSiy?&uO47L!hpeG52Rj;E5l&OY2Ysz+CA`!KpsCT_>a#? zLeojb*38M((7_ZYXXs>SW$R@1&WO^*)WPwctqlh=FEcwMo;IQkLx91g#6?xzl6M;2YpB({Zf}e8_fk_6$!j>Q zGQ)h8l(ba)HK@vig8Uv4P7rfZNh6+*B0sg@q>{Ok6lMFmp&`o|nX3?1FPVuJ#PBvK zS6l+U9G#zWu=Q{MUnf_!>ziEuu^jm{$1PRolg2sM`I7a`br+2>EsIToWA}xjb*~2A zaAO=Xv?l@o{$WSC%1VX(=Q}YpttLfJs{i>J_$?LxCH(*XF!2#V+W)>&towKRx%hv- z&A!(``+q%`i%tmlf4_~)6Fm(6@2AQ>2vPX&XP8+0|NKb$<6ey>ywvr@xDwA*)#*UP zptGj4M&6~Mr==bz7H+AiL&panSvEmitL}bBW}C%Xor}_N2Xi$~^5ew&x!t zn6G-l$LrG>Y}hZG>ceGv1qnxryM0D0b^pii_9K7msGDt!KDB&)X>O!E`+jJ2p-{CTr}U za@))X#V81o2;Uq=*#AT!`s20#et~MJPAI;OFSf&FD1qbsej^Y0Mfa;EUnDHet-P>9 zun^cpx^@WOSIZPEC#rXQ*UkPhQ6V7m*>cLhC++;jpsU5%^%7BY%Ntf0EZKQn>p;+! zEk`mtU^kV;TpvC?u~b>&wX3Y)|8E7JeSqGaXwnt_cnU6`QxU-NpJ-u6hhl}~_GbS! z++1*(WYV_z`j-`V8CZ)~f=jq=gN~{G*xm>JU^e5YX&3$Gc2|d8#&dPfnw1uWU`e_b zulId~Gw4RhOE}V+u8#V;!V*7ztDf9*Czlu4<%G37cAbryv1Qk9+HZm%R8==VctvK9 zd^+o>@MFgMYJUHkT>pAYW7%97o_Nx**95mow(lfy>wZb@N64W5rtQ-M-rXOgc706M znln?Hg^uTIJk5zG=rG~S;fRCsgvR@%+*TqLQ~kviHG8O!op4}(zFHRle4dl+hx%ee z6wQy)HNvKTms{6qSc3OrCC2{XC#vzu*4TyeklN7 zzGb56w6e7dgv;5%Q9?5rD!Ciw^e#6vOEUMBsG5z8&|kYQmDalVyPD5CSnl4^+KR}Z zf<+FW>{?n1W$ApwYRApU;y5Rs<~nPS3j6b8RG#!b7W&;buUSPfI6yNt^$)7&Tu6mLWG|=PY^EKAXfzmE2|=GC zFL>B)#SDGOc#)3%#cIN`V;Y0Bl>mBpME}yF|;`{d|jU!(Cdb@Fp z?sf}bh?r=;ISE=Oe!o{s>qptWD+~hQpvcw>Q^W|l*=*pE)qDd9&zuv!P2DDquJ^_2 zIau*9<8Z$09aDtJLWlE)^%vL%S4%|0Z#hdX#^|kPsva!d-kcqRIHkCSH{XV0GS{Rl zFTlW#*w5N`EuspaBYYj8Q7_a4b9RGG=sG@Vx)`us0_Pe{|0G}Ib7g1-T8Yo~_Tib& z?b%e7e2)L_O!e~Rc1hRCgh50fbNzh{U3(NP!GjiMNB;F>N4uV92_|Vo4<8;Jr`?j- zdLJhp0+8$2)Q)eoNs&hdI7YEozb_=N6!7A75(%skBbV(z2u=<{e^UQq0i13lSlK@O zP=ZL0;C9cox$kt&=l1%LP(v3t&0{O?aL#oh#nN>vFQ*f>RB1WUS)|V34N!&DcCL=g z()DsPrwe8TI~>z6c)?x#)(8Av_-_5$SIhD$e&+g}a$*tBKOa!Fhju$jZNoH*bxDwd zps44(xft>x#|~`c4PQPF7uX9jIQ}}(4qKAU#5M4_KB=w37CaE~Y(YQ;uOVUaQr=un zG?TwlBIvRwGkCvSdH5}m{1FQyqsei@Zq-boqgIGxWQlRkXfOmConXUMs&3bkYzGIj z=4`q|aoPdwGb{`2H*kb6^O9o)9x_$WMps^hHlK%{`%_%K@jM>j=`tklv?uHG|4DiC z6Wbdn&GV>-&G#I9Y1d%f6<+38Hg`-be9<#?`~#fB&IAK*_wg=hqt2&>yj@O{L);S< zTad8(FBib#EwgwoV%j$^L@e`$`y7TEv@3Wn;a6<`Fzt&kJGFg3GXoZ^3BE__bKpxJ8EurpxuNM{sOJoy&`@WGID=8qmOv-#Yt`;a3ArNL*{*Q!FdM=UCr(r&NT zjd#7_GYe)JEu0-WQiGyR;jhTuO=z?e*AOYaZ;sOpwggQ+wHaQ0=@O*5hvTzjOhG!c zPbGv9)O`5aHf(qQ#N!aG^dDl8t8mwb%)he%-Q`9dA;~b>nzQ-$%P#egk%FL!ubRLGFWwdHN&AbSXQ`)7EN9 zWo%pWe<+14sRy7MAj!fg4+${ZN}b?=f-6sWPkyUZ!c&iv*I_W5hQrR@VO?lDu2FnLn-#0I;C7;n1devO^GU0oSWAdmzuZN&ssCr*M%o0a}Md z*GZj)OZB3mk-VJL5O5~aOH1Av@ccW=`C>zWXQf{L&dHdwS$-vai5vdnRI}l7tfUj2 zHrY2&=!Wi}nzd z91KTz6F>-PKcVMp2p(qKHS0W~_wjlIWVv&szs4VUfni~I*}5rwaURrLKDG|`=DbO;^Xvx_REr1vo*L7Bq6}; z$r5-+rzB?sd73W<~v|6^i(2oNrWId6|IhH(tGfX|hhbze`ZS&i2@ z(C|6YI1t2!Hq-9rVx8rLK;}tr=3evd&4?B+NZNe?U+VXpX55mk4IaxnV2z5Lze#Z# zk%Cx2P#czjm2ByBjs3E+taW}6{ExQ$dan?C2Z^$_`PzHIZT3eR$G?EhMh9CN6czYl z$IxwEU?Di6>2DS+x-daYH1^X}xn)3?67i?=EsbXF{9BOxy9C$RV7`{cwViIWJWYq6 zm9Kkc;bhrA!DKCAEx519zRgi|9g0twsNA87!7?5#P7lt(>rk2wo;$ zxH+x1Bvt8H<@<+?CU}q-DYcwn-o61bj41Mr=$BDBATcmlmDQAy;2Lg(8*;etjT@}R z;P%A87)*U!NR4An_%c%%5$1V0n%2qUbJ16}yx(}Huj{dy^~@~AoNe%%4MfCXEdaOi zcW-1^8VRcBJ+@WXO9>jb)JnuMhg+`C79x%Z1%^DVniqz`xNi^7*ho1b~uNYQ=DC#FBJ#M>}2BAcN)t&E{3x`5fer6sJi_NTrC1{KY zupy7}ig=3DVHaLcS;2ICxoH61)$v5#H2Hi7oLAJDLP2ZlRp6RG5%f*Z;9`!-(1Ka z5J?4Vvb$(1hl>H&_xt(A7s_#NiHb))fLJ%})PPvNZveDSsrR)9Ab8C!&J02K_?}viCb>FyHFt>s?I%^nkNM3x)}X_Tj|weKgSRFtJ78>;u{l?!a1BZ!2p7$X5 zxzjzY#D4&-g9I6yx{wo;3jrVNd_R9oP6jlGrlw{Kh!`AX1oG>RSIes`K72wTELV^z ze%@XP-=gx&yFHZ`zINIHutSU$IO#a_!X7ZorB9?bEm5z?`Ht5WX$Q>kp{d)?yRR?) z@yC{|m=Y)J;yvnqdiV|73k_P1Wc9J6SAs)rABpsXNNpQ%OWX%6p;Z1z6z2^%&YJZu zOsRjr(=L9t^?V9eV!HonZ(K9HzPW8(=!}od=jssJ9+%zek07BAyPef9d}b)Fq3UDR z(bUYnZUEEc1+>!OXE1GQ(8rG`AkJS*IljJ2Rj(hru|1Xqf+{j`Z6haF;xI{y~GAOEhL68UWH7Jhpp3~3G^?2XMVnoav2 zLVCXwXd7Kv3zXJr1sBm}_~iZ}D*exL0q~Vcuseh&5O;z3LaKHwUv0A7RE9?Uu|xNh zb3miR0RZ_t&yo5!&}UyRs1Je6#7fX}A<@4%N?4A3iS-kbn?@ZNR+FU&Imr$fLbn$~ zM5kq-;*jifbHRIc&^Em3R0`=)bOkp==Gqm!zwqnUQxL1z^9P@J{zOH1QmYs1215x3 z$gPf7LPxkY8v)ILkJxpRnEwGAL30Q> zV-S84S`wi+VlEoY4F_V$F4ONIHT??=0F0+lul^x8evCJJ`!`q<20kx7{;M~!SF;{V zWlUKa@sgRP&FpdmZKqCx=nEAc&LQ+rD^UMj*}NPs096>4LCpshR;XQxVMuH=QLG2^ z1xy@K!@!FRWc-51w*V=g$n$SfUjcQ51asnl{MVz=N}e{w2@hl~mTzMg?`Cd6DyF^D ztf1-vi#A=VpJUFTLxe%YJqICYp^JER$65Hd3#}SnoXz4x0*A&U#dZF!d{k-uPklpp z?*xVp#=X@2G@|_$?sJO`ty`(%y1Y}p-Yj6pZYKo>4`5Js4B;5$eK~Uq6bQFX^R>&} zg2id*2Ls6nG|S`j61b=n!Rw^V3h9F5K)c+%Y|v z-I$ujB6zHY&28;^YN%_&@?*_fhiBfW6={ng%HG=C3M^d6H=GpNO5h-$1I-!kk1fPo zeXDS@qHq9cD;eORU2;5g0UtkpoV@|diF6AJ96^v)2Cxm+JRJi78oKX&Ru4t}VH?E_ z&VU(5^(~Yc0XP5PkHwExJ?nt!N6D)HFY@kABLbM0RV%(PBOD!e1Ihpb)%ymZ7E&&x zx`+L)|?G`|+YG?SCt(;;0=tcmVBp zyof(d!5<5_{CU3sC--f~mxfA~{}MRBPe-`-MW4YEC`|pR+6R@Y(@EpXT_`$?fWRC- zh3Z@oMqADpxUa@dy=QwB2g)D!KyDqbqW#ZCqOpk{<{>X!t?^Wx1yXpso!(?8+4Rab zVhilB8ow{IUGDrm`Qx2R)pd^W_2wj7)u}K56vvsqs#_4c+1AY=9_`x7? z^ketGr$Lr8-UIQt72+3zu1)wNOA&v&UkS0#oI$DQy{!(0&OG$xJpkwhzi&WQMWlL0 zB4@Ox(g46a03oeOeR72x-5+6RH}L(4?UH8i!p7j2*e_J;uM?WDotG$)A@s9f?#xQX002(1#y8}Sbha|;es`59md?59unV`fyXS=wob=f~COSt2xE!OPq2!**xh*PM(G;Get% zFucROGd-rW^&D(nA`9UVNbaOPpID48ICJCD`F&MBQ{T4ombFURMcQ#qx0(hT}$3!1M3~#q`+0vrA9UW&LgIes8t_T$9R={_=QG|BFHXCq_f}4mcx(sN z8!IXkx?+T9I;$%GpQ!0+0V-Ou0fgJXI<{LI>HHhPQ=lR_J%wvyk9r;HjTV6J=BTiz zY!*wAfxpD!qpohWde4=m^rIOtA$t%v?`A$320>N0>C^hB_Bbp0*}HWKmT9Kbc>e|- zM2XQ>>k+kz-9h^RNPMh$kW^r=19BiKF}|!(r2P>{*+;MgP{o#eFH6={vlPMrgF#%< z5soEv{>N&SM+FYyBfygIs%y3`vX~+Va|<6x&4EB4sq&c~O^t8lsk{ZuF@fZB!LB(v z5kk%ugB5p$#tOVPVY0+#qOsL%l%6rKi)H*m>Fp51P2y9knA4qf`eOl1DTU2Etf;4KA zh#aVqGOjETr=swJ5FCBpCEiX<{R2c@uahyDFI~t1Gy|W@93KprTPH{Aha91kJmcLV zzIC!fgJyD|!dog*PZ+O&20(`Wg?rtN8vr>b?7Tu4&OzpR@Y8sg1*H8#{l-UtFWVjh zsz3@ARxv4izSIHv0Er(&*!*c#wc+mc;g|z+-3Ar1s4v8S++FzI!(@2|fP1KFDv)M7`DWh3DuDtX6`aF z$ZI|93F;uk=t6#NpTJ;HL!!9p(xT`b2?hiRw*80{?V@Wl{IM^!Oy0z{Y2s@r?hdn9 zywDlc3x8GJ4&7cUG;Bz)^r~mg0ERid>w=rj^&=<6<&h9*OSB#fTEineSDx~27gn&6 zVIjaUF)=4Wl5c*3+lchHbAEkxT=qrn1I)w5$x`%D+e@aG_Gm_Tik3tJRDs>f->2g73Qz zy+5cO^1_0c1)v(xbFL04ZrScq;Ftvo9MT+KS74jlKtVbHlGx{GZ*1hJm|gF)O)A9+D9V->f>FVmQxve!XE z`S)5vanBQxo95JFwXuvo_BpCZ3Z^)(9j3}XO|pNqpfy*Sa<={vO1&nop!;PqY~SNK zfOL2{gKJ$r9ECO<8_iB8_WH!%XoOyOwR}P#Pq(0X!1|p90}{T$m+x2@El#w zsc&c(%N~UdL`VLZTrD0o`?^rEO8=S-^#8bjOAWBPvDb2ln@1zH6{Ppj6&)$&DppNs{(dYuZ$G5@9jc* zI0V^n+1=Hu7&N7-$iasPwfZlUu;Vs~Cl0qT$P@T~xjse1xz%otS`_7Q1Z7yP`R z|9smKk52Ng=gatlAg#OK5HI?-SKZK(n>(CZUm^Q2q&$C#(wFE{Vkz=>ga|6>p5@LE zv}e_kA>3z=3N16Hca}CN_o-zFoozdkg6fZS8V+scM z^YMwrHNdKr$Vpe&^)L84v-$Y63M_*;!H0DpKztm~L zgDlck3G3TP#>cxQ!^+|Ln{gS6)zG9O>`Ddo%?OEkrb>0(Oz0t}Q z(zG4%ang6W#R5r&5#KgFk6?4^>GrSGp>L!2-_5PM6MO?tXJj!F zA8xo#lAOp{#p&*|qVk*;`{~C0z?2XlX`s1UXH~iwTBYHL%3Uiz}~FRui5RqX>462uOS> zN0(6Zr{#Lf;cnHFyXte)U`4LY?{sfVEr4!R^FCccMLo)j8VZ?C{ku?$7&9Y6^frkz zA3QdTaq--_UH3cIl}8HBH}jVtvJw*!az7$J(&`CR?#SPeNQ*|va~{QcTX`!r{hj(z zp0elZG|B!U1d(Ba@Yd;C1HE*t|G8eRff9*gTp=d@eg2agw7}!nbBSX7y`C)DaR?f} zZI!B2v=DMb6a|@ZLl6ld9oxMG%5wc=RfJn1<*82l)~R$_Rk7vG-N#aUI#-+|p9)r8 zGycjyOwCYdp!g!CrEuVNuKYZe{%vhQY1IBxI##Tb=x5&=xs~6nKPv1&_|B-g*?Xp2 z{_S_|SS@1weIz9gwc;tGU@e(vYm>-1@8UJ(>vxK!CBJRABC2@@)+lme-i;&Do$?-z z#PP{KAyZnsFoZ#Wv{N(4bMS+mx+Z&%WQ}J8(^mSk%F6lj{>leEFNbBFe(UpOkDJfC zw}R^{a_Z_Q#2XezS>kkH=Lvm=TG~_cuzAX~j3$Zb z?6IJ0&Obf$jDB%)e4^QH&ficyGuj6L^&_;**Hom(S)~DwWiDlPKR!7f48*k)x}GcGsI~bMdtqY zJ8k-vq_)NS$0v~(Ob#qducHQ33HVJ(R0$u1%Ngkd;pkrHRw@KQFjS z44`v1&pXm$gUkrH&3jr7@5_j~2mSvNgR zY4m!%T+@qXqxdBxbebi88xq@0>rc?T#l&(>OB?k4<&%n69-d@2R`k8&>4|`(N7b4~ z%i;-#;4Qv-YV<|jE#|CC)VFj>e9|hsJVm+eHI|#Kw_?6q9EwU)1nk`>g#whnaILiR z1FH7tNw1%FYIuECrWoiAmo{2=gB-L`l6MGnG!twE)&R_U}_&q|-MB$?Gx26pQT%+_@ zoe#QJ9bIaj^oh3c%;H27m8lpaj1Hpwx}s^LBg3E)WaH56!Gjn-09t4ZWmlMxC1 z;`Fhuu06X>nwXX_(utf*aPzzA zG%O#b#?MGJrI{)qxU8W*F}Hme8c7Z=+pLTy_pwN z;8BBAQ$kFvH)2fDueDyzili;Nu>yx#Wg%C!b`l-Z1m%W~hv^`QBekfPnoUhQf%9w) zLv4f2I-w%6_q2$i7T>EtOUPmkFOn#%d?>^&>y)%o`$8yoniS-baRfzk@qe?RN^ej$ojL&W-X?wmnsx0k@BHNDu^j#LqIF8 zZeN0MF)#c+eZpbB$M>lK)mmYEweq5nfDEdaM^Y%c?5yxRYuk5XaK?+3I`GwE>5@9q z@3~pLzo=m3UsW%( z7X84e+2d6k#GIi=4QHv;e#%Cj;xA98jKcYb;J)O$bUMK_!Otz6>R)M}nBO2vQ$DBA zq3IrB?h0?nRa^5=u<$J$L?Rv%is>o~c2HaUvn9$A@pE%e)q|7iXHS*gPwHy|!$+@Z zZ@!2pXIM$cWvtiBuEp7qbK~ZR!MGw8Bp_KC=^hBqJE^MuYgYBsY_?zA=vWq=u?+@$ z8XDYLA+LvK+*95ZRlBDrte@F=9v8R9$aAuUZUbPZ))~*RRzlG6 zp~(+YRBPtoM(8z7?e_-9pFN`8zOZuki|G=t{?_xz=P#j@#&0NfrbQTJB^DjF$y<9{ z=FKGHDX_SDo)%5M zbeU3Xfx!S3l1Np==a@?DrhUG>M#m}kBo(h&leqc)_dD2)iwlyA!_E5wJeYbf`4hc) z2$eWr&D@kvWah?J(Y5`O2tYhq=%AmH9zF8?Pfo#x*jq;YH$qdIJh7nS&vH)el`-%K z{;;2KSX~Mk#h#$yKIsmYwV=!x_=6$VvX8WZq|fl86h&Nrq}fQshX0l5uzl4LNm4|t z2vL~XGhYM{ zHg&7Jw&2r?Z;ZXCdE{AM&R2qs%p{KX2L&M=c|N-CqjCGewHT@@_M(X*O8w|x@x-(O*wGcM4nx%UN73I` zkZp{!v8bhwcsRamB8p)x+R3hCkD?*Tv3jU7cW;NAO>2(Xhr;TaH@iirQ54KHGYnNH z(M#q@21HY1*lkT+O)fYLw!LEJ9;S3f(u?GF>*H)S%xuLy>aU## zBc!t8X0xgWe=5{=SJ;k8ROZCpESzG_L@5s7+C#)_^P1y?e=`!N<*#Dltd))u)+|F( za|XZlC0%`-x`TcxH)SMhSQ*z!lInM@4Y08TBI~nvXIi%$4Pf&^G_H*c& zVo3~@ZPsU43ini)T+VMcQEa*Pta^@JSA|VT4Vgxtnx>9+-0VT)H)#jOzn2Z$di$-A zi3aNIq^|!wZfJD@Rwll1!K2rpuTiK|jWy)C#$gYd=Grr!z~$A(k#->qy$rl$!02cv;BNqJ;Qtc#~h;~#Pl01DV9vI9v}X)~o5d$^d< zVLarK?vqHwvl=e$Y`P@;>)d0}Ukc(3&1riZh#SnCX#(;|uk$4fZO5_@~YgqQG1`~gjHUE+C(Vi0uUpR;N7cP zhWfF~TLmSZP-)^nHIB|{$SVoid+ctn&+aN0P$L0yzIHvyXw<>57^;$^2@nIF4YPqipNkIr2$|Oocxz|^5_LSW9 zE#b_;zGrS~&%gR;*~_H_UL~uu@wnFRhxSk-DiRLYV*Tu?G#NA1Q8VmEA^K(>tz46_ zA8m;~&xw*(cbTfT7!MT<_U>vY{l?_}Pz%xxbT56OMhLK?u#@{h9T{j9fd_yEvgf$9 zKP5+iK_;EMUK{Y5wjFj+M1Y1%;Q%nM9OP>>g1*~QMcOrED)5;h!Jx7cnPWfOUBxEQ z=R6QHTRR#z9>tZkL*@yn@!SPpxb=p$*zvZ98eAE90s~qX)aZfQla=}rT7KZHWvF4<{3Y#Et46r>^5W_c)8EP0dBw!rN)*MrG%>G+Z8iKplV8@6{?!|Q zNidMPA=n$nCM6sbwq0kS;iqFdo582n;qt(F#%Vp>(zfnZ@tOR5Hb!Q#QHaf6wpTG@ zr{fyC`dq3u1cy#RxDvy=;N`w+4S}MX4UHf|3*@NIcu0VyUsX=V~FI)xA~E1#Z4GX1|eyxWUoRY%MnJ!Esv8HhLgpGP#v zw3uUlvi?~sQ>sWOXet0tG>=Kvd)nQ}6D&W!QSqofRA{W9S*0qRSfNp9i?9BkOx^PD z9a{Hd({iSePNrT0rTv0ruk5}RMHw%ri7YzHewusnKPANJ8CVHVG@NW{vSii6J#-VB zOhd#&slN5cW#JJy4K;`D@|C~f;s2?4lafcSaxY<_@|bG;A7j)azXA^9_F}#I(jg%@ zWJx!MLrxi_JHO)WDOA_4y=E^`#|(VzLhR8<4mo;qxU0(I@&7_OmGvXDzmy#=yz_Fx z^C3b)i%EM?iViVM)RLMULS?tUcnh;!1$(c! z=N~Jto7CBuijQ`PpLrs6EJSI2vxryF^Qt4;jxIBqw!s&4-Y-C-+S*4F@oBDD$Qj`t zn~)>p$-`|b!gfyE)I4#G3)!Y%-M9u9M@;mCjVZrY`1mY&7HKY8Y!&66JgKjNbhf@;*VCczEDwXkM6+G zw*Gm^7_3wgNuqL+$W`f#n-Ve|ccPl_fh}iLxF?|3Ns-@=;aH6L`#Zsj7PTEz7yT}H z=Ze_)76|TGfQT*dYOtxsgn<*>4y!9|dQ zmL7VBvEw)(#zyyi$1pR}jnmCe@Q`OU=loJ`)>(`$Ii;{A?GS_fSwc&ouJD<&L_L+0 zXmN2PGnz9WPt0r0(=Q!n&)ajga8i6dKnckpCO*4%P=Vps!@}1&RTD+B=J2_qaO3R~ zEYZBzihBL~_!a*y2muvMB8ki*hBLD3xcQQnCOA_30q&S$RxY*pIhursGIO<&%8}zQ zgi`ih>Kcu)0uz$ z)_)qwCXS>{{IOC-n3Y1l?IaMuHbPSbDG``~W8{MG5OwZnX{o=+lf0 zMMjcI*79md`}q^?S-M4ge6d`e#ZPCXta*Aa@}AXhy%;rpUKiiB8NkdIZs{X2r7+rJ zdf!YK+P9M<&M=k zm|!$p@H4ISbliN|4_e>J_Hz&d8I^0!CEX3b45=Q)90~aRd2*y-w(H7!d zN)mc(*Mb1^t>3GYsrLa+U*Iyr1b&&MU@>5CLxo(BR&#ZPfB+C-0e5kkOGYyiwje9d zILKR1mo@9S`yMb)iLLobl~V@zK5Gu3Bn09-ZA55zo|9s%o&VLZA?ZEwdyyxTg`ZXZ zCN{!_NY~PvG(K{>$I)}ih$UCpbO_e6Txg3oMU+nUSH?ud7}VW_Mpn!@t!I*3P8;=yqQy>%^RI*1&kTFCQJg`ZcYwvnqTDbMF67R$FXmJ`P4_Zullnvx(AD&OL zV5FMjO1m~NA5;XhN+hymI}R^KFB*!a#4sVrde8S_DAw_*B~~+)7U}r1d-3RYP>oh7 z)0%!{9(9>JYdx7_J2Ai1rRJV$s@OWub{u_?R#&@yS!&AGGa+ehi=W;rm}HuIScjaO z(a)sgqxL0RQx+m5TUX$E(=*tg$NO%mH{iYw&y4q+^TZ-BZmo88TaKDVA6y*5RgwAyk4?ExHg- zpMErRrL)lPw-}eOk!ON|j|rZn8Lz;Ng(UI=LmKp4UpRGzIL5=P2VT+e@R&B$ zxiBMq+Y&b39vaW#_2J@F>yW8cNa3rnk*~V=vZltVAR1NXPAGdO;hJnMsO6hKgK4fj zoVRB$XJipqWg5^$wV1b|pMNGv#$t;v7BlFp>wU9IDCW$djkq^uVyZryL@-fnAIA@n z(@`p{{n$A*x94b+!QcYpX3h4720pt_%QlUlcHV9^1KR&drc^0zOTl+;mxkNx{Vs4H zk{2?az65vTAcGrkxIOTl85$Zs;pwb%-aY_L@*y{H(I$+j>EI(I7s@8|-$PFDJKs=( z&qV_CV%M4r4mOc@jwG2TVcakjvuE49aBdF7txOQ1Tm8P2_soOZEh>CFamnfY= zA}He_j*BlH7fD3yh=5W&E&F%I35kA*0ofq`cDvah`Coh9>I}5wbbUN>mq9R&;wvN0 zd`r&lbgyT8U4+Ajt0ms2mu7{g;$-&XyRh@R$v{X&auTM)0ZZ;nJGK;m0Jhm9YIHGD zYU;4qu3trko6}vKC@cwVV_{EKNK+JxX0q#Tv-hKB0|nDEgsi%|HrrW}YHMx6q}CzB zQRKxRaQ&zax@uXrdsGD=jHP-XTot9byJHEt0E-)rqEU>Z6oFmHC`aq?%D*IWIHziC8J!|CotS`A}r!?3AyiJZ<&6t_?(Ap3Za z3(bj;&PhvbX%+9h;5e>=+re=-EUBJ6QGEoNwna${DA!XY>a2mUa7;?`rY^eN7Jf*I8E$nNEI z-xyZg-he(re;BxU_J(ufcjzo8YT~&GW9VU$l%z@~7k!zfQyjXqmV!OQ^NBV$k^FnE zb=IIFhM!NI#jx3j@>8qJdv8{5Lhmo3VXU)BQsC88R-wEifn9+kLdb)|R!U!w)!)&A zar_e59T-k}sSz2=E5x~mhHsi~tzCPN= zo#A*(uf^rXY&6})B5BZH4vL}Wn(aZj15*?dOLbd&-ThE|kCR!8iQ8XC$qzM*T~F13 zb}UJpFsU761?4CyWLzqI%-4eHs$~*`<9OZ2e>2gPCK1~GP?hM#dJto2mZfMPZMJ`5 zq*N1UwGWe0#e>UrZLg&hX2__V7H^G&u>XYRTlO>7U+h>RAH18fo@Yg30953SOOv8ZAa1Rd9_wO*3to z!3+HxtG-Xs!Uc)q{Ao00O!xg5U&@)tPc?j9DSTELP`puBfRMH6HfoRCi^*-;J1M(d zP?KCCldYh|CX*%Wq7e6|DI{nGY>^A&ocGCvBhzq_2|2wnx!FAfnhTF4>D~7I`$;&0 zpLc{bKD>6F{XV5;QO`b+_UvC{$OUliL`hmzg2%L|zG7~8rfyT*FDbUn=L~K?(h;H} zw3^{76~u)-Z%Azr`m_H!tgB7kh@LsF?;Scqdd$_|%iu}s{!Y}#*6;Kuc`qfMZ~m0{@-<#A7)U6v5&5ZC_K3Az1PnFr2TJ0k5_2445{gZaO){c z?k&c51zW?a_Y$`CxX-IUvtics=U9x#?5 zka|}k4gu(E_O)z;vBygHrtsdIa@f);Od?Sie}?jWn% zkdb`ksSmc}+@UU^(?e0Xsk*opPdS@ z^Y_M2#_{0?wors)QBZmrWfLqkL}jMn$Tu2bhg~8*n2ZB>S9?4 zPYheLbZzl)Mb46QGaOU=Ud7j%@s{M1$i!gy#Gol`DJ0IG=}%{G8+h-@Wt2^q?4}Y0 z7Z#J)T5ziwWq0IrhP``(w_gF3x5=Q|x%M*98;$6Wjt^&s)N|etu^Z%k#>g^c$5z z28GsyH`P}0;Wptk2>D@Olvk6-#t@xr?rk2u7@xy;52qQH?tB(%t$lC9dFjZL;PKOh zvafrA^1jg$bXwi&9P|>TM7q*adQBWMi665VkkqRS7*{>-{JZgwpe7R=x&l4-s6FL? zFNUA)MGEt%xCy`Mb(J<+(twh?9>+aDYmrF=9GVP82Ew#y(wMZi!Pg>3@OLEo(nc>>JXMYw~x4@BPJ3_ zk_0_N?hiO$o8%bxWJe(l@uEr69F1JZ^uc?P1B&OlP3e{;R{dnA^a-=0-XW_pM9@F| zn&are)>0llic(J7UoWkXo9)16y=GijVuhZ4(5lks zzA9v@Dyqn3?kYOa+uO;YB&LC)GDUuOr=mhm(8tuZuwLgB(lDXg4zxl^euylx*Qt?c zSQg#Uecz=%<`~wemo|l3XD_*7Y3so$u9gDcp*7^~;hJ$)+x6=_k zc!N6O&qYyGDZ$@YX_@1>WC}rwVqcCfMP_@^S=FR>tX7?~W$EV3^=|9D<*em`j2*p| zs~lJthDe6r8=@(&na4{wuyb@_jG%2 zfQhVz%sh$o#lLPTePwEE*$6HTwt*vw2Wgsv#N!!|q2?X7Y*N2%8~*Yw4;*gDlcw6iHH zo2A6*4!uWU-epP>nN;6;;_|O+s+1~r%Gp(9NH5$`zwhI*(ukNgqh>8zO$8ott96eQ zeNFgWaQIHAFpP^xcBq1$cW{J54gy;CP-t@gk5+nFU_HH#bXdA33$%vqDRHM+rY>5| zqP)Fscv|vpgWZe`!vpMJ8r}#PMO{$qZ>?v?9{!#W;`)sCxcS4UbwlE=4R`WSu&N#{ zm2z{{Ow4o+?Z*m(4tVg2X<{FrDUS%gO z){^07>p5v6Kv&*sqC(KqATOvVr*U-FA{aqe7GT?aRzfJJzdYscJ!+^s(f1!?%VtGe%^DhmRgOc~V#}fGd_yKG}yECXWjg zq$(Y8!_cB)S9`SN%V8*C<>`LvRhKEAk3+5!tiUQvQk6;XsZ-Rd2TH3H{H{r)_kYzeloQdc2nfM z$>}e9m4fl|zU3!|3=}9M>|N^ zL*x$r4^?Lw71jH_{UN1Px-4Q~=omsu1f*+d98zLX5Rfhb5dmp|p_@^vBv`d~;F ziz;Ceiz;qMFU&R5R=0Ob|4Y%bw#9}viH`Nl4?eQJgjU)?)Dzvwz90G|u;pG)rM^QI zijg{~8ComcaxpV4nXbA|7%=I2BE*G~<<((ZMy+p_O@l;7UVbB!676xB_Ic1y3Bxl8 z`_B~@=L!m$fFtZaoNGCh3mF8b63=Kz+79^xl?lY=eoYDCWR)Yrm3Z#N*nih&6Bm=Y zd3~^5uFUV+vT^707ah1&?Xnl*BE$B($_I3g-NMt@J=*T@CA%LY>e0M9eOn_*J7glc zLBdq(#ubmDv`O5aygY~c51amQr**_(qVF1V>GyfyY>#@lj(iv1bmhIYO|bg82)Gb*scH%Uoi}voPz}vT!tRhyPk_-l-XfB zUdNIST|u8{hFw-vYsfzQluw)!gSNY}ylkZ;eD=};%YCPMO=U7n%Xhx;JE!O^>7jj^ zVYLCjO?$G;TiI`4HzURFzN4*#S-~r4a%3{MA;v+*(b^ z!sJH}9%YsgzQdStX)AFZMdE_f`}}JzQ$)$V`A>MQ6WqiZSSz>v9gBkBP8NJ~uE{;T zOcO_ml$&Yvnss~0uazg73hP-sKpZI2RP(X>OkufKK1ZElBP;|Chkz;eLvV6vO}RhM z0k;9Jv=85$I8lx+JLC`THN2lY>YW@c%oUo|rHPhfF~3y*#2Ym{7x&7g5gn$&=+j!Q zpEHKB%Df1AJP_pIF?<~0q4!mdMCbZo-|SJy)5M-!WEIF~e*Sa*eJ@6AHWF1yC zeq#fpH1;Fa=RLan&il@!)6Tq)bls@(aEY^N!P+~xmqRIw5xx!mu(ek7T}vdsP&CnCoVy28+hk;n^(t^rr#2`6LhIy`kb_ zhiM4jH%&xy8_0t%HoX`ba)}QvYzf?JYX+2p z5?m?saLhqlgk+}liB1%*v#Cr~s}iR^z80HaqZi9Inp2NBzp8#p$2h3}IyoO;OO*Po zW-yebmfqY1Oo@ey3(@8C@Br=ScTwGf?NGLn4@{b#%=S^IJ-bmMDo5Tyl$jp*2DUmbE(1Fk;4d#DlLhrK=7qKh0)ALLc(Z;H}c1%D3AXdW?t zA64*BvHkEPCE;XKd}>%JzTV8?h~y37-^3er9f{3Zb`LzEuVC`*bX8#vOxdaLxE5}C z9LVa(RYB;uy2&*2eeku^EOe8ppA5#jeACton2L73za0J-!&s6w3E<;ozgO#)^z)}vRhH%F`Vp~8qtAs zo!Yh5o#r_z<@Fwa@J3*9qxr#ea7EUHQ?W;`Zq0WxE*U{>eZkR(j72J=WYkXu+r*x1 z7B(Sj1@s?MD4v0l-Na-XgOly@Hk)Bw{Ii#Lr}d^XGt0-0Woq6)=0ttAlytG?)L9`U z`H`9m9SP^R!u49Mo{Dzo=8So6;5HpOmkxaCNp)@{UO(o%P7$Skf~#W)NQJ+P40bd> zhua|7+q;j_Y3G`x)&L#fmk(@-+CtP581?xA@dCGYHJx+afMkyo{fk(`HST{E$N4rb zLP#+|8cZ-tFLgA=Y@yokPLxr-yKhBQb~hY}IQ-)X7+(NgJ`p&0qq!!Ze6&n3H8`to z{UsHW6oDxJuIhi_y=)v#pvdkZ(lY7uGEHhZdLQ)5n`*9 zUN7nEE-HE;G&S3oxVhdD#P*NR^W~IexNBi8n{krc2kb-(?qb>9NUO_pN~U665z6q7 zv$lLEup~{X;^YUX;`nQ|GTrN~ODxDE?PC}X%DLeo^|RF?G9#)W;M>bDY*9!}1MAQaN36 zIYI7s?L8T!svSknjCM02X+FtR94`o5y5N?qD_B?;-ZJURTH>=6n2|Q0eu0+?T zM1kqei&0_mM+=y`ibOGvI)3&_* zW*?wAdxJ_w?3hun4t8};3nvSu?+%&Gh(03iiTbOAR09;;cCU*G-@Fz_;}nNQ1Yc^C zZsKVF^WArXZ(IbA1YU7ZqMc++gkE`a!?Jebbn%R0Z$=73UfBKsw27N8_ShL}`QDik zv*xQ-fL_Z>iPXe0jvrrk(2zwu=BN`}WW06lP1&~gK=3qo*Ih4QU@E|bsMC|0`Ao)y zKq<27-4pm#coPcF~D9p2I`xHu8T*L(9{hrnV zOH%f}7@sB-ZA_DZ_H;n!RitBwHL7z$D)l*~@~5H~j2R;8{j__Yuz4Th8HkY}=XD~NDI7hSLw^AihW(UVTm?0PSVq$cU z+h&+m0$u2shYbHb%}z9iCRebM7tZu)VSUGzXKq**>OYBPaMZLJuaSB)VgDo}Wy7y$ zVx&{Qbi4kGEk{Dd$}7}#Qg2U5FgH1_Gu+J4xUZ+H3!*$FkCPphXbdP=g194dH_~+H z`|`blKTh${b}X_micm2GOe_9sl<5IBy12P_jJl#3|60Y`8=I~yNXA89`%-^GnPOGI zqpu2ELUc3sj*x)NsqaEBdENURF}SXM-mn~uBq3?b76BVelc+=loI1XER79P5O-GgPDI%Ffn@C=ciXif!_CpC6=QiB34p z0+LF|B$al|LJCVz0Rjq^NIVC<*OjqJWLsSxFzJ-*fhF8$lSDl6c!uxyY}+}udJQ`s^9_GZJk7&oxF>CwsXZvwoEYGE z`LX9!uVIi01Et1C_k+R*Z=#d+X*3?(PIG-oC3w1tn0 zj#S=(I92MNr@v>bz@yR<9kWm*wd_@sZ580A+H&r=I%J&r@|RG`93}8deHdBb+DlvjWRwPWOV_*MGk{no<1vZe@wW zn?AF#Xx7mZuT9U<2;KwPduIu<4k@$_`~D^FZ~i0SDf;rgH(w%s z5@LGw<6*HGj9qFF_9(>|mL3#OM9!Shn4O|${x@U?KbU9a{+7M+fohosu;g$jgXy zvq;##-=aTszHptBwkWzBTq@p|4juBl_vlSs_&Q2lGvOg#O%{#qPSL{wV z^%y^^-XK`5lNP-euMt!~*@iC7wcUEp)pTu$oTt&L0$**o#KF_Tc=QjN%x@HsI6>BEeXeYDlb#D0R5sA;h*}kZrvp@qo|J`#*;c+KviC1pS69+cIgT^n zStb63u>2y&c(7j*k_bxkeLXmrc--j69$~ZeE%{KYcikvo*{SHW+f-@pn=dcN~OXAQBApC zoGpp(>&*FnwWK~$OetFmO(N@gZQ3(S-+U)(RlnyYJCt zI`~MLqE5XZI zPh9^I58_6~w@ej-0S5J~C@Zng5+v9FDP3{O;PUpP^362^LqFshbp1y8fXwK*i?N}EiMB>YpF&t4kL75tDrI#5!b2gt zZ_^t^a0vLc(98&gTPrRSTJb~wb>2J+h5KSc--Tkv6CqW4+h?_K-LkTtvgF~kY+vJe zEY~e{6{b9I$;%2*{EwqyPj7lfZhuxY3l4e63_Y-{MxUz5bgiBzb}ri_UM@e!?P2JH z48};Il^pTDqT4La9>Y;#LAy2p$Hc+w3s*I_v2u#nToh)u3WBAUeMVT!XQLi{=hHzO znn!91o_#wMc1J+IMg#J&e7t)zci`Y*2IKO`E5p1lgGiGVnMlGSUnOsIr!@y$7?0F| zXmX7G!!3pIgz5rLes2$|B(`Wv@*^feY1zJ?;4M~Ir2#kC_)GEST*M_`kKjo*F{iGE zAe>auH|qjlFRw6(G45IdB&kB?{xc6@iaHp|%ieBOD0Wz@Zx^ymSd`65X(*D_;mT&} zKq;o&mXKad#{|zFTjHe5_NXTwM+LVx;`inYaehzw*ihDGx7oLHW+dF1O^jOo_?UQ^ zbCYYgL^|q)@UMC602o;xsn|^N*(rZJpZ|Y{$kjXGj72AubMEuV6obNJYU_kXzf3-v z;*bPn17$9Teo>jcWp&k7)|IB6MNv9ZNOMg*QL$J;+j#Xb4EYI|4OX(o-N`{cxPEdw zLQURVw6KV%<8nV5w*T4gtD25@(5G5nhZkGkl8K|K!AOSqg8oCx#5rr`L9xkf(U%2e zs4kwS$R|^uIjP1AJa-ECwQ;MPhJyjZ*(qvkT#v4Ljk8n)fRp*Wv!n?H5IBH&p-8&& zLwAi>m3Y}NAIq%^f9Y4hZ~h%HG)S(~uI*)ZyEaIfA>3q=>1dd|?&)7`HZ*r^MjDss zZ{h~(2TZQblXu^icCRrPvLWARBu^MpX16uFhT_@%9?JEQxnVySsOYegr# z47>EY#dO8q^eGODdC}Q$n(tQ@{llzvc-}VNq|c*&+xXY4mQ#ygr?1tgs(nZAwg!b(SbEp!ijPXj2Z zP;6+*OvQ#QuCKQgM<(WbSz>i+7eFeJ5>b6qnM}i*NA$IsHdlDvfh$K)q;W#sR_2mA@MxyiE|ghh_EGVu*i8jZF%%7SIS{Hmng#JcQ6 z;qhrv>fGgHduc&nk=!b~L#m`p-tMEadTl(4KlIyy44{hVT)ts&Bp?6AG0O!*PRwA_ zDd;<1p?02SOH{#QV|3&{vcMcY(Xg3YEXXii5t(B!zGk1!@vI|DYPa2*9I<$=Gz=iY zdYUQOv!w?MQw#og<`Lp&sO0@R>idwiOMQ1aI^PO*Xpf7y-xeox9(@s5c~i8B{cG{C zQgziMlevnwz_EY<_VAVk%^X)-UA;8UfZ0pvnMbu=lLc+w&iOjw*B%&|+UXpm=c#1A z@>;mb=^<&7B>wS16U(Uz7n#t(D|p#tK_p3uOTHhzR=c2jR!YS?HNqRlcvix126*tT z=Kh*u_w+e6o+rFy?O9!m%R*7#jlyPa9#^M_S?lHS$Zv!STx~U~H^8k% zxZLCE%xWmB%=|s4ccyY7`y=%qiTwIr9+Xv5~ml34-I1Oz2jGPJvA0G_=&8IuYo>aj3X#1;=Osg)&I$pZLS86HSl0E z)~I5(MB1s5WN?b-xug&IWP+uEtvJ{yAd}1$OY36p+e!a6{IWF-b^1)HK;DF`@J#$v zHM+Sa@Zhd0A#7@?xRzAwRd`(r2_nlNh|q?ZDsRJaF|CtQ$JS zUtA-0^ZhyL`(Y*o!tsLOz#5%7zH)SkPa7AZcgAaG$G17nv$Si(NJmQ6X|H`9Q!2ENU_8|MZdf>&WTs%g+FWV@ zyK)_quxeZb_9pk#zX}z}KS?jR6jF)V11X`s+VVjpc$CkYa|p3-6Sz7>m=dDO3Y8gv zPNUPH3NRWtmhlLNI9bu(?Os>bO(0tFWjt&D5TYF|vYk6IE5p;GuUHrclnLs4i;M)m zcNYu!qUorZ1}y1wIY0EA1GU0;xIqEkg|V<;rHR)Xb`z*;(jcg_&!Hu22_x_P2bcA} z!qa3>xVz(jBNgjQ>SYKFTSm>guO|8#11KI(DG{76J&X`69 zha)~rA!6YdrE0f44`tPW6?#k-epsYLV&%BYrMI6`>4Y2 z6(=CML`j~JMjRGNkM?$y+4)`VesO+a)pBF1wV1>-!s0ezL}5HELIdkf6UUHkJFG^z z99kUali!Bs`b0ooRm7l#+%Ol66%J=!Qb3HU<2ErQb3*+nZPI7aQ{ZHX@~0^>+{oxB*{_yCK>U7JGj@Oan2%%3Ff1^pT#BSb<^JVWu5`JYL}&kw1yZK>3b zbnv?Z;{8|tD0>@Fr$j0$a5?ng8*Gk4kHsz*>VI;m?~d5K+>pEvo#$F05DR>rm>|c> zQ;hO$v{^oB#J15&{xs+$9(AqIq%KPepr<$W!6t>Lf6zRP2OXIr%sC7-GFgHy$KDP@^nil6PSUi%p?jYZ{je*SGj#_z2%Q_=^&wsjU_{)zNV)|ef zs@!Ga_w+-SDI#}L&ikA+jC*diN{sl{ljsN#o|e(R)(Ya$m^v=`X-(eMM_695G%nn# z)=4wxujxLPq}UkCN?3$l6L@ulm|#b&%pu!(#;72`Fu5_&Ibqjys*Y{67u7k8%yn4R zpF64PN%@Zf4gI(s+b@Hms4TjzI^c&(njsoN+`+PXSCiL>bL`T+-?RGofF?Jja&+i$ zNQ;0a{yIm0&r7#B_NThnrPYo{pYS(+C77fRn`{z3X5_Re9b4iJ}Y(f6rA-!%J4; ziPV2B@1sZ5ShBhvrDnLFFYwxCWJ|ZsR#%`_UkT7QmAoYSVxKe~;g0N2Pyp{XB`Ei! zENP7b7(MiqvA7+t)le9M%F0$(*&Gjn^TO?&hc9u4?NjRDw&R#XPcU4Eehv^M(meSq zR0KSbuZ!P*zjU6a!vW7-bn)cWWBT?r)CU@;)ir*3LwQL&5?_9TW!RJHWlBOrrx1_8 zt;FezCk1przYp)Gk`S?Y?3wFV=SLFeOYM&HRTAHSPP|+(FU{opx6Ykvt;9}S%k8h{ zU)kZj?B{cBOu%1@9RswAO4XmP(x6!!-P7<{ymh}?iQVdf_7n|fID0mCKJNYRnB5P6)q2dVMWmD|W1l|Qh^`wq z{1qZBA%qJ*INuB2L88MLZ1EEvDFw(83ek~Eb|Z-AqpB_mMDMMxt(SLeJ9b=J+`Kd2 zO(`eynEdxd3_NFyZquU;Z4!7bI^}0?cPUcuV4qsb>XG@W_O`eAofpM~cZKVwKbKfW zZOCXIy3w`cw(k?2dNMWvG8;jXpsy@53>rC?fvq|o=^g@}i+(xg#-B_n==DQ{eIIO8 zgjRTbL;VwlM{PDMS0`72Jr7E3W@^kot3eWw?q=M2W(Y7jcfWw957aW6eXg(KkL@ujES ziwAW_Gr-Fi@hZ{GnW63=IF2WKBXG019GCu%f#uqPX9il(^XChx`@R`{x6KFUldJ9* zPt`QmV;XI-?Kc~D&se@lK0CPy z+&DdQVaiaz2>RIb(}mS4x&tIaF91~KRmA|&3@yNgJy72|EM$4`|MA|y7rj+0es%lqkCtRAXU|AMk00}Fe)&E z_+QAElK{X4J`2J`fv^-6e;^X58#F>kR3h$#e^H>5!sg0b9BBy@>URQfzFT6-+I8$U zC&ZVEXYR*dbN`dus@Pm?fPIrQZQh;k$zqyV0M9~M`?0#kwMMIX(db8ty7LR(LjCJK zPP9i!7(2$XcvqbowrS{P(;wvq9r0TV0Rk||x0quk_Y7PAjJ3g@ApBmOG0=r#0J@#!7%YEl1+Ku_)hG2j5c90c70zb&io67-a6`bh0IAAa=QG6FqMVC>EwpqM8G-vH2` z3{rdZE4piXjXt5{JCmQ78Q@5Dzd6gYtMSy1k|Lbu2jSV%pK}6!{gIVQAQ`{j4n=cE z4ry2-#nFwyS(LerHxU*sM_+P94kEB9{xob(M+1Rxyq0WN&Dp)UM1g`-c!me(r~t~= z4VfaulN?jJk`k$HFhmpuNK%!o-(6V1LIlLwXf#f!-A7SxXi?$oa5*#Mx#~N{HBW-1 zEcZWGeECtADsPUI_Y`&#wlOK?qSyW1pZ*wkt}lB3|K{*&Ah;X=xzYd@TOKfV3M4Fo z(Mf!`$rpa38I)nHHy&QNT;&-6rc4L~NNQmaX!)%NLY^T(AYYy&>EAK{>%8Bxp#=#7 zVdp6pe%zo_9P$OUaqa>Jd5P_h?QY$@VDiqcPq#D#+BSZ=mh(;y${HG)W2N&xrQl<54z_ zq>pAF-nKp*QfYqP8vnj0c|nb}y~%5=iC3rfXDErbxGmbgRVrI81e=x9 zSA}x<#+PO!R7ry^uu`;8IsIM}nvA5LCiG0IF_Qc)9yshS9W{|~wS1Fv|3InuhF{%% z(Q;(u4?xC=ARrL*nM1O~t3J~o_z;lwxer_@zz_xkKz$f(Ia3v`Ba46>WMy5vj%A%7YA2*Z2*$KdbJ!HUA99uW_dSUV4eTU-46E;}Oyd{~V>1F{^#iA<$-8ebaYD=Jw`=uJ^m zp7<11luw*_aH4kk*&LV#I^ZckNr?eCTT3X(B7`4Xwcfc{_G8%aPg~2 zXuu47tsqoG+<@s_AvRFQ5Q|-Q1*^V%m@;js`w?bi^x*B{D22;PlCj+`LiW^l2OzV$ zQ+zK&5SR3GvM*y*BxY!~B~ngBI+?ET%On7rrz06_V4YD+DMVa^FSuBv+o z{FZ3<#FOHkElkC~qNh^`wp%^Pmr#^E=>qrK8nk8XK$?a7)0P8a(N`BkxYzrrB;Gpf zfag$>6n^N|I+}@D?FL(fn`=#x{-W`^$B}zc=v}U3ohG++i^?`b2}&Wwy0(-A9&L z!%~)d^L-9nA=IM>bSF<(Nj?re!z`VzD^pR10g_p_1O4>VvHbu(QRek9)?Y82m2VfW z$!sqhcN6>uU=Ix0V>YkLpu=^3Y2V)ULO1IxOpLqqdqbQ!gwcrM8ks;`UFD-MxoEshhFUXQ)Y+PAqNJni`gTUftr^RiPEJl~CUC6q=XL!6jMkt% z)#l@ZQ|-eai1UX3IA;u8vf}`(W1r+|Z~x_<69onb0i*~ZIs?qYivVxk9{|uE4r1vA z!8n}z%?sBX>e^n|12F^Ng*yUWFZ62Wv8cYs=k{zNFu?Y7OOcCiKPTWG9@~c%)Hl&6 zE^UojMc?%MXSchxD3%sfeHI@)Nc4-lC?EUJ4fEI2n8#qQW%(6MGe#Pm=Xy=P061?)Qcvz~R^#;$bPjsdiH zo|9QPEhZP2YXxzquYKrO__@I*hv#dBpz~yBN%>mG$k@5gEku4|UsdckV5kVAn{kL= zM3&z2&Frk7Z(0%o5Pi1d;a4nzx7H@IAS-gbqtD_PTjd07y&$9aD$fnrjN8Frw!^`P z_X=|Yr2yOWAV=!TqV@j)xyfgMN}4hG<;fd}m3$nUROj2+l4`2oO?}qFVJ*V+8W{nq z*I^LqJQ8~^ed(-6kLY7rP>Mu&VfGoyv>a*rfT$Kugm>&LI;8dKDc9z|CL$JAQ!&nR8|U&^4aUtwPlERW@&H?^Rjee#pC%!kooawSBs9v)OgY zb^IESxtMd2>MsmoB|3Sbxbj0;h46IF-6rq%uYqR@^vv2N25`q+s?|Bm0c=e?G?=lZ zeVKg1L3tlIKzlP0_{69Xt#-TEWN`&vu*GP2W}%)}&{Jb3;EDBJF5*Z%@S3Yqn!pOs z9NH&pX!qUfN3DpayhLpof2ssTQL1SaU9T@L#)wE9FME54FL?weh71Pm-*0=vg(tNkeFbC90@1OPEi zACG={hvBR4eTV7yRz7}}Ad=f5Y{AIpP}_wiyLkP!$5Ik^_rR20kR$%|YHsz~L)4Ix zn&h=QiDG-rcE#FxFORp}DieoM=T-sl&j|4^LWcqB(F1SFJPy?Zu!hHU?xd+g7WPfF8dbmHl2(18xo)9k&>~Rqe8D05*9ZgHqaYD( z|0mB+4MvbvpMann_w#HpB5t?!xVF-M<`uxS>Wlsi`tqO8ya3V~0iSSrUCV4`@g(nr=-3F-BM6nt?i^h4oO;CyW)h1zQN**b=$WfH*OE1qx3M`82BI zH?O0hV7y<^*-_z>{q z4YI1-&a(l4%n}$>cn2l|q+Am|PNA~zFFU^A5@oQ>@v5#+ni3x9upKco$E;?yv zQS%vf=}ZJxnw71$`$oL2LIfZ8sf4ihuNKNQO%Cq{C;7a+Wwx$V{0sXiarE(vLjj(p z9Rnqw`0gUVyPU7vIYa90c6xg7b>C0)S(NP6Fn%^VXm*+~7wb;0PA)Nf(^#AkvocZ; z``iq=ZTNL1y)-||Q*XtO0X3F1HL!gZ#S!PW_Xu#A>F9dw~2tpBqZg$Ma}n)5GW0{8*&uoTp>wgLPv zQZR53DBPb9f-8O`e7q5LI?EzmpT0dV!9Z?XpyVvW3a^m9zM4L-+7vv50JbDRx_FV4PbDi z@>Qf4D#bhuh+@0RVBy0GU|fLTM+TC2=zx#{L<~xcpT5mZ=Eh;z(#OR0KM+j4n8}@i zE!dQ{d@7098|}Jjvt**A^thXl-|5mcFA61;*{}DEkMDIEbrS@QJu}-L)a-e1bH~61 z2QL&2D8^?9+D|&;OFVLMqhrD)uZ+i|42)e&Ysy+2+01OY%4Qz&%KK1p?uyp-SCs61 zXmVD-HKaT5iBHU4m;b!814jSi12KNDm6ys%W|azF1(S3Yc2> zr?2%w;{t%&eXc5B^Zf%bE1rT8!EHctlGO!JbhiP}CKn*ta1n@ukoxhv;Qj(oMf&7# ziEx+nEQhkdW%iLtbB29$I|tbReiy0_qR5`UBs(|YNI z<%#bPT@6Z@QVT=%a)i-}nK_(G3!@wVM=}CZo7#Hosw-{>2=K^&u%MS4;$Xi648R(L z{{=Jrz;;{F>|Y?WnTxjA5lrUz0uU5}aXW>f!04%G8Sr7V^wdRYashQRkGu+Xe*u1C zWWo;N!=twcG`fJyZCy#1O)Au?LPk5TPrFSu$l=3`G$=?~Ga8zK-?j!^9Fd=2HwO{r z!kqe&i13T!>;?njM5~MGn(BA(444o+o=uq%Ke3A@!>OJ^&*k$4SiV1C5I}jM-mGFY zt1(^`PPjAPhP(HlpNuGHDI_)~6gibOx;C8DQ9y5@l-`#tfy=5|;dZyXG0tfDz2@pY zVBWGioHS}HFQ2{xeJV%l$}^#T{0irv^I=3984}qzwN}x}K^3ki-y6cGQ2XHK1D2

Xr29fhu>GPju?TD&*z?HvmJ6Lb`~WqO%Qjsp*J3zLe|;rlK6++ zztYMz+8J!Pkk&A?do+<5b|OZUquEe*dE|1;=}=9Oe`H<;XS2OhzdPs@w;je^&GGuf5eJ95&+M{h;{zi1?I)pPs$N0D@-W&+*%F+H`!9j|}q z{1sBQ$Ts*cz6~W_PWb9AIF0v5cG@))P-_at3PJCQkX&;sT|NS4i(KkPt>h}a^Sz=Y zeB8dTWFAW&_~QhWO}t=6Em6NQiO)IFk^IuQ(0qzA`bQLKt)?hO8rc*QK?*7g;-u{64z3N`eQ+8| zZzaozTQ{2_d05l~mD`{!?Kv%ma5U$H-J!UUWwuC7>Ia-;dops=8DY4WUxi`;KNShW zo^o96dT-~`@p^y8ZbrqJ;aR{gJdaqLx*w?>WbVU*J~B8d(KSrVm($Ixd=694!E)Q)y6rYLGRqnsa{ zN0>!CzM*YL0jyo;9+V{B-s{YTdY1F&vT@~^E01U(L{qGqH|?tH{QrCa{6U6|L( z&K;rAw-{3ON2k}1n#1FIG(3$t`>nQv(PzjqJTFMporj`&qzUl-?JBcR&HF%RFw!d4 zXb0H}ovtOdlLiuo*1{6`Ebc$$ymEYG6;9cD=ya*AU>9H0sW0>6Z`Jt?%QlZ{Can=j z^dC4!fX2c%{ok|v^a4|HbkSL6aLv2w!t=}+}|kCkC`r{(7rrmjoDF)I<6u0Ln#yBvqK2TIn|N@nwu!+ zrp$cU;5YHNn1&LzcI(vWQiVrJPkTATX;H(I0~$^=>Ku)u^cb84!@j0=<6?Somi>hU z3C~O62HWE)|6-4VAB{U`ANg_aKRPm3Z3ZAz1_nP|zsSb^`@@Sw9Q^I4VCuo0uo3#s z!{ld2p3fM1|*owE_s{ZZ!!W}*L3mLlQXaSwOt!%`0 zfkE7Kux>IS2z34DlG@y@>Vh+BMF--5mo!bEKp4hy%59xjPZaX?F{Pd9)IexsHNP2G zby)+h243gko~q1Z@|{7QE&-prT20wF@YCZ-^$N39_D?AqrEK#mW6Tk4NPDN&oQScK zy;Znf8bv;ay4pVRopu7LVaocldeZnwHxBPA3}OeUh(C;}cLPX+kDzJYQ@^uzY` z&F>)m>Cc1WH|l!=ajVeQL`{CQrS5PYPwC7QR^05(k{Z5@>p%Lw{+G;ah8#;cXbCN< zf?wQ$Qv;cE&#;GTCltus=-zC&G2;Z(m&>q6Ddzf|?6}{Vbg1LhU+p!DH&V)!g#+it zSfvc9rZ#06&cv_87h~YkL9Z)v)?Nst96^2SA?&Z!loNmC%_ENcq}xU1$T;M?S>z)4 zxElPm>C>lmL&8J{iK%aLE$kDjdEl^FP%3qnr)n#R4js1eX3DC^cM)}efumS#buFE{ zWh7sy)SCgU-O}c5&TnoRw7#9fqk$9RZuVIh`ro|tX8!a<(PMUXs7U}>gunF4JcD?A z&r0UlWtvZ@KaVsrl>9AQ%2dqua>K`$ z+o3>K_0S<8H)7cjCIbfa(qsyaKE;W`Kq4(Bkuq%Tuh}a9 zAe~S~Z>iH3Pb&U zD%rxdd^`E#NqnEyc|=PN#=k%*?uY(&R(He`(>%`oQoze<|5jM(LF<9v&*21P6WlaY@9@Q3bPknp4sN0HU@Z`0f$oV$=J(pr8 zGPj4;9L*9W)L-o<@tEh9A(8~@Lfb6bC$K5RLXo3Dt-o2Z6Vt>UksVRN3NQzjE!5i)_Pxi zYFqeLCjnRmw$n^wWz#l+i0bO|KmxoWk0y;8+>v+)5?z72qF5G=>D7<|iGYXO%bkVF z_hFFhmv@k)b3)gP!tB$`3FJ(BUGRg>-?nRh+*EJVzg-xNl=?ArD_Z@a<2Fz7kBH~X z(-oR>V#Q3Kw*H`Enzv+)vQ*+<3_w>D1lD#Jt2oYI6{iKEs#OfIhsG6e8sS;Rtxtq{ zoIZW)=7c8FWfSU}1a5&wsV_)H-UD&HYNtqS4))Zbr$!j%t<4se#AN(-=jFnpSbozD z&IJ{rja{KpM)a3{?yD}H3@9~?BO;Czj6JRowt;A|&}y`4Ln9E2)w#o37P{nbie6_k zU>1Cls|j3rTOGn-0E__042`#w5epK|DV$~87-al1G$TA+ke+uQz@lmNmwE~=@L41n z{yLdIJRQ1M%Kj{qQ2z^e&I?0#yM|r0inmfZYQqsMO2Op-_KAl5g_d0&L)bKRCB~6+ zu37VZe4h|ac;-sULiqDk7Qc9&ExvfYA=S$$nh&$}%k+*-O0Po+jWM43k8Ab(IzpuV z9>6ybe!oLb^u<5B;s23-Xt7_QFZz7Nkw(uGL_REw7bG-Y)CYbZ(LJN;W#kZR)JA`WJUu514HNC=(`sabrfpGOaP zb30g39tlTZi%3nh6Co8Y0mN~V7BeTpii-rbEUWBBUulp!o2gO?#kYkhMoKZ=Vp|^^ zyS~%}mrLPB9cQAB@s`$1zeg3`SSZC!!m+vRgZ!T?4=pZlpUR#Ae8s;dh9)`r%9Sak zYz_|vrrb(S>tsHcXAacQYcdhXC4pWhaN5VPw!Ocd=@t7!y&1pmy zM>{%sfUdUC1x)6Nn+XF0`#jpL++$!x;O6reoc+b;eyR;cBM$p?mNCY~wy7X22b>W+=@ZQ5wl<`K$ z0%i?CpKTym2k9Yw)+iU4KBzS2z#;3FteM-WNJFE9{{yOEkXAQJnXNfd-9!F-dZL+( zHXgW?{=32$$+Lg%_*=h{uORbQhn@){shY2<1mPs&L;@D6sY&N=Ai6{N7ut(>EBPzV zG0q2f8F`!f6yJ|UH?KJn``mXP6ktW^e{&Zl@h`FW2sCfN-vCr-MXs0SR8SWgz zuWI5M;^sGRp;|DTB%jA*H|ZHRZ%~@Uvot>&8MZ`m_HLFayq|akH1bFvO+QsN<|*n| z`}C=wuWA=A2QZ;XQ? zV`|BEd`3YcYNXb|OW#*ijSw!=BLPi~=?mG9)-*p0iI?PGLB;dKmU@FW>i$aQ){+Vb zWyJ`D?F;P(I6y6{iBOtV)8>MaLC;Wu@DfUnf6*$dOPDfky7Z3YlCU41<D`v&=U zbOb0fjlztXgtfn6ibriq)#doEEjzemJE>Sm?7b(6gV)&pgT3~*9NT?bF*Y77gkS0B zJo+JaTQudVw;uZu_S~^mdW%b>Z2IknRO01b!-nipftIWD-IO_a8T46uw$qiw^SS{)Qlb^>YvOn`NxT6oCVP`C=`Gz8G4!)`(*a`!w3%84S5T_y`bw z?*~x4ftU}r*FEN5L3eUmxe2^LW8a%qhdL_n2<()mN2Tm^L&G%Tg;IoA;hc}8YX+zr zsB_-NFsUjv@90S&y)gU@%Y?Ss{fRY0TWwN1tsp&DDuoi;Z<=f#%)trujc88#Soal{YpjWRBdDc`C!P)fRS7sUiAZS&f#(rFNM=44V@oC%O%3`u_ij zI_s#YzPE1=rIgYw-3>!1-AWA2fI~_QNQrbv3rcr)!%)J|pc2xZA|fCq-5`z68NR=F zy|etog|n9IbN0UXo!4g_S-A3?!szomp(7OmU}93Iy%d-{RAQfT`^6wmmL6TP!Rr50 zA6HmV<*h!OP`?s>x|^~4XQrSMzJEM|bONpR?pP%y#LTHDnV55CBlSy)b7EVNX^O;F z^-+on$fvU1sp43m^SR3^!mLpkx^Ib4QnQu@>=6vt0yGizZ&@QWMso<2tJvqjb(?`a zYJn&}ZiOte`?u$Qjy3WIs_||SMuiR>@#$-4Bz4D~tyX4N)QY?g#_k4x&XeFWXv}ra zPzPf4*&3m3vqc#+xPcRQTe|~!Z0kz;4a}yXx)A|(3aU6<3m&RPa_Cu`PMyvr^kMG8 zbj2qM$|(!&ZAj=-4HXId(f5ns&WTyNu%mwKtj9@46HbQdT5O#vU-SVpJKM+w1(&c5 z)VthgO&P7kP#u;$c8J6+O5se{hs6EnEQ3eAQV!FWx2KdL>aXG=WX$nidz`@E%2VR% z5UEw3Z|i; zVoVnVKhM#WJ=@I?AMA7M-S6PgA~lsONArxkBklZx$Sr;)*!%dw`|v;7tnVS7Srs5w zOQEw_TK2zlIkXFRu;QpRt&fLVEO+5M`rlvrQg`X5Bh3$AuMS|%>p?n@XE&+iZG zJvxATF74%GpPA%Rc{sGZz=a+F&O~p$AYy`9MI`SsFJrMTM()Wnv0Ng|rfUdJzgvP{ zxfVvg5$=#De0A^~!*NVu?BusMMt1>03%#}-g_=x|+qzUwk+Iar2tCK0l^)`Tgv-cx zMMLt5w?V)lHqn$YP!e+)_7Qm5)RY)rE-lB@&j&uFSRw+VHMKGljkU}BJl=fA^>@@g@~ew_Kz`x9CPC-R5_ z0#-Orz`Y>q)vkwe4+L+enPkYkZv2ryY2&Qu!=sAi*ys2{*qnD|DdW`UAc!!L*G}EH z-1`GjeIK2po&khCwh*?4UmAoliX3wtFd#z$blnfcRGBn_%`4z0)uwDD#lk>HESUHp zdg{0(1FQT&o2a1NFU@$BvM;%l&8=V8D*0wK?dj0n&a&7>A`n+kQU~-CYW-4YDjUHC zy4l5EOglu%28=Vx{@%c{HwyjQoD$J%wYeGVLeMn^Jok`|?H|eU8CQa&HMO}&2(Ol#$R@}*F?g?Mk%YV_( z!eg4Ggoe{lxsd*Slm_H1_E`EevIxngG5r3SRjU<-{^9CX2HEMTpmELNUZb|aWz`EE z+225#91+69Ib;-nmKv^Y&Q6kwJeFur4Ac4MW;U&=-wgnofcx&tpV1={k~z)0R+cH1 zznR4H29zCm4=p?2tX;#{RI^NJTBcPtHgrndx}l0%J#>j>`P2~x12KXl29Ga{Lz9s( z4tLDxm5eq3y+o@?w&W(C#D&?Kw1^msYL10%*?lsw%c;{yPbOj?NSpBc2l?=G`yEZ= zK`wXVg#_Yc`i!-@HlvDVF;l-q=r%roGlw_yABwz%e5p9JMi5|iiOQ!)vbD1<-;#bD zi0~A33yvhrBUE0e9(g80{IH-Iiyk46{3vUBLdh8q8v{{AT7z%EHvcV!MbtgPZ)CrW z)aeJB&ra=BJBfP0Gdq5oSOSRw?u5YueFxR1%tw7th+LX|-nwCVNt=Oxd+al8@R0_c z1Z7mDjfG_DWs7xqm~mO8Cn{AMvKJajsViY7 znAhP57gZKM=pFo1@V$CM)Eq?D7|0=ID$4W_Kr9`9Af{5YD3A}K{!44bm*QI-Tvd^VRcjgO>18Z~e-zcAuO_{vTW}fR7>Y)5drTZq zGJ`>E@yLeblo*xIHEVhPEsUwn$%0kYc-~P+bglH&nS+m2RXcvwSCYV3!?v?hpML(P zzi!!m0?rvV$PIIQzFIKMCx7JfThuJ6{~Rdgj)LtxUZCsNWn!yvi?Yr=ueCy_JAJ|Z z3v1zq%gf(}MGMPh%W9HXG9GIk_&VoVPy~%hUIXXcAI@~mFJ}YSa_pS5G%PSp|Mpap zoN1Q^@%K!+4CPnW1APyv^Hoa9gl%hs#bLtEIBYh&zmr0RL=HVnd`$0Pp|Dmu(ZQ6Q zbp0e(qP%Uw5Y(+Y zCfOHHNG|<#h&T40z=hGg895!${PA9^!qmTg-+b0C114}P^23*~l~DOiyrTPynzqT_ z;8KLdi;P)Th~iKyazsIqLQ3ok{p=^92KV7L|4g&B9`3#$zt01Ow_lm&c+EL=lRA z5|;)KB6W_GO(&`+XmOr@)9?pd&*TN~r+*HD zaLY%#XWo(K=S7yqCv$Oaf~(zNPt|xO)61y!_&sV~x>t%T;-q^MWd}N=sqlb73^rY# zaH&Mymc)Xt{J_a}TUXk#+CAh8*F6QpY3{>L2}_Tl?WyiQGIKw{|EU?aaRcEvq%h-K zd9jII-X_&>-xmRhK2pJsn2s|YqRyG9G9pXN&xkJ4%3RBpFnFZzFxW(7k<2l7G6^Xs z3f((_K_Axo;?)*za@D_Fa< zOt*KaY`EDSPqPHsT>ueY_}jWs5(6Lf%_xrIfO!$m`2ZN>c>v87muojW3{K`Mu2y2w zW6Q8~GcnPRsz~f1&n{nCfg6+%G~^Z#o1=0H|IN&wU@t3MNp1xToO#(ZkUo$dM~_SC zzns)$Fw>xD3u;kyJrc^y&;>u87?PA;!lOg2xLncB{ZRsW5Qmf=QEdSpVCY9DSg zb6_xc=P)M}8KiMKtNpylXtyPG!GMCN@IF8oK;>g;fsVoxzY7GFchTJbY10)a7m z#V65<^d^6vPw1>#rWP>BHeyAYQd(Ec^IGc%+P}5QoGM!6NlYOohkqd*ancXXfu*JL zxM8D7JXXM5zQB!?6|2qL{DJIJpkl1!JL;V=4w#g-B3JWD5UhIBlGH_bUzFf^pxrGK z95)vX*cGY}#GBDVl`j45)${9tfX(-yT5LXbwl6`akuNKyXLn$ZTiLoD%Ab-2%N>%nlgP9>JiP#$)gxovmWd37I0 z^(6&wjp|hj?@ujJRXb|_G36=0T6KgE#E}Do{vY)Uy{(z=e@_SjDx^8=dYiP&0+#@w zE-PtTU>XhTgW*i?A$;+|WAQmWt^{y=U_2!&J+qcU2T30=0fgT-5&x5kDDMj3GajGM>(Nq^o?F*TM7rYEg_8m%XYxI~>?Fo%U0}YhWr^-WCeyF6wwGli3 zTP|hm&LoN0$d`V|$7G?M3l$uBXUM(UviOnfykhrY4tBes3{(WuNiejZ*#zi? zr~05<{RAwWPh?m1JSy<^R^s-C>(cS^9zq+Z_j;tN^YU4d+bc@ak`Qy za1)c@z%fRXx9km+1c7B-5u(r3V4Qw0{i=mv^#1cGIprqQmea)Pi`Da-ER&Rm_y>}U z4DwIBzVEQQCw2qY8S+*fNIGG;3?^?1jJjF`n$VlLP}o zi_L=$fkkO*nKvvWFUj=(}}s|OoBE(SN?&nQ_rZx2PABF7QK5AF`7T@o)Epu zPL{nb|CD0(i2bYtd^w&jfD_=30|Nlu_epL+)F#(z6jl)Bi1jtg6!vk`T(5T=?VLfNV2#maNlXWglDHvxN z14aJEQlwlxCsAd{CVVG3u==;TRE(| zHXe)5^1N4x4svX6^yJm7Fd`)kwkCr2W~Joi`HNP?85BE0*A9^Vl7?Jpb_v5zjM$7} zx&bEFHFLr-Eqa^12A`IT<}~1nH3jxggZ^OJ)#E4nBX0{)df!%p;s1dVv;QBg;14Iw z@CB+4bQlbB=F@r&h(DpraSwzZ`lA-S2(}N?&e{otWH4)8R)r zyaVN7U}hfEe$>$?iF-<&DpV4v_*qr$=mF?Mrw6_tJrLQmV~>M~(FRY($9Ay>uSmLP=30>Pma z+VqJ*b7AF$?yMh~CB+#dJ#%$* z)o}IT=V=>9ouJ;HYn3Of;FK!k`pq^myx{xx(S99NLYo!n81bc#6AI8F$l<`R8!jd6 z|Lk2LfN5COjiJhwJH)71`f|YcC+i*wojPajQm00Htf{Ne2aq@dAZo>Cu5xdPv|f^( zDXQegvfy!X6YQe5o4^$T_{MDVYFT+LS z%Te6E*;X7beH_a^*W^&kL7ZXi7iHW#0SBi`8^Ae-4!Y|Ya&2G%?5Q@h`fS@e`ZnU# zJkX!oR;W4yp5jeY*f1sPpj#To58^50%{{@^9o(}*EJ#F=nQ^{Fw{{oHFN=F zxFD17r3ruDW<)e1(Bjp-&{G;&ieiS@JJdHhXjodW7}dEJ)h9htFqV3JN{kI^>$H>3 zgdcUIV*t~bp*ItPJ)bWb8e&~jQa7v2Kllj9a`YNSoaOz@}z%V|J)+}8LBl; zRU7X<;Y)3rbSVq;AuE8SobZ4adF9XBRrKM;U23?>A*J6-d|Pq>=|79z45j{u?j;E& z;I2fxDRQxG(U!(!LfrBsmGthwV&f6V+M$5yor;`m3sXF(8yB&?vFeC%`r3_y^&#|2 ztJ~(j(!$vLir4z5zDZ;$gHH?|LNUu=6d&)+Z3z~zkdrhd2uL#kR3z|&Zs{n@vSE_) zT>ejyH-9-YIrWiwNzNfZMC^W1SG`P4UO5Z;+q>pxPtv+5MOosg_&^Uumta1<;iU}w z8WP5OMFdRY`kOj)+feca)5%1D2{?2=q>cWw{Rwv#ErG98QdI2@^#;xPrzRh6*k(QlZP(SY8)!pLlACNJ+r<(o}RG!&J@RmcL+ zSz-0+N;0;R7ik@^A4ePS$7C^)B~g~E)F^Wy%Gu`9H5zO`tguWaY8$kYp9AY`ljoG< zdbEN&k&ec3bp~!5(j&X<(7Z+*7B&dobAM7Y>jbD6yKW{j-H2^aI-q4$jnWAtF;WAX z3)HdAAXNEk+7_sB21xX?=fX|_zr$9GbI{VksI!u9O@-*J*@#$~GqWGP%2zGWnpyGu3SY*ZfXrqM#;!3z2!e9P zh(G%`hb4Drr1hd5XLf~5Qk3KRXK<$}ZRb3TDFiw)HT2+$&jP_i9SzS+!alUgE-(3& zm^T!WWMG*nlZnaFQdxnW=#;S|7XFv7LMo-_3>J^2Yd=?}Aj3Cb(o@uKIcQy4YkW^C zvI3)gkdoIkp9HnL&tLSeCM-9{RHLK@U`b5I}N9Cg6Yx32-W;MtB{Dw}NOV-Y7g_>s=fH3fT%xB+Tg;4786c)Q-UK~OnP3@nBuA$- zST3n<`EH)YH%=wVFIvYZIj6c)K5DX8$3a6RU?Yx`%ij|Hc|?(_wzk^Q;*F@_h~kX> zmmha(T-5-@{aSnalN!C9H6_Zg!bUs*K8q)EW!;vQPSqpzwEX(s>gv1ILvD5_*P^L zC+M`fDKe-tU~$46e;$5ran@F=^#V+D?k6MkBsPzLXC_bd@$-ser7Hat-ee(0igk~U zvgyalie)v)R!`AX9!!5%cn+w6sKByi28#yuYe}p(Zy$EzDG2*~F?e100 z#_66(l-lDXd*2xRI-Q}@|y`aS8B(IxXDdJ$=d>V zG%858U27*DLQgU_EyVK(IV2U$v`i;J&ec5Ar%Z@s05~W_4TfRwq=df_hA{!p(O7~} zi!rX7-CUZ_H#Y>~6+l~KPkVERE8OHXb~dwlCg9LCu~dlB&Fi)NishNgiN~XmAFXRX`6|IQ7*iA6mgL6zr z4I|S3Q*zIDYlKvPJPl3;T@qfVK<#GKP0MnO=3B~rEDOb8}*o(;@7++ z7c=RhTAnos5}R$xZyuw3vz9tbIVxb==|(o)H{PrgiHCoHiI>cI_wZOW!#v!ZLA4GEtE6Ri@2}S!OQGv(Bae|aaERkd2^q7jF2*gVY zIK=u$cKW5bUOn4WpB5MC8B(#wp9Pm~f#xGhe3#(F0Ru!o_X~rBfEZPv=>gTjz^PgrV!)kY&xv{>!+PT}c z)jaNqY{$p&&;zd3l!1(dz6Wd+UH5L0$9?GB#Zt40E}H!>@tL*p4b>h6Ors!cXkT zj~HQvWU!Q^!>EKlk_Rhx;V&3sBAH|jMKrCO#nV&mg88sTM~#sEUi8a;2!Udj^=$HhF%HykK&%-5ADXbQ@UeD*Sw&_~z8Tk=R3 zTZai_fRzw@dHv(BO&`@C`XS2_mMzc5xt*5 zda03)%;_C;7I}UPBTqW8S)w;+7xErvGViKaH!w7qZmbN*9Atrev~JXfA*I#C*^X3o zu-KqpIs5@VOirSX7!vbUabik~7n}N(zvioFB)Q?t8uM~bU^Ec@4 z^H<|?&EhaQ0`rG=9couofFc#gkp3JVy4RN2CVD;-QDp={9KVwgj~^X6w$_u=^fKb{ zbo9<$Q@ul8F0Lu<*mV7YXx92$@j1H{=dhZVqIwFzJe zU-d$i%9h*%UpGHTy1|(({rMvZl12$sP09ETaHs6hs;YpwNdbrww@k!%N56paDI;d3 zIs1bfTG_aiAD4cw#;M#%J%}d|4Yu`5YO%DH3L)+T@0@Iq{C12HMgxLC#Vxa?1BN*V z2Mbm*MF;y-^5uzC5f=OGrGcx;BXrqhDCch+e}J_I{|Y%SadcWlGYf5b@wqm_u?K?d zetx=H5D3pzVl}AlXRU(P5tzh6$2xnW{PeYio|-tryftnsxhpa;Q<3n61MEyn={Dlo=W+?5cpMO6iOl;uuj?8tOj*(f9Y!v(r!ph{2@1|e zhdR$CIk+&0`yX`3TIkR{L}T!F9N@kMSbyj`Cmv!`BceGO>Lqx0<<`_`A@Ru0qCIL& zVqmA40lj9-?`wWRH-waOXNVndvR7l5rf2JoQ$LX5d+ij#h*D3&xQ-#9p`HeUO^+PJcM zhf&CbXa;m9!XD5nj*zdI#*x5{yL5F2UTO=xp65?xEO%rYIU)in!(O|TkiHt_;{0hn z_yn;sYe`*ammX97Nj%L1^!a5$C?_z+%c>*&oLsbLqm`povlT*fCQg>zG0^N|0)=yi zu+y|wHmVFRMd){0;ygh)zWtLxs)Pp*387R8L65slG5`h)O0BtWu;pHaX(AcOngai9 zx~>(^sqICpyo*m>J16OUJ(E44DKlbBjII-~u-TkH{qb3KlfQ5(!(K%L=jD@z=Z=cG z-!zc?e)J!%*A&^I9Rq(pUF4K)2Foopq?`{0#~yA>Mmx%5n-+ZG34vGK7O$8?=@Bpv zg$$41GI(>E@IQH`1iByMB4u>+=~x{Td$1?;4UjNsoIq8-b;i7oHcQ#hxS@4pHP=#= z8XWUCkN~<;fovzGlf&rXo<13wga!nl6eKSII(wiM>uN$+*(b z-=2FRg_Ur@(w%S4PE^pnkxcV~iBNzzQc*OKMcR82RNL=G?U7)xLGH!9uQJO0h7DcU zm86DgB+#%{kjnB0T35Z}H1!!TCLg0emWn?4m7gPsPiV{RpZiyCi%J2qe`^p-XR~Qb z_uD^;Ld5}>U-~^Tei_V?P;n$?1weyJ`D75Sf(vRLUzxJi+N+zxG?1S2X=9nweCVL{ zyTKewyAQbK zz1NUrv#*ALs-iwONx?XvQ8-LevE-cqn)!uU`9qjE11Qq;t^!CHw-@Mf{f5M>E(OL; zGuf}N6oe%S9Qk1_)ypE|hk?NCsnN7%jICp*{5X*L9*<;lc;f`Q!qq*pg&Tflw~@q| zaz4@>7Rgqy(3d98gUsQI%MG4MV^0U_J}P&AzTOKVT23w2VtcPj!7_9w1MOzZmWlph z%2vbYW4-fu(vgabZ|)6r11_OCn>_0l9Odiej)z^g3BI1@;n1ZaJG)Wu8z>Ge0ZUAM zw$XMguW&LEb29lbU*1lkWtNgq9bzzh&ayP`O}c@)5#`xXxeQx}bviD8QpOb3u@wPD zhCA0KyUy5x-Q-Xr?d@7pWw^_+^eep;wy6H~V@Yk|)aqAFB}DmqSm76I*K-t=6n)`v z-5T0#ec&Mgst3qh017HmH_RQ?&C}wm8D_@x&hE#+!NYoBs88dW3r;Y^BCdix5hwM! z0{0;wTvu!YUB{Mf7p+(oM&jb_U_j1{XJ<$SQR*Yb5!|+!IZ+|^aOleA0c*I>syjyJ zkcri4^cE*U`-BylX5T?Q5$S4MEH%ykCdY!}`7p-=jK%py!7t#{ie~ ze(go~!5P0>5Eyzw(HbT#yQQ6<-01yQ#VQ8ABTKLV2m!(Q# zI-Nc6^=Fr*I3{c)ulP${9}UaLhwG!ml*^f4PvO|}{aG0{tGJ*jx#Lz)daX@on6J06b}7wvj#v0G(c8AI;7ED)I-YxJW14uH8Crfq$t2_W&c ztI65)o77a7j4jLP}G$C6^KtQ`8e!-gk6-j86Ol}(C?+SQS5v4gBbs*eBAVx2`G(U-cX@V|`sK_~ zU_4<;bq9q7T*HlIwqK-1BwTM>8d|Td#G(7jdcK-w$z4Qf{vQ;c~V7$)! zm?Z;RZtaCQ7{bkDZgf8y7>3(8kiz0QAu0dN?(Zr`~pOnoJdE)c*Rld!BL9ePvu3IaU)H>8Y@ z4Q${Z+?f&+e{Ud_=)`FDNt|Tn^W_pJ6lzvh1GD^ZI{P@%s#fxg3Lf;hTRj1k2d6Fd z_~}KocrtQ%Prjj+{I{Iv#WF%Qw=>4(iogS?Z@SQ5lZGQ$*XUhQ}I&2(dxU~ zXZ5^tg$_X+#bfEI&ulQkG5rVk9;y8O7@I=8L0D|}hRWlYq2oXl4CFH)fvU*7pJAUL z|NcaC$z4pP^k0Mjs`pFfYk=U{AHvQ+6ymdG!^jtoYy*TR)hMm6&)=}XAo36$tjgq( zY|35<5Q7jCg?tKOGsx;zgqlb+GWje}`+Ev|)$~X04}s0($XB`{D!zhn(oJ-6iq#`z zQ0D%HE!+U~M$U!Gd@LFE_;rO1sy z&H7a`?|kxxC5iJIkD@nU`DW$covZ9B-9S{2jWwW9e-EEjCaER0iC@P7lEG7Da%BVm zl%zGDFiQhO7@0F!VwjeN1W<%($JjMY4b!}JPyaYM3TV!K#&%?3buB1*la?|BOit3W zm=(m-x9@p}cLJoY0=>d`?!Fx*qE<>AEgD1KdMSd1dQ2xqvRZQLfmvNEWi(kDSwL&$ zOcKN>YN@;Ok5u`?nlqR3BXN-apX&G<-JZ1_%uR#Vy5#R$!AdmMeOo`H)5A)y2a~Q_ z3h>g@;qTmkCq(PG?QN6Smc$?FSyw*0<-_pN6oS@pMDD%QvaVK|MGU(0OqIM|Obk<1 z3c#+RHCUr(|2YRvcRO&G_nHvWIyGqs-xIZlJp+1P02h`Em8vXu_+5A<*&_$2oj;K< zb%+FJ19UzW*9Z~k6eX{H===_G*jCaWtwY3Tgf>kj?qw~9!LL9CLU~45GNyrvvhH2PRnLLdc$5s&53Br~|ag9p>88Gzt z&tDjmSAZA2lQ~i(V+;T6Q5O#IG*+(%%DoUAGmjKbCyymyUaG1W!dnPA`tfen7JECK zX18KM$c)73RY`To(@y+u2S}cBFD2VK7>!wdQh3@=`z^Na8km74qth`W$xNZh3 zfAw#|LUxRPOX{J;eE@p^Pz94ul1-ZB#YFr5G!qoK_$p2Us0hY=E(j)+2>Se+G)5I~ zIU1P@Vo5he@ati+z(0=9TVeg-dF%WZ>w$-kF4XAs3iV?BlyJ zitI37+}7|o3@fJTj)TGtR=AV=1)y+7y+!HrH}Pfs<1Oc7QSWtePXySN;@Q0WxgW|HXN|x0Q>lu4Tsf2- z<_5k!WzBz(@H;VO97o~k4JEoIdMpHD`3hg`@MvzBk#1Ult!nyTEmp2U3o##PvsfCK*H6Q)l+4_muPoZorPSaQBva zA?=wy+sOmdg)!UsK;5KT{nS89AL&R%zWJ=3wEqgWE~q$*$^k7Ck)^~}g)xbY5|%yl zm0^Dl^qX`eHWN~EIuACKXc(V0h@wTK>NO)TRSghop}^qnaoE_SF$Mk+f4g^dBA3a%u7Di-VDVF+kOUA<2!*PfcFvEeBjm1Y-@luihHJ3*ezV3J)~1BX(ed3(;XJZX08PnE>z8LZsS&D8o0m%G$^`1M5c9{MGe zd&bgjsjff=;w_oF8u6C*8r3Y85`wB_{cDdBF>SPhp{$T(D+r2>FQ24!YpzJ1M6bjw zH+UXYlO6_%)@SNctcqt?ZF1>~+ITd6^d3T~GxALdhi)<#DUc*YtT|s_?2nm#LHeO( z&%_ogAvb>>1VqM+_LLtAAys*qVOn!o)NluQ0X2$r&N!GD^YGXriH%uxM56}Iv#HO` zO_LRVUGbpNg&eW~$q>;=DHh=Tq&gFoR^ZWES=xW@Dz8XYE@=Zj=Px<5lBctzhN;OO ziSQna3cFn{7JVM^WF9CQb${FqiSEda|u4`^5w zWS2+26H1LPo3X%xr|GDYMU1X1L6+!~kcP!#rX~11g^^4t zT}JQE38wN_sNXA&)S0uhVy}Ye{a@}>+UC+VykIiVvp_B;NZqVkv3~1tiSl;4>fgj? zCAiQ!I_od^PQ+^t&r-?I9lPZ~&(bsu^2-l}RZ=Ed9M$`hL>QaWo#s^^nAF{@5!*sT zJoapAUwtRO50g((`6}`$vz{Q|x$FV<-g~AF(-MXKm(FuP5O+fIB6arXPrB2piW$Pp zTmbZ=hml$ydoo-rfshrP6&UY@sUmDwI{)tC-`ulE zOmGC>U^Nez>6jHAW8w7I{=5CHR%kM;T?V;W*>r5>m*qOP_tmqXeWhEhluL-aLIVih zOLI58&6N>U>*6!t#c`Q6cRrUPrTO+UIYYCNilms&3{oCl>cJvP7@T~$eXn0OlWH?c zd@$B?PfIwbT?-ug`t$?l_R#rOd7MZHU)L_j?=tQ@{SkVmx9E03Y4Qr9$A3el-(}It zYdRX^rZXCCP)2=u?3dCd&0~4KOZ^VtyF2{n*RLjxbMPcB6RX4VXMTShr7hkm$FKS9 zU*B2JUHAR)iXB`cBlzzV%N_mhK&I*4FYb;3)>-LUo5%U2T?MiXtX%~Hx!O77-Rgpl zyPk?GNxCOoupdvyUv8I}hdKUTv140&JdVqu!8cOW9g_sC=?ACUuJT-*mIxymRuICc ziT1-Y5+&eISYV@1M8A+}PqjPR@n4Ch(eNe#CsSXU7jaGfWz|bPy0ttiTHidDA+y4 z^^5~;cDCu@4tX%kw=%G}LEUt)*c3bAK3wfs(LraKyj$k}WcC~Cv$`0F8<=qX^2_)1 zi_`d6U(BaVzC!x}|E`&1EFGMjR&g}F&=-$Wn(|z%)KoZ+PGtU_T%I;Y!DiaLH;$=d$3J@4kL0r&}8{t*OJe_5$wy zha@y+$|i?OgbclH;F1kuTp&hpWy-n`!Tx4emsV7&?USk<`nKYZp=)v?_rC#skQ*oQ zRT8e>-@N?L?Uy3jsl*nrCm&Wim1O5c8>>}AeV5kt^rE5iLD?^o;2(atg@(@0x^slJ zRxBY;Fni(pRp5QX7U}v}Zn;#cJ7izUt-{!VT+S??8+_;yd=zc}22p)Nb$vc~{}8{e zZZ0vN- z_{)zUKRVtmU7Ox?5Zr+7c}On;PG9hE*wW*99S^MbcaAzUjf>9Oq%K5YvnR6{N+qzw zIsf8dS|jDKcL_bt9Yj1nsFpEcdcnyjwlSd4V?v;#cfgE}^SRuFkaC9>Wch`A$6s{0 zXP~sKI>VDKLO@r{qcA-uK+Hss=j@1nDC}jCl3plr+;UfeQ&=E+@0?q2ir9g|l6=y* zdlt0MbI&vTytN-8y%OFyx8c=7J~@=&p(vlvVK^q;uD`?ZAa$#qXHK~O6L;I2Iq#O< zCrmk4qoFx7Up*@HV=&1Bo@UCrN6)2lKMfHa^PlzYd%68Nd-T7p`nrHe?eiKde^3&! zli!Zf(WkqacJTFn>ki*9uhr;_GawUo4@x@s9Xkhs{MQZqu?~DUB#zXVP65vHN9mC3 z#q+Nq;qbFv8yOmzQw5ojw*6K-?di%3>B|Alm396AF;P*`!yp1*P^{msB^oFI*ufwB zr1qUJj_Ch6O9EuC9)JusKIHZH1^uGOhI8ezq1TZl)s;rKF0h+b3g(Au2E4e^Z)1!O z#@W)J?b^9LQIte`6tDPQ9K=@n8G89xphW{@nE!{<-Uum(#$$MJ!M*E+=17z6_-zNd zP84iRqLpua@n~0RSI$AqGWp3zsNY`RW}UPNUmHQwp1Y%K!}5IFUyOy6>i2>3@N1q_ z6U+`ui@eAu+Y(EH--oLGsv*UK@MB*P|f(YLI_;yJDZ#6&>mID0C zMQB6rlJiIQT*(;H59Ht*v#x9Mqihx><8%u7IYJFdAw-sV#W!cfe#n+{ioQ zr`Pj%H|z$Vs_JJL8JLdBy_!!*=`y zd$6h7ey9}jC9bmTt+_d_?EH4Z$yGLXW^-dT>&E=df!?GQ|IwhEI~z$LIZlsj#->tO zFsROOPIy(3lqUCYx&x;u+ul(5AZ9W}c}f7WoZ?@(uOnpQ`#QozIO{r!>Gn2`X7Xq= zp^U8I6@K(rm0-Wf?b`AL_#ZI2K|~00MpIEXS}K6zyB}TF%NmsraEz_Xn`h4MaUkbe zKX)-wcT2sOCVn4#>zkZULl+4ao?2q(!~gl8Hi%)PHE>BTuPviK&g+N2AIeY?c=szD z4ruxlx8LowFaGodNcPLK{(G};XP`i5Oy(PO&<$`BML@p+aRpfisPTh9fFV5r3Pc?# z>-o{q$9K#0cW9u)vKLZz`D0IgzdijuoGx^6vmp~3Nx@&e(Y?=lxR%%#kAWaIrp$aH zACgFHVICAw!)80#mPtXRc?y0A!RJ)8B4+=H?IG|CTF+ce{K><{pk)=4G#*kP%e6Ci zsiRFOT+Xf|jVP)m%D~gk<^JMeWST1#OQK!fDC|ETr&WKkt5e)UURQm*=hxnVXL3Hw z73mto2)0Y!ez)V${)Xq>2tS1v+2`8!Q0~HheMxu3n_k16*1zX)yXclTevR#nrwv;^ zbRTo37`Yi>8JBnYmaXGTvMs%aA1di|OnB84c@;c-PS{%yxN$+s37AXgeoG$#;AUsZo7argg%Yb$EDg}d4$Mr2KOUBDUGB3CZg_5*^qA7^{^VLP$_bStSeqeZ6ofab#W!! zW2Pz_SC1S@^{|a;`hX`^q<`3=Efc?uP+OR$;F4x@$TB+GT+o-T3UjxrRQ{;vK}FV2 zc?!oqGY1H}$;g#Q=KbHjSYxD8o=I|ia4=SoTUVG*g)X}x>h%X8H1zoUVHQirfvnGFD8LP{P%o0#93#5FnE8ei%)31X65XF-$s z9ua`#8OqOfUwW00s)B?#DUx)i1cbe{vYInyijoF=xzr%v2DFY^WEpq$*bW^nNh$c6dv~dwq7pV;IHH?X z?eLY=8=?|+T=K?n-Ct7bZdD&hQ>$5@B4$%)UDIogS9#xM_r*ymY)q8y(!9^Vemm^f zy8Y#sh^PGQQXbSfX(s%?YpRb7Wp$o&XBl5imr94y116+bWY+k-#C|iz6r$Sn?*5AJ zF}qRn-BL5_0+^veW|zrkohSi~x&Y~1i9W#3!T>n{6mv%fzt$^nuXSC#lglRu0Jrw= z-)+D@djG?R0fYp;zcGj~(SjK|D$H)TwJm+uxy?EQE(rdi5d>U(b6)Aj$&&V?*7WKk zIaF&uRV#bWasj}+b9;H4eg*G*YNxZ!SlO=l)T^6wOnUPd0A81^2Ames_nhRMOQMjP zD9;UGn9BTen^M161$;W~TN%LH_zf7%F4WH*92|bP?o@w6eV^Gt(xDkC??AKg<8Inh z?h#aM*T(qB3eMbPQCmXGo(HKWVUAUvQ=HQ%@^5Y9cW?WI221R33zsBMevliCTJ zu~o;{8ltUX(64(g%PzEIN??z?%kF*_*G>895S6LbSSjY5>U103IRz}%hxa*bt7?>z<1a4GrS`M$_)fhLH!GSXeMYIoHhqiuK5-{mkfMVd>U{MP+68-@a!%4a&{NkMse8kt~@2 zx&yz1cSnE=NHG?0cX9+^M~AQ-=AqGMSH)&ssGX8j%%-N1Egt#_c<)}bZHu9vUv^Bq zW-3f))C#^_&3x*$H$9;S$r55d^FC(z3b3wMs+|0|7ymXkEjP};`G(?iLixvjzT(dM zAa95GLM(4Xj0HJUh+s6@(`ClSRSbG9#ZhDmZczuln&0QSHi6j)JMS#$VHbWV@H7=U zFwVZly~RvwUqxv6jix_H`1P}7DJm!jd*7;=06CLcKePyu$b<} z(O2+e^pbfkJ|&n9_Ss!=8!oucOUbWx&D(J&?0GRO2+6ql9IEmHJFI~SDEy?!irX40)lM}Y)oFVwMajLHN=KY0VtD#qx7c&G&{IeRz)?4pbQ7t+DNE8pGQTW-Ib{TBf!5Pb}|_;`WZA`;gD z00g;brEd)Iiyd98vCD+xQSkll3dQpR&N2?j3y?(#MhOp$-qGJ3emp9m_<{|G ztpGwvY+nyU`Cr-CJVeE8z=1{wd5zeczHe&3-5b3Fq+;eD9k~thHvQh6tNSrG*NIX~ zk~~Qt1Dss1iAd8Blz}L$?vqxF0WRm9 z`|Q2f+UxAqTy4kqSgR%|>Yc2uG^Sj!7u?C!rhZdg1A1CO%ZbgKwoP)zuBZg$c6=$+t55p;lNS?0$|TCS!+ z>PJCqFRq%jHa_dXh7iv5@PQAXBRTF`KCu`1eD4(;q?efNazE)yevf(vPta>t?@#&f zXWH(8+>8zSCilpX5cKVOzi#la=|j5*4$2#m4%C zAtD!L|MR<}`=%r84s|%|TUy>b)O{rPUU9{uzxePTZECL)H8R@=@Ug-M{m#t4qUxP< z>)ar#18~XLQ{J!dP}^A6xfyWe&VaJ0@)^<1LkImH&i|vVv>#Yen&Q*XZH@*)1*j;b zb2r^3UtY2jN9c3pMlwrrD!Vw50!LW)AwL=V><65O`GPa{&s7fQL?xL&jKGDQ?&{eKCQ{k> zhPA5lI0bSiqTiQ$6KVdD3=7Bd?PiOg)9_er^>bAI^_`qIx=`lLy07@WM7nP2%zHi^ zD=Ktr{G};H+`2Q`1@W}e1<^E*Jr<4jspm7X^&t;ed$FLS=j#PqRu-7z*N)tIY5kO^ zPD`L)y+IreQhy%;iu(Z;18jf3#NSf(2=pDce2oLRpr=oePXSoGZu|C!EukXO+k?Tk zjvqO^`9Dn?GSLx*V*SpazQ1~U&jI=dtSDb?_uX~aEq}nSs$i}LQ)wSCGJ0X5>*Gi1 zUl?efc>yveY>2?X98VS0le zp!Ab_b9a{S+_VW)gZzP4qks#;nlA?mmGLziJ!!w=SeN!6R#4$|Vcpm)`_F|Ej(K~w{oF=uS zQMu0)2hYP|jIr7eY6pqt~}8Rd9~N~2HKd|2r3e-Bza zJ3rzFY}`&z3{lx+{GXxtzhy-~79_{ZX4t!=aJ$sqS{Ujwx!{ zP7xKlPQssbqTSrw0HsY{P`UJ>ozD;9{7C1UX6N3;u8YT=C$Y|bDC#35f9fOt-F@Fe zkR~wF{x=YNu>j|{!23%{q*}SI)H;qP2-JD`@!09G1IWm(yECP0caQw0LQtea&(b}R zfb*~Z043b~(mjwAMC@+NZd;n0fBqhPy0(-*IeHZMg%W)DI$5Ju6eOZOQ~DOp3k!>i z@w1bhgZ?Os31XIyl*J%jI*7;^$r!JNtyY0cyN65L(%f+%JZcrA zQ{wFZ)v&Y9fydvn8+`S_p71(VJ|B0_&3f!?vb*DATD0S-WrP})``DgXfk(b zXFRD}>>`EQ>q$$svY9DYv;0FZvq6{dQf&h?)cbB)#$a`#e}X ziSzyjU}zzfvtH*}?r|T7%n8n4^0e;$x^9yq@PxwTFpTiG#r=NZ`htmb|Lt*L;EL-Y z-S5ErLZ~qJi(gKIHJ9<#&qW&+}^%qQ{NXgC1x5t-1XVSZV zx#jHDhdiRScp!6k5}!T!WW`0nwu9z%E85>OI8yVC)%QD~OkI?}Qr-(hc_wB#)Vf|g z?47dF_B;;++^n!RWOqOB_3|8x?VHe4Drl!a@FDDXfA09xN_ zbOo1bsaI-Bk@&JyM}->~;_d%H_)??i8OKC*dHJ2uCpL{{<4um+5d~8T0*zCL4{r13 z;`qhv1Q#DqO#Qa*88UO-H&@c}TJ5iCQ_!o0n)U^U0CN8t;Phwv)gfjv5 zJ?T_7hVLu zmAdp#3 z66b|+8vC!DW?flv1DK**5UGIm<1=2ZX|~P9pdl9K>>dAv2gB8?d87tcyX*(1ANG7f zjDx&=W_Zf}*;TP0zhJg=chpG4*Bdr{{b(oWm*Dp6Ib9VvFKAv*F2Knw@HmYrhd`yL z?b_X~_4u;oa$0yW|066vQjqm0<>^5I^!ncn1AGpAMy<}#QSFsfrkVuuBmltV;ctrW z0s^kyzU?fYx)-qI&JI7|n0q!L=%Cw7LzqY`WL2sUarLJoQqA!}409IHF>CY@P9^Ao z5-`zTs#t!(tAE+dhbK7oj-Ty9mheVMsD@V@%K)0?C4pTy`|xUgLAumZ>NDoA+d z$}G75?2cFHRI8*CKas<%4pie%qDZ;|J`Mm2^?21~~fnN+EwX|8V z!98PE3qE2esHt+(tegv>j@{T@ZBALOmzmR}Uii{{;OeCY!_urb0iTsUKHv6j_t7Tp zpzY9K>SCw(^giH3%nC(Z6&8->T>^C~asJhqRlf{Dtp|eF3uBQv{FnnBt|+6uM>>{Y9y=&#VVRAjyoRS(VE6#{&qERq6_t*p7oBQ zwu=G7tH$A!s%159_rJbBZu@}$c@MGQeo$pS;I__*G?D(_J|C(7+?u79m0JS|CdI;WYsK;QiVHYD^TenKdqe=-7L*Xg9RT!_4+sO0kbGl+@ zNe0`oTid7i3YUv=)qVknX|iWO|MwUY>nvO^}b|w;9S5#ddM5NWZK{G0p zwQ$i^8RCPOS4mVr>#tgJ{jO(RmGtUqtS@_%@kLvvj>PjQ=-`7FL#0Nmd}QdhJBF?? zYFq~&Fq4Oq;k@2dQ_PbQE+cz9TnaMU|LD7QRmRx%!WtUtc6++GQgYClpJA($65D+# zbrkBuM-Ct_cxBBX^I-BkzG@+j#jEM?LtNHdkJO_TYrcUp|DDN}>iDZh$>hEf|u z@h;89aJT!d{6EQScVAEFzD^^*5}cOZ0St?Q>&1bQX~6kBUO;KeZzRx)n7BjL^r)7O z5?3zS@heAzdu}v(@N47=J`UN4Vz${-f_mp(Zu5$wy2}%mK(Ry{N1q@ZlI;a49nHkB zIP{^|+c@5-h)`ysSH=w9Wu!0Vf(`{l`li&lY@o2_X$Q%u54!dyg~K85*s~E?*a|gK zS%{P0ohB8-&AcL zn$CEli#0Y{Kj0UlnRdC;=&Xa%%Z<$zUGHO^8TKpqgcZA(^MB}DFTwaIMW9xG_#IE&p`7DV5Gh|HULlu zWkm%FLV2as1ONqJv9_e=`8|p+2ijMoOZPWj$2Vi!wReHn<$?C^dOEI;kB&Ab0h^Yb z+pAWud(UF-%h2O({#u`+TcJ45g4P#($;AjW!Xu`*9})tc`cGW_jU8xSn1hTVq#rrG zxoT=W*#|3Ms}9PorbX1)QEn`Y4TJz~u>#i5O`cP~GdYFMmI!(m_Ls#Lg10=8hnzEm z3X-(B6Q9E{FWT7i#HPtH6ct2Mb)DKa*Ec(p3Tm=87U>__4Mp}A#uP)V!j~v<-*&W(mG9pjAvGr72OJ{93Jv@ zrSQTADSRQ#Tx`Ej@5EwdD~a!Fmh`P%Y(U|OsEZlxrtt-H(Jt^~ND`z4R_9QRZM#SD zNNn4^e3N)OWgZOIXHQWHdKFGWLt(s4f*GtYlenkM{*VZBXFqeT28UzO^R*ETKU$$F zW5G^~J8#OB^Xsn^7u(Qv<4+7Par_N#id#P&GPB1C4}}p&UvFpay15Q}>>A z{&WB=wYWdG*aV0{qVe_NQh?`rt)6*}+E>##tbH><}3s^+J} zC}J>Z!q*Q)Mxa_$HD2#yYXj?>p~9kQrAZiIW$Jkn7@)^}X(FOPNXk2(Sk+FK_!y=x zGVP$>ttYa0z{5eK4>&iv#t|-{!4}sGjvDF_rw@zE<4hkg?Us zJ2~5E?nttgiKLZ#6R+(9Tvn{igO>~kFqi6zISg@Vh)zo`ok|F#?NE{Y=p?`-;wTt^ zo4nF^K0Mff<);+N^1RbN10KHo9!+=XyU+Qqs#-iqEz(MkpWGFccq(hx`h- z524UW$kko%(?7kxf$f2w-Og3&0!EdRKU2!3F!O)+ar^`fvJby3FUzOFo<;rw2sSDd z4R9=VgtD?k(JVd_?s*}okmd8Gmp)v#T*Fc{TW;Z=1Z0JcYx z=0M`yq&xP(LII)|{{A!+e5SHc5`sFv`6`#Q@h6fuUs2Yp06Gdr@jI=D%}AG)5fRq{EJgdy@>E2YbcMOb zSGcw-ZP2#8zDv5tO=W7xwc7H$Yn0Z-OlDw^GV>@6CWUwy+^f3EPzw>p{*?vh4p})eHz1XmBBgoXs6i=Kt{pNBhR{CKpr9U=4#Xeb)>?cOYdp7eor%rd0dCb@ADb&C(v}GZdvo= zmihhp(FTD2S^*^Z^UI(NIf~CY0W8ZaTke6jiT#^J?*NLwx|CjqI{}ovywo?eN1sUY ze?vMCVEnz-^k*5VwWIBYp@tQXSRVqVAHk9pA@j(LRlc|%6ZjF`Z)^GP^rTTgXGuYdM0N|MvAP2TqTZ04rQcAe7HH>qvYbxmb8qd z(<<$^8K*$%0#1suz-;D?%4)di2?Wkj5Fj1-hM9(*NTZXP-l;(rPrGYq>vKOHph*IQ~!~@8QjFJ`;FV?&=Q}zGkQS+4jK$`Fxl=)N>Z-f7Y9= zU-8YrT%?K(lcFKXcGi_dyHsq%DqA2okgn|ceM50H;Xf;V_0b|nECr^UJi-)&vAp{2|7 z`yI;B?jL3NC}#RzrE~Br?8+Aw&fjozjju>U{UgwG1GjY0?C^|}<4Nn`F6^A0>>{3$b_$PYCHu2onkuuQ&pBy=!=P8$D6U{)X3L-vb;RYXa%4szNVF0c4m=HimazrMe z-`Q$EMBry@1j%u63+7He5O7@!Z`Lg%J_qbqVbCU0HH=cQjl0vbDw>+L(=3b5&P=~4 ziRL-?5_Wy2C|-BPYZ|ohn2o{4?H6-KuZB24poU$=Pa7MLb9TdcIr7Jp#Ujex+I@mU zRyZpLQZz04{j8G>_O-Nm{KrCKBq92=DN+*PD2{L6+>M}zBJ5AAojVKdoks7T?}XD^~(!361GvIgNZlqUj|o z{vm@ym%rdp@pXP~DXs!%L9(Io;=4Id{)<=#gP{&ucnxe?G0sfmW>rqP0d{klsL{MP zPSD0)U1V>up>Fn5vn_jW%h#E;@qRU9*P8zvg&pd;WB+ z(iqP1`pkqpAV7Nf-zGRvRfMCILsAD}MR+w)dW~YmD;%?&a#W;;QC>|WgA=c!coa## zzJ!07A7P!<=TfT?pUE)F-Gq=GfaoN;(hpfCRdR3jo~Pjvff~?Zg$d)TW8Us#-gsM? zp*pz9HIzXUvFMF8bv(G`8}LRRZ#%-B0ynR&Olvgg!s2L9W$wG*c|Tezt-J?x#WADo zk}2j(Ke<%!grDjSyjU$6`O@$9Rj`9pE8U^qKH2(tun)EHd#F+s-{T~0B?%=?HjL17 z$+OHFAPgqmzDVk+s;O* zGjc+i1e;VR7^#0b!}o)WEK*lnu3O*0PHU;-I$@UFZ&tQ)Ar0Z7R!kjyNp=xF%tE#* zS4ue_(5bo2Djp0uA)=}s8=a`b6WaRjO3|;nAfg#hDJ88i+zE&{#Kp3S;pV zFcwV1-qNJ7*Ox&~}rA*};+Oy@UzGY*lf#+iIEa*6Z7eT}sgy z`Za!0#o|Q;Oy8M1oWz~rn{Dtdv_l^1kw9EF#@?_Tju)=lPef@3ptvE69yODW5Ut#xga>QjY@o2Ei+*f!Xw&U(750>~=8ynM&*ATg z1X|H4>7=?MsY4ekDPf^Hsl!1!DstFpr77%1kf33GbT;lWTg);fP0f`}3~RLgW76?3 zgU`iho8nrgz}&nz&xzT{-#SlEAo`LwY)d^)@*ZCaHSWOBwto3bKuJ}@Dfz2D>@;}Q zcBpmie|ZiSuUC=%jqZxrs3*XaQ%~VESJV(m{oYgL@)FY(pGb2wN#jq4unq0ZZHp7W z7!J(D=IX8RG~0n+XSSj!TGm_xPDSlX858Y-`-V;%-Td}6iircBO|idUmwv@>#!eZB zudPbP=+)BU7g6Q}Q@Qm&(z+v@IcgU0x6iE$>Ni}Gbd}{^mlS6?DRX4U5pU3gILVb} z2$O3tfLB3-nbi)Pt%)u^S%bZ=lYo93Tz)8#A2q?-pwyI}(2g!h5pL?RCHBX=cwO8DXrRCDet}$+D zOb=HAF?#H*S}0S&T){F9C3|9;(`5IVLu>Q?tL^$4Ts!GmFCw&M$ED2y&H|qs7^!=e z%uQ8zEJOeHzmizs+qMEkH2rh(0F{U|oiIJkP_!_Rft2f)5e7+$D1-1#C-G@Wh7P4T z=)+w)6Cx$@sOoC=f zqtNHA^UmV9oN@%*IFPWJ8A@V5&YZDrlnR|^&%wnyA^joi@NuB|L3M8P8d@}24K^;N zo@@=b#lSO*wXuv3uoo-xi>aQE%T~X%(UY2uG#2{SI%w=O+Wh{=qLr^(dpsDj#;;(x zVMZ?LZ{omUbQJXLVwH7zktYk*ZMEc_AErLKXrAo&<|NH;+ zz!faA{vTav34Ok}<8wZAo6 zbf@BRsBci_n$3^kNQ~FOZOfbS7^rdS)5yedC=ABDVdB4{osmhHcXC6^&2efo8bvd>z&n^XdlK_2iOwuje#m6{Pyl zg&V+Ejd3GBv_crwfz*`AxgwB>IHn2$c~QE5nD%wl(KewTGOa8BJM;UPD4FdkB^_jJ z9?dLGl1IM<;7QB*s^}^+Uominv|`3LYxWW%nkSv2J{j&QokP6ZZJt6TB0UOzR|k#2 zjfqOe93x!5=~tgS)?e9c)ANsd2gUEiT|9@MBBk zNL7idJO-87aCtbi6ag)W#VDgJ(RkxLfeRLud$yLyEWfbNs%CA%e#X zl6~)}-;vi^9~E}(Igci3@i}}G68+TMI6-G~P^fhnGG=Q=DVe8=IltHvt+&ULa=kot zfq9c#<5grkfV=&av{lJwS4(uEAcp6rjYc9A7eUv*oxC$q~y15$@IWQh)kvlkYLLAv&F&g0C;srEyd&v|i`7pabCG=lWUonctQ20F}y z=tbt8r+da&aty9>sdA4m%)4~-^XrYE0gw^7czrrfl41iLWiFlaxcz ziVQQHRG{o0Ij4CDU(0uBqs&49v&vzdiBxY*HFh=Svq7 zpF(OQe=}_iE6OiXs&>VEPB^d8yq%j*H^7l}`~_v|Sh1NFGTdHC)8<~v@0gRUy{olG za{(?kbX!B+eCISVYJK359NDiB$KRQlcNoQ;_Mb6md+I6k{0A{N@il?VH&i?g365Om z@(!P$g@!@T_~+<6F!pjyewrnm>J^90LtJBqcWi-{tUQL@anf!B`Idp-Sf6e zM3JZvKje6otR;l8ReAknVg9F@xn`2clGwRdJA(}+x~t=XY;X#8bbpko0+`L;(vbwa zYD+Hmp-uC)k2v`rmbO@pLcb>^tAWMcjAa4;1Nb7G0^s(TgB_p!Hf!o z(zC*b*U4GhcK5BqA`$SI`PZm6MB3rEUyPtofl!i`Y1jSrYW*jPW|IkqDur+>rv{cL zl0-$zTIG@v<~;1UpWfEp$>rzH6h9j9U_!r!#~PxRUB58f)^-O6|pevrW&N!4<0i>O-zx!*k*)BjVWdSXMO zdExyWD*3v_!Shh-q((&~mMyZqXK-*!_9689eh5d+-%}MwGo%falzM*wX>@Hh`EqSY zh5tyr_d#(rN4D%nRC$Ec=7q%apmLSnYP?V(9B79pPG%vp5WYsqYUnCl)-9vLk&fof zxe!8m%4qtfJ&n9ISp<ESg#}2`H`$+vw>+OXoGD>LM+yAJo3GG7{{hn+!qE0-L|de$fnAna7{?djr;+-TF_7 z4lo6Xv}7e4Gsq_cSZCX@D`3;MBvNXR^(e#XB%#JLrO)O|You6{VJ5OfE{0zOL<3=suY`3Fmp6C-z^uZ9V;aNg;%edAzsZ zq>toV^GamrFx4Jo0W&#RBlO`T;&RbSh1EG7$o%}_D`X=9E!GP?^%Ad&f0r^M`b3(O-@xOCK7d7#ZN_KlZ9hDpMo3MGIk`SRRkY(-9qMP<7AP$3K3L(mKSv8(#ad*C6mj z=V(b>bH6WQ8{^YYcQTa@a%)Pt=R8@6mmXbk3d#5n zsdA%`YDxW^e1<{zo{sc5sL^(3Aw1Q~-#U?Ha=wB>;=ABmT6iIE{<-1VWOi zcHmBN0Ij^Z&z?3U=@-ef~6?eLB9b)m%&&BF@dShmta9Z3;ZbQ&uV{}m)wg-pD z!^l+3t~3KSk%q8fmtrc{~% zQ5+osVkX#hSl5BYd?uy_+0bv)E%7B1JUxR|RsZXROAY+R9JqYhQ8iI6m8|5BW@&qo zN~|E>$GRiU&tJijsa}NMtM8kMT>DcsfkNC$2O$(n#Fg`-1G8Zj(~}^j&++;D*fT;m z4UKWWohy!;ME3F-?6Xx`mEC4#YAbGhLUyJ*!O7UH%24*A2%qIdV#$=vzG3!KEp*;& zGaGC%Oh$#WA2n}yK%9W@8m=CCw5Sxl#F{~W95xueF3Z*=szN#}yJ62H$k_0AO|hR@ zKG~#ajLf^2Q1rb5uNG*WWTUegD{0H}(xS&f&S28hDtP|@v59D?PMI?!8%AtDuU8JO zh2nW*Ep3H>1#5vAq#-{=Ny;V1#OQqlM?1rzzg;z%bEdyDFy4$K<=>#ejs6J|L`y+i zx8zq1^n`tB#eep{GI*)N-y@1fhJm>=Nj2$>IP|D>}{ko z%mX&u1Fwy&%18lq=Ussf3z2H?uY_zn&X zyi3u{84|h?JDIDK5gS7HNL6FgkX^dny_o_oxeC6FQ@Hspb**Q%-;DJ9JmF1U#YrRF zT_05rixfeoEkUVVembW()zdgc@6*)92f4)_Gl%;I|DypBoF@rf8>ql}pO;_j&|U3j zrk9mlM6xvfs`R~dYJsVDH(@b zvGVZdA8d9Jb*V7x$|?#ITjpDzpX+35t_qt@Za z^?^Nd{)mxMSL+3jRPguznuji^#Jl#OHo+1PT^rVzhN`8;sx-__``A`f&+UT`E#Q z7J#^-8bDP-I&~qT!{PLtXogXMTuPQZ4Y(VXVuafON4KAWD9 z&x-q;>T~yhni?lmUa9Z-hF+i`{%KzIA{r}PGwjuOdZ*{wBx(}}evLI>>QdD_HIkE3 znerOPYX#utj&+VOIVc&Sb4f%JhBhrru4C2}m@DzvR!e7N<4Sx)K67&`6GFPLb;`ML zwi?F_-0czOa;@d5*G<+gF=uWfDXaz`D7C%d*qT2rg3AvtyN{X~K_y&hUy-UwIgi4s zSd>7G%?u5)Wn)w${%%24zCN`v4uz7okLRd$`P?OSSI=oW`=G3$r#_e{C z4yBT=yEiwM80(koZVZ2~h4osqVT@mIefgH5zG&_H7vr)d5Jy;Fie@$*Z_s0+aTQ>* z<5jZfMT811v}b)-dU>TG#Sx_t8m!HE&NQjgN5j?Q$E>1a>&og0c-Q@b!F|S^nwfqnNq3+VlidXx4%?|4A|XKHH>Q$inkEIl+t=b){)Cy zLTOm-S57QDhv&jmc|j;1rvp>%HgX64u zRB4wEuR8Ua3a{s6_gRbd!PFmYzSahq^#P*$@vbKW6RJ3ZYEmeny=L=jTmVBcpRrb& z<(GdX(p(PPFBf2kCYWn(+y7sz_!2Z!fvGc+D%sae^tlfwHOXki5g^#vbA0@T^>4-F z6jcvdAwir(gg041Dx&gRnNx61B1RQ?&eDRC>fzF?65yt-ect#7;9bZrZzk#ou1Eyw z5bwT>;UpRojy$u-w7wa`8S`?(E9pbAE3d;H<42Bngjy+4bs^Z5f9x@E}VoBE20x7t55>9yb}k z+4$XcBhsMV1d7&VFO#A!rX5b*ur&Yh-119P;xBKCXnj2$i6x9V39#m=ZOqdU1$!_> zT20ZvtLC~QxHa_iXY0z}5EG__J5l%Zo_&=a)1g4W%}>ID9ndWxRt%j5@W6->a`j%wFIbh z8*WjwZ561}j1ogMw2iw8cUGWJ!^nyqL#H$$vA-6$Q#o}WQ`zmv<5*S4FvXsuqe`Z) zPc|dar8~|B?v=`qV0=iV_Dixhq6@!VCRL9C&GSq2LOnQ56VpP;PU@Yf$03*XS!3Z+tC08Ej{; zoUBapW-W_MvZmv1bJcvyi#Ps8!qmnarJ zxu630hbp~fgMJ)Nk%b-vocf%ksScdt$tYg9{|J*II@#2e_n%LuNYx(WKj3JQlmsf1r$JeL5Cooq`yogK{bpk1Xlt4@|Ai_%

N0b&lc8qzmY6OUK8oO)8lK&7XJUnXlck9^qw-Dt*MHd8{3UU+`n)lltOij?s(MFl9RH=R5)O_^x2{+(5x76BRJ~aU~;3r zj-p()ht(bjI!A_DtDn>KrmsO~4Gt~Vaw^*X*U*bue`*X+!$oF)ea&mPr9<+!zb!W^ z`3K)`4}xBQ@Bb3k6bln78?ai%nENhoa6uwqDqd4phgW+>jSKc(ePlh-(X$F9-H=rf&P*Ym9c$#YZ>P)r`@=6f6J_en-ev}yV97G zVkq@~Ad@g(D5GKHF7{CoWd@ZpRWl1%NBz}Pv*>*&Ma^h}_C9NYqt44!Jje8=*eNpN z07A9}!V}1#6Omk+gx&mRYaA?up#u~54?Fh?<;J<2tTAhsNAffIN^Sj_sp)}I0PB7x zB7!k=KeEnG^?dp4zntxZ|LVb4Mk1N~e?Aw}rf zD*EuVh~YH&gV83iy#>g7TU^L1&VxXht6sMokj%5Qsq7@2I_b#Z1Xr-v`g{=M`2Gr+ z@?CXWaOWD7Rgk4z8LtafZ=OYjTP>_vyNYfyF5qw)%5%``{Q__ zeO>3N_;ygZ4+8#`XnIbO-pfey(6+cLUR`SXqtGwYYHG)|ClvofLyzKnQNoV6r>&`d zcR-*3wDE-M8KR?ZD!lLhDR6PTb@{>yt$LWKEf-YOysUkfOq@C#Fw!ui*TX`l*Hzcs zbEd|eE3&E6Bt@@9-@m+IpuxO#L%hps--H!(Sf$Arg$a<8Ua385TshpT#g0NHx<>Xh zk>~>#+C9> zg_Fh%w(@>?#=Ah0)VCV`ifqGfUd0h$3pkWbeGNwAkQ6UpzgLg{oFOy1{0rL}5MKHO z;MT33ppU-xE`4EJx#YFLCjUpgeYxYvC_UAgjQQ27io)Mji1)_}{V6IMUyO-LMJAj~ z%b8rYld{~$5ke?p79&X~V<8%%Blnrvq?H=1i)%+|1;&8uZ1bVXri5zgpw&0`;}A9C zl(rk2i7rxUs6dAHPUUoM06q0)JHFeIgL>6j}(bA3dHS~8&ZU%HoK z^JXdIupz;;^qdb{p<2z$WzjAhjAW$c^sJcnCW8{3j>JC-@b+YYbL2a#*o6exk3JX!=89qf%yWjh}7u8HF`h2p~T6hiTx(k)+A7p|~_Q{D}oHR*k3aqH9PIcb|} z_Ds^T{?Vw$;6GvQlwdu$bw<4`8Y<)F5FEY>$XOY<0wEx{I6 zwL!OZfPnW0K{%E=Sbkl9;P}twDMwr`#ah)e4r&A8pcVi^yESEW=X2% zwPGj1T$w-X+5zcQC;z9**))D8`bEcT9gjAS6dRTg-C$&J6{xVB3aJNOwXdgtXj1*Q>ikdK2umA=nnqspQh}R)Y8^RS9v-C@ps1dN9 zD3t(}C7DS??u*`_SQMj!;;~ew@*-B7^{p(IkxRBDJv+>lDOLkOqAs+LE$m-x~9~ zjRIFI&;Y5-8WDb_USJ*1Oyqr8PAK{coQqy*g2yM|LeigT6uBH4eY>i!muY9%-1&i1 zYr3b4K2U9dI2Ojxs~^o%yih;c+r?+rj3}h#F#v?K12M?--L2)PqDlb=v>kEZ^(0)Y z=!i6@9mO|>3Fa**XpJot z@DSuQta{;au9L#}b=)K0v@ixJXXTwjhlFv6$o*cs(uK?L?-9CLR{Nf{+iIz=U@g)MTg>aDnyy5Xt2p7MuE@U^l86KrnZWK^Wegc8$8j)yP zJG$jaQ9IN%AkPW4f;vb$ql2hJ_;g0~8HdH5F+xmmpe=O91+_Z!6edkrJ;`ZPAtYo8LfHm4;krpQm;XyvfABSnkz0dV(UxF*)jY{g;l;I?HPUlDp zdZ;0zWr`kel^KGFDGCX%0@^-V(Go$Xj7v&|Hg?$D>frB6I&|zBgk&h0gm5|gY+ zB7JXKJ^|z{ge|-zs>Moy)fLZlz|k#8|8eShPkA*MqLW4FmKO$H0KQ`lA@`D4$}OZ% zmwPjkBqX3sL&_)Tt)>S3iI?aw>5pj9PBio=YqOD18CCPIf&{ZNeY}=cKSW%=SZ?z* z&48PY4CohyD60h)r)`H`FWL%v5NnF=dL%@7K_6AVMr!9Kw=}DYn$HuEW36PW))xF> zf{~gn7OMDIXi_q_{YTSv(W81{)@Xo;DuQDKAGf|D$SRtj;>4yZ4^ZQs!i>2Kd{U)A z0|Vs1+(-8Gg%Umdj3|#z;#|UDrtqX#Lhb4Yz0sYrNo8L?ZogSIFC1$!RvE)(rCENL zu3@Ea+%LhPf_+QyDZy+P@^pejgZ&Ha^QKKHi=u%Ml(Tn=(6%8<0O-0Ma@tpxyoAUY zk;@Pi`@lCYdeW02P~iT81Cf(KJq==gI9Txt8$Bwp%;gX^(sx-|fbVNf#9PZ#;b}?N zH;cGZ9c|onrx{t^qj6SRS6pmy&JiR#@SE4j@z@BRO;B(21YzyYJs0rg$}f3Lpeup4 zx}<8|(`9D;>zo0u)?)8+CGjC{B*7Y&!l!5WulCA~8N|5o^HF>{iOlKl+TTdT)q3C+ zKrYpw)j;8BUBmHe`zgR+3{lgRgfnk&;i9V*V^T&aNdzb zJZ(dA@+@j8Y(;Nq^wM)p*N9VHY#z+f#habpL=656Bq&f2LJONxP^4zKkyuub3Sf{xt4C9WE~F5vt}a4gY+Sv7sF+%T6B(i5=5^0lr>cU3E>)|D z#$BBod?ULQLc+MW?<1k|LpMSx123U%-`Z;%onmTgo%6ZVE01#q=_h^hO%6#X+m$)q z?b9EIsI#|y%BQ2>nH0)Zn~eiz%${Xv{e*_}25;72?7_puo88L(t6CQS_Qn1%C12!@ zQCNY|dQ|Z&kr)6~Gs2ne0iJIDL4~OerSb$wF+^NS|{HeB{!qUc1NFP z`>0EfFVLSn==QmI3X2#vyy}gCj@wsAS8Y$IRYILXrBtcz^m{zw0`6U3JwT&g=Dj zy&mI!zuoHs^oE#cr+q8t%`L-%SL&ocb%!e*;yA8>b6N<>fdQVbIWHGuFflU+DSwSG z1EtV%Q;5dgPu{_Dn1@lxn<1Nh0-k@1kkFfvZp3qipG2NOVq4Ta@Y+f%sNUkLB7le# zYRWX=^SIzc6~?9Uz~MXg$nna-c0C8gh(EGwjuV(%vJTxl!3aj;lXGS{in#6V`EzTR z*Vt}lb_YM~>p8iU2rzl7VlIfRBQ!aIs&KiZofxPBvkjy0Yk=YC=y)4BI-M28mPAOIGch9z} zgrxFebVR=!Hqs?Wcqi+`$bMAk&$vj7n(cvW$YC4mBRUe1Ab7dVV`|mE^+}Z*jS*0g z@o88e#pTZX8RA;?^QYIxbJO$Y+!ax~LdNV9yQ)=JeuefQ4V&GEn+B?w!c$Sa?8xWC z!<5=LvK~W1&<~}59ReTOF_j8j4!@kK7B?-!;2OP zvHQulS4+9r)xma1Ir}E|wSiLT9#ptRrL<1Gy)%R~o--F{d-N4i2ejMzcVFL~q{i+f z?&Zx0TXnYZU4SJ%fN=ScYYRea_WjoKr3uiTguXHhPV_yLV+MSl^6Nz%W~O~RK7eduFUWt1BXD`&O)F;3eCadqoauf{Cz2}njsO(~q%S26Qb#$N4Sx68fyASf#yMU0A|lr8V)NOYivf zW*_S`W>a43zlJQ=+3R6x`bb7cpNt!%vftxCJKjye04nvre6xq=2usRVg`*pDk|Xf3 zw8r$EpQ}_70$YSYwJF%qyAJnG)142VmD3vbg&r53lz^om{HB%4boRxxi{_^xH5%G> zD{&?dNf44gD1J|_*!Vp@DDw2fq}hYP8sPE&iA;~p!|k366uE4v22bVpQM+Xw!=F)H zeWpWgcx#g?P0a(G#YS{4dYqa+<139`ycLJ!Ua*)w?Wh7Vlk3<{X->`5`LjSJykXkw zZs`qQ5{&2Oee*l7LM{zB(P4@pTj~j?OxyYCqv-i_aJoP4$B~r>sd63zs%H0JYkmN& z+O5=w?C438gnwO`7oSfb=BPgU&1974&rl39X`onsf}f2Fz|efE+ZlAKUsdJ$_uSgN z8H>JJ-t#pVmp0+JlZacQ7Uppmi{UbtoqvIp2`_8VH|H&=tE`%@_xRf}u@GT}D1Hv7 z)}$&9Cm)lFMO9%xLUa1-4s}lBZuD{S2XCcz z&8QEe#C1&3bK$5r52@u5?sk&Z)0U~UX}HonSeoL%I5uO?#o~qKTQUqyo8VBcI`wp^ z>)uf4-rHpofr`uTDPf8f4%37dudES_lTYJCoOgb|N>xRzw>FL&RpEp;$?b7s$e`k@ z0OXkvps(T>s>qIMN_hUj$e6?EG~Zuz>@(Loms-BQy-CpgLA6Ynde1)}=bGKZu&xvKww@dQ?Dz zPBH^_+y>M#dk=j0wLnVp!+WlkF2((?)uoET5OnSB9>t220xY2k6|2tdSzjq&BFO=v z+Y$QS`rW+q$yr<0?}|PEu%>dz-MY72t@HEpD#SK-0gy#d$yt~lnj!C_mrJWt@^v5G zirEXU0^ELlHuNhmk=3f)f!lE&%ybqBtXYmL8N@uYTPoPj;LF!;eJSpxq=pz^!CL{N zt+$19b3)2}JYW+}7}=rEJ{6-otX_Qj%aY8=k0CN7n-6`+wQN5M6#tgSQkm(c?!Egi z6>83QR`QK7&c^zENR2^_L=z!cv=Pb-oa@vbiGB2*FJc6gi0hYOF5hyc5Z{4fm#CTS?Dw-F4;4oz*wR+K=@; zS?a=xvy{mPMuG%a(}X-wDc$MT_*Cuq;6bCEKpLF6N`Y7D6K#xDOjmbs(y$`*b$%;vT?XNU zXZ>i++ycMnU(mp{qKL5~UHM-{)z+?2TOL43N6Cm=#O9tq`VvX~$^|uKQ0L{w2+F-f zP>!lD6aMmoTjkcYvPeQ*AIVa=pv_RHviTJrcF(2!S3`m?7HM=$>IaF#GN!NQ9eHLe zYgxVw{GU3)=jI8{+`&Nw&W)MdG5+D%hMB6nYnN}k5WpHRNYkNorN7N_d=~s!9Tt@! zS`7%>D{_lUbOnw@D%5yO5cnsVT*dt+$`~yyKxn7J9AX+hT zJao{fi0rf)`7U7u`G8AqMg_byx*ifM1C!XM#NaXG2VphjzL<$N@Y@+N>2Gc;} zDEWoH4vNsZPJ)j; z9-c$UHo>le-i*r(x${s-x379tgG~23-~P}K#BT1pGj0i%cUa=!`#2(F%2}}TZ>?f0 zbA43!<*e6o1w= zV{c=zN;M@1kP#3n#ptm4Waz?ShW*#CMUJkoQvc%6w3BM`j|UO#$oW`3IkijG6Dxce zx5Y!n9@b1fiekQVcB#tmAb*ORa&lze0>vqQEhXGs0F!U#D-bZcXuXXJxTDR=nM#H) z9g*dRy;VT{p|#peRGHBhUj8yVXQ8i&_BYYVdgP>0O8?^BH})xrDE)%4r!q`;2sRlI zlsXWpW2?|O?>+QFi%9l?%Ol7Cy~t z=IWd#X-E2Np~oSo5w%oa3i!!{ghro3v&iW`c_li&c!Y-vTa(mXEPDf^Rs+{j;z)>% zCuNgKv6@v9a@Nn>5^}CU$C&K#3`VC|ho$IixiZ^b4ejAlB-;Y^sJruXA0BT>I{0Ms z;CuM#zN_}Bp=EH%t=U`il@{`$OSUi*fMMb9@xG+y&T;+j#FlYyxGTt*nkpPYa`s0m z-h`k|C#AE2l?g=pQ@A?Jg|^p0rsbkVB=}+;d;L=jxc!C3ol&EBrv-HxALD&_-=n$r zl7@{fQ@Y~dfVplxS_xfu!Q9r0hIokYrWpUz6|Iinmjz;>$Tm*yOEwmzLP=5i5}eE(cj-yJD$oA3 zAsd+^_Tug$;0_}E(H<-KeE_ZGyS33g|NU&y0*`-7?$)p@?vcBR*Mk~ab`$MMTbQEf3zk*D=YW_C>+QnA@f-}b`LR#rpp|DkEux4q?A&*God%CR8@?&$q z!U&y^FMDjUR>=A!OkcgGBv70_6e%Tk5(m(TSz`ueqI6s(EC7ljvcpwxROTV ze9*7Tm!P%Ai)pL&_f5Rp^gYwol#r4#IM30di%ZhqbbHQPQ;@o>y+b_;`v*c!+@O+Q znU!-AeN}NZCUel(vHFGmLKKDzBvqk;BKh7(=-O7T;^(}62h+BFa&DN;Fe2Nzl%Dtu zp%wi8lfyPTP(WS6r-5aVS(>L(B--c^zehwmOVcxe3V-6v{jc7ezNz;TI{#vx2_(jd zekq+Kh!1wg?2q9*)oau<@f*ORly}FcF2!QgV8n)X)(bd8Y>wZ$FAEZ4n<05~=Hd(V zaoMs4{ZfxOy0Bnwo^cUaldUUoIn(n&bxy&S^m;0%{B>Ul-UT8!lha5BR3fpajO@| z!qH;=?k3k1IIJji7Q%8{maA#*IDlVOre!Q$Zz?M20ldo%iMkwboS!#3onOqZt^7CI zkh)QYztoamQhT`>7iZ8IR$}FWbbqP>634Mu(4~7g8d7vsF;JjmpriH#yH}022ivKF zTCs+oi;awmP%cW8KvzGlGFo{9P_&IiBGWWH>8uoR@Im27{fxt{{_|3<95e;6&Uye3 zw#3UQNA&BD-VWm+5hh_wfm7*2APwL1j4E2qPZROpw5fnik0CfzxM{Rg?Pg9G#zu0=;de^0U{hMQ4AQgh!R98es+G9E|OMlh|+09662 zXEs0D+ElEnge}iizI;?|78Ft@*AwbzdORbBH@Q-`qG;2Ku5_IsFj77CHhNQAw~k5? z_L<`#sm0lae#Zpp81f1&{p&{eNv^F)DP(E_-St0G^vvU)46VUn!f3TdeNE#UNBJw+ z8r3((9dckG_X=nQ!`NQ%48ifD`mDn!J!6o}4|%Az+UASWw0HrlE;Rv;ZkR}V|CuPR z(gsC>b_oR*U|X#xy1d9Zt*Z|R7cm50bHD^dfP#38`bXm${`u5dTPp9_w74`d$~O8I z`9T98uzGNDf(jJJ$oo@b3UbNqQN_>$Q_=(buXG7vG&yq-u$|2mPGl>u)f-{v}7Kk#qT+qV72(nD}sQlpB*`SH8oFq$_7(z)!n7cpnw zBnWSW_z=S$)QtSHXroA8Al?l1kqF@->UPh7FJ5W zLLY!D2a0(pnp0IZbqG4lqo^U3*FIpPmR-alwSx>NpMuOSxf`$aRvRFpWE+2g%#o2^=Kai&q#~BwTCMmRY4LB8^$nsXp1jQcBKGv~EDLaEJu$bKQ zgd3iWH>~GATzEU<)QAH!zan?Md{%v$xZ*#!SZGSCG5$9^>>^})kPr`p%C|XtZg%x+NJ{C;%Bp!|OUGuCAZc#0Sg;N!k*`$Y)Q+N$ zCH+qrfXPj$n@ea|O(39V;mC7spsWP6Qn{N%~amb_k^@2bJhs5C7qfyoS(tPe1 zLf`gLvf~Z(VqvyFKqermOrEKMO6~X$k?AOm#>Pb+>H&5wyYwjTvVZl}f4YAP@sCt0 z1mw|6B?yh^PsN$1sA@aJFW@DHm8;oZ_0g%TMECc%d+gFDDqu~iTP9m-wbwS|d5cCv z&`P=ki(B?6poA!(z$o)2YribR z)oD#D@|J_oW(Oc3gUhXNf9$W&k0}#jVUP7ceasx;zWpef`hE?})*e>)PJWp7dGYmx zS0+p*%LzMHK3jDco0wPi2kv423n?spvnQ;gagMF`%^AvlQlnYoWL;LC2$d|O-L$kC zD8bYH6ts1tTXJHUxl%dw^s}=gx-Bdz*I*nispBs}v&X$36s5-fv}8y&WHNUJ=*?ba z#OAS8&GQ=39@`?C_fZahblW$6^i|ImGMwSZCM>i#eJ-uceAf+LAA>xY$K<^aIU%WZ zf+mRE*hZuPOUGW?U2^@3K-WA#Yhci5tH=mY(V(F4Wii_QNnGVPPu^0M%(Td2lOrR-k|@xu1Corm|AZTw#I z8hGJSkd0;1zb(IDpzH`n-m~?!*G#y@{l=_>@&)(WfPsTlOu4-WS=!|5kZ04LeP0UL zF5BPlFB3E2P;@M89};l>t38JBu2;HXkGLi1^pTlCl>d&zA2)1;>$dj`cCVs1g3H2*OW_Z zAr&%2ibz833*UNur2w{Yc3By=G3uNXqLA)X^^zTDb4H<4N^jB`Z~uoP%wh1>i4;6~RH1~D(% zJZ+*^mBE~k0I!BtKF-!e={rLvqXq*(doQm(dq288^m!5i{bzUG{}(Vc+9&{eO+n^q z+kzMXwO9$ry)3{gARt3}D<3&cR;2k+;c5m+*Yn&F;-&znH=x1M6x7ebrkR?MdrtCd zY^v-_vQvAN!IpYL_9%b@-Dv0>HR*0$9r&yBdZ7R;DTCjz1Cy9MHK9ihx5)2E1W5Ia zVAQbyI6^!Ji6%3ZrGes;F+!50f_i}TjqSV^p3ld<`%^kuGZR|Y#dNqrs*oDr{l!>U zJ^XnA*28cPCIJ1giiclb7fE%OE9t46a1;f%i8E2x=I5TuE;2Ni^JN}ewgxDTa-}og zr&jL}hkyQ{AF4WPYZ#^WKoT$W)5@<+JL<>(($Z? z#-Ege7ysOZMrwg!3%a2r4OO{S{oQm7i1ly=47Geja2^!xZZ$=ofl69*Jht~A#M0xH z`!3SvdPG{PHK|!g*Snb7iIPd6%jTF=cz-IZGSNTxO$Dx~&WffidlE)ptJ3#r%0+Ba z-b11)K7HDbvSBE-YYLRz+%fKxYhHnD{zcNJLU19-1nD7*cJ&{ssJthka%Wh?_8YHX zm7R18ekCfPxig8Bnj71hm_QUr+KN*Hr`wOFQ8)0m;@1kUIdxw>&|eyH|1|FNtQnu< zBB7Ue*|j?GE{lGy{b+jcddc>a`nPX7X!eQK&u?7x5*lNVO@jRI-HcoMty1^EiKf2o zBZGeTK8Jo%Wyj`LSX1V7a_#5jowBwv$+w<1Q+IG=&Qpcdlu6(uj;7)61 zT?->2F^d%HD!^JpOQwgvdx4a0+oLl7A~a4g0)F9xIXe)JPJDo)<=cwxIcQ`bqxJ4k z^Xcxq+~lDI{Wfb;Vb*H=?k0ohoF?Q$Yqsu>`ycQh7*RUk)K%R&9wLSc^!w&6Sm#A= zVGRl7x~c1_FqmzJLa{$K7JhgowM-rum;O~*R;~fRQz-?x28cL5)~VB!PJ|Hay9Q{q zq;6?f%{PiI9bnD`Th3s#qv#R%)pqQ_+S0I*J#F%bKA^m^ZOyepm!|3La&+~I&P;!$ zBj_d&1tBU(jER3Wuu3xl;ae3MeJHUbmu>lkh}=Wlg}kt6o!4W#D?r(4udgi_QP^k- z2RR<(r{Bua|FUd$=z27J3jd|XUy#KX1uljBbpLLNsglP?5bVP31 zh;Bq`V6C$9jV=Dni3cLKa0Uaj2n(xPrxzTc&I_5)x#~2{5Z>neeTOk$@X>_kIg|@AHPr%G1nr`sro=cPa zx67LQ>y@>8pjT#J&v)2;FR&Y59ax*6uh5k))9qtKBsD_l^gbT5HdAyX47G10XZK{W z^>B87erX<_wKcxc&_o<~*Swgn74QrGsEE;a@a&=uf=yURAaP1FnyUR8NuCw%F@`*) zUIJENZuf_fgp)jxP!c!xF09S=f#;x2J@HvL9{-&0`9($x>nhWtZEv5Q4WZ>ru?ixf zoRRptFp5n`AwS0;2$Cn(*v>OjXlM5Han#n_u0y0gFvaFA;7awqj^B(n%8IsDkee27 zqp!N-7z4VzC;&EVvt#f2{4dSDgy}Qi#cK{l0gCWAhzC=x8Ww#cO-+@c)nUOAj9i5v zjiZ=mS5O3*^udwME^bS34Qyl3CL7;?JlzbbiA8-lLAec)X)AaU+sB2W)6}cBI9e`h z)Z|WAS-Vv&S2|s*e2ffhMGrpwSP%U7j$*Frx<<9!kr{$_;>o{j^f`5^6bVcfv2SRy zx}_dv8NNOB*CZJqvV%@Ty8Go=tiF97xbn5bZbr@-TUC>j%DvDk5hA=8RmL{`&+FRz=zv& zq1(T-hj^=7^}Wu7e_h#+TBj9UX8AKvio2IJ*zNqB6Aw9`YgK4~Z``xRyBG9V(2Jz+ z^D`z}zuaQ(?Eh8Qoy#|xquaES)1Wf>SMu^)HEr!k8!QS=t7>bzh6ibfI~`ov{+r@Z z^-_7qiP$NvL0b{fPv{xZYP| zg}wYI_~*6mH=4377rQI?OLpXi_usbe=e}sXT!2JqWK6)B-jHjHNAtT6%_l_DoV5>{ zuSA3xZ>l^MlP<{jFFJB42wy3`D@cL)x}YqVAQ?SWBgbwKd)O+3M`NcMs_7%mDF&p(`h+653heYM-5-e9O$9eqxOr#2otL3!&((PM z9jwW=r)X?UrK5Jf@;;T`WyOx~LvWK2y&jfE&m&N`%0LgCZ7_IkL8Wd3JvMwV&H(is z{kX~1FDDq?*pMhDo(|WMoIfXLLUX0dzcML95+v9VrgDFFKzS7P+_(JD_I1=JJ=@Y_-mni<}HfB@0XHzH%nDxaD>jJndP)fUXwjx;p_%ONZqwS4aBa2a)bF5Eo1hv{iVc3O(Ae|}a3-U5RJeh1+NQC-wpP7j zrD-%rP73ZpFz=87qXv%djAx=#?ztU*tPhLHJf(Hd?LkTSHE=eBkVa2%`ZJI+68aekk?g+2Tantknh1@^hbyNL~JsowAZ7lGa+Cu?$%f6cFL#c1(}JEweh~hPLAje?Iqwv0hky< z(}pFjsvLQa1|(QjA$Pp{8ixYsdDH7$POZzimOzE55hy`uaxiAuWx2W)@)M>ilCt3d zPC7Dd-Fpf#Wc5VS{aaaI1|Ps>reWU!hb3lWbsaPnz81-ZrR&C5Vpcu{6&Uv^91N`_ zBk}B3=np_qN=<3JV|oJ&*12hQJ;%bFv_xC8mjuufZfp-@bX=OwI449z(=sK7jHZ>-Yi>3}pP|2OR1I)D4_)f|G*i}v zrBJ7kJnEA{@DuSy;%85k&pVd`xN+4wpJ`QyXT-n^O<8&4^__-p00!xbRDC*7P%P!f zB|U^rK9VgJ8nY!VI4qKTU+lh-(=^V4VYv!-vVl_1ytq*jTON=nG<_ga`VJJ!mwu1; ztv!_ZJitkrG3oRDO3sX9!I<=GWNq%MfJ>fo=%OJr=0}Cf4v3OzdXm)uRZDXP7u={PWXy>$=tTzj8{n~NwZ(AwDW&1JDlq_ zmQMnvWkn>GDJrSmxCRfY-QYr7xu?olZK$Y)ukjxdjNMvvB4ee*whxiXdz#9N3n6F4 z(E>`Kv?3!`Ow8*N3MXDJ5I&)EmS!s8TS|5&5OOX967RB)y&Af@ zR7n&e`WyJP+Z+~>a?TB@YT~UTVHZ=v;=kn97dQwK>g>d|)0y1qsi~|nu_g-Lh)kAb z6{hV*57NeYcr|d(d4r}Y$9|Inb;T&){aRXE&rp?8;aJYwQeSV;hnjDc)V$uf{3RZ$ zO`5DFb3OolEFjtuAK8r_}Cxk=-~c&i>MBx1$2Kp+ssgESbm1Jq{0#7?(I280?kyC2K*TUsr$Zkba| zSTSvHP=0kn1GuFo;3NK7uDKAZzTW2#Gu@wnVWvlfb|;d9MRJ{hpx}oKU|igFAZEh` zELI#OrcYi%e8&UWh#L~f08j41R8zAzrQ_Or|BWC`0y zYBfM2K`$yBZ}_~?iy81H0v>x1PaEFlG{wYUUlnHzow1Qz`4hu*lX?Ubs+w|cqSNQ8 z$k#_MYkaCM*||`qhSWM2D-oqXPHv ze;pB%u(%YL9N7|70BAU^V1TgLIOxuQXUZFO*_#$H^~(OJ&4=fCZ~RBqc^}?9(%8CD z-!p8s~Fbqv?{)&^VZ1c%*C^(mfe)(qP^ zw%R}|b{+(#3cM)%r2+zPgQoV%d1khY6-LD{rFKy~#2O9KgVxw%ga(%V&PeNpBYz?3 zyL^7II|uS)Uki&A|I%T{;whYO5@KvgD)k|#zr4T#RbD~v)`e{Gs5z0-b@CPzIn>&% z`Zh{Dqy*u1Yu)XlpDTz_r>e(jT3SmcP4D6ERQl4pvd<;B9;b*QgNG%HYx#XSuSm3@ zOz1=R=|8}?Ck*^xr%dm)f7J;-JtJpwsV14BRR3?`z<}c@$@>4Z#ROb0b17`bDMSmZ zDcD0Fp;ZTil zhjTef$aMiat0+ORujsb($b(G#*KUuC)3#j8);nU??~VsXjW*8lfw2h3=NrEbWtw34 z>LB@7UkhJu@zfMmtl_vBa?K-~7dKvyy8N@;7_nU6F(p=%YI1%R4?b4N$zv>J?uOI6 zwXU1Vl>_!kj#Jzyf2kL)5-ms1ej zyrf6}V&1AZ2cALz0sWWupvh|ja@Jf(hAZbaof3h+%Yk}1ssOCObn{m<261~*0L%1P zrOlq6^0;_$^&VRZKp3=Wze`SPPOn{a+lQyvjF(rw#*AKX0OjI&fM%$XmjkmEP^iP! z2c1kZ!q{bU5L$~`eU|1kkD!vtYw)gS$&a(;vh@!#Tk+RXCv^m+vT>{EZpz0>>E>g3 z+Z09yxEs*J_zu75`I@XJn+$!jf-8-K!ZS}qne?NYM_T^jX@fg%Mrq9QV3i>UyJ!2= z7m7qG$^3%VO!Oi-b_093l$(!raho%tF%{p<-L%tChR5LdWb&`}`yojEm_ zxKJe`80~;Jg*h96rg<*koz6iHw7xp;F=tDybll+0U8}q3uOKczMxyzIpTmb4WV0 zCx(s6;js$l6t1seL62evg+S@}Io=>Xb5WOtLww&d%5eM&n?007{{W+`gN#ekGr)ub zw~YWMQUr`gMD<6lqh=)zv`zyxiE_24?)1X^A^f!UwOElPf85LJ%e&nrn`c~ti1LKsgBwlqUAu( z;pA$@Ob(8M|ms=jc&as0MB+9lf=rLrOxxY?9UwVm`(JjUE2uT}Vnp(ETgxkuvrZV^jySmf} z+eD2!3^t^|WH#aoN2vwGaerZzaJ-Zvi{}RQ8Hnwhq@s%6?U;UPtk1KPULY{y$ZNjf zsXp?8ieq?r{#270o0@DeH_eR;Z+IV@%tw+meWcLsCICt2$7;P-YgO$M#2!$TNvLt0 z_0ewrdV4utMXJ*+E!LlS|6TTJ!e*=TtFIqX!iPEBvvYU@DgPcE-z5Irw6HJhoy|#1 z?lsWJdoJ=69pG{b$W{feex_|J`7NinDFBofF#CQkWSBDS(7#!tqxh>dg2I#k^Lr7U z41Z%DyCB@}SFIGwod%DG0iL%p+@D<$003EMdr#OpqT%{lKa9a}9J)T5I?a*G`v$1>)P4l?m(;ala7Z3e z{x+_Ig9ANFDGeXCh-A4=RH|RuA+#exl|epp07yzNgdS>+IEbk-}fTdCD# zaKZ)MNd0RIwL*Jx)EFsaQ|;Y*(??d|Y>7a(P*~}w-pdcPzswCP_#*9x#{8^_2O#Gy z&kub8QU4FzDg<(%G#*`rIetp8Ln?wt!?&Z$NU9~@koZyww`W{ghKZ|}Oh@$L<-?tU z5E1hl=NRAUl&-YV`v7jXLocnZZe!n?Qlc-DRcgfRUmvz}BW|OP#&(mYT|ye@dh_3d z+pT@!&{sRsAQ!8F>E?t{6mkX7;PV&@*vUre#(R5F0{uJi`>q}EiQq{j@9}hdKZ&DH z5v}4JrQh08*{4sangvp$Fq8Q!mKtSopv&2Tj?wt}Yhbd{K;e+a!F^ZMLWdL6qH)$R zHrwnB?(7Z2UVs-kZ#w#54joxK{9sToO!WPvgrGM!sS!Gt!O!MKy$I2)|#FJ%hspGM~f*z;jV>t_C$5U0+d#uRT zuZ&X6?_V4Uo6ody0)F5#UoA)rK98wn18+c`YqJEFg3KvX5Jr+IHQ0E|=DkGW`_|u5TK9fGu^l!<3!mPENtRzb2XnPBt!$2zFHk4gDw%63>fH?$@r78Ap4Estjzgiu=EL z&MP^f@aOqPQBsIa{iA_xpyC~?$nSeA9q6`8^Ke;~v))>|YkhLojQ^BDRte^*`cWD zA2K!{Bb-rdz8KP%Ip2~0Q-LJ~-PpJ|zJRiGx+lKSokj#XdhW26sbEr5a*2hg4_%|Q z`7SF%VfK`QT7@gX3b8>F8E6OwED<%{^RE3|fk}J&IyATtI-o6uc$zik%7F=}1wy}nu)8VM>@5^OsbxiMui62J- z=vv%cawT~_pK+-tb;!Ka)k?KHCd8u6>D?igK_7Qbf@^QX`Z}KF5iQtoE1b*E8SIh8 zcr$>$a$;+k#EaOkb?a#w>agf&yu|VH=b;UUO(IG5i0}T3C*MJOz>1}ieHh^COU{nHYaDJZ> zU*0%u`|;0ufKf}gVKXseU3EWlg+|AwJ zb9aKJyz=NgA#|X^gFhuXpi6Uchzy1!Rbz1wAzNgnAxl;1d}rYlamSXn#Vlb;nHj&7 z^%EJdYC)u&5fxT7ufrz6q`|Xiy)Ix&v)O({{syktvr|$!c=xoX;2IprEvlw}X}K>P zTVSusK70Q1M^lovT3Ov$E9#&;nGX7>rl^&EVVP9q*`}5;vQ0M5apnBwm*>eEcrdYm zp_?^QUm6Z<6;Lek-h4$^m5=N!mnjQvh|JtqKptyF2G26o{2b9q2Qu7Nbrfb)IMF~$ zRf=*>SG5b`+-hqfpy8(AjknQ&2b<`~a7OD7)@vlO(DrWysfa^A``usre8pmgT!ib$ zfujay1XDy615kjc_Sz>2oZ1fqliez0$eWPi zxKPlZM51vFrK%2Rg4?jD+8rthZqd~{*PXnyE&P3vF@QBJNE#*Rmi5Vw^XK@c;}t|I zzSCkE{d#YZ`Swg6qd0{5G?_O&Zfb`;w{>eZ>uBz27r@F$(@=OnF5+BUT+;RLrPoYx zQ#Qz1#x$F+CZ_*v1e(?94|dpkjk))^+}gA{gg9*gs#gXN{_B~K^Ll3>&|u_iyj#GY zP*?56R)Dq|Oh;`xZCjqhDR#H=&}7%U%jmF3LR?ZyO_c|nfO~&b#I_^bH8+wB8xu_0 z<91)3RrNLpBl(1CB**kwYegeyBDliD5{xt0I%rN?2sw1~D2k2Y{PU>3pSKkyK%vH| zIp>qU>8{Z);kJGhsesR5>Bo6LI}$2S*MndSo13$hA90ewC1g%NbQ!lEe}JRFa@_5e zC$A)dapozwJU5l_c!jMcl?NnfkiOPIEk2|*JGW#BZ;3t-3cYIknpt-~jvfTwgMg6Q ztk2^SksyUHKiroSKg)+QU`YS!-wFH~7;%kK5sQRYWKe70f3w#^luX-Y0{PyMpr!*8 z9#m_Lp+bb{zt?Eg(_H)(q9PybDNenu&veE#ypQyge{VTIq`MU;{Fz!CA`32cUQ-1I zy1*<_zveA_<;4zZ78Pm5mg{wacg2 zXB})w-q=P{ul1%d*uMNGdGIz+>qlEmsUV+Iy3gqJEMDUOnb!H>atvgsOgk_}s|@%=6#1s^aLN_(M#I+jN@K7;xy;Q*E$jlNx{}HbM|cZY1KyltI!p}=aq4hXqdLbm3d^w(#WzPLj1{08s+p$)Mas!&Vlo+ zqEajNP@CKv?Y-?RLqq0iq}_xkyJvgUP0YeNkg~8IC?P0eQGaT5L)rHg0>%k18n*X2 zXS-&g&UAd{SI;X$V}b`#Jcsw%6`TJVXGm+1kqWnJ)k5r%YTH1)op2 z?Ap0fizLFKNUmJ(WxYImv0qf|*+*;(3!io`EvmNDILNFWk;}XBK=Dq~|B#^+VW6-p z*~1OGc667BMpEV~mrco^A+dVCV@XpCLp!^ygEmhke)I;YF z3ww}To}Cxg^`>Zr;6T$wT;M^Ke0cb3sJWiBMNJLHhJJl zZ{ur?hp0hhxVmL7a+`B%8!qU%>WTuRfQ5l%El?@~zo(SKspvs|na@v&O(Vr81=DK5 zx;?yq1$YXiP?YcA3pnH;g;`52|Ce0l2 z50a=NVsu?K+MQTe%7IyMI91(v6a7WNmQyBnuZS(X>YtuM`C;@udS>-6hA&PH$#Fh@ z*}qOW-=@p|^P}8zNTBJ<#eS`FR$24KUe)n+^dOK8`~HzLDa+N4@^Sn2qr0=_eoW%x z;vVlWm+n4X@}~UrGwH9t{@=U7UvA&Tc3=NJBO{RB(7ONa`rlvwN99vXYK6ZKp50H} z3DR@uth+~0x=2V2;{I7=!YR;jcg(@gO`cPauzp@m904^Los;w zLB5js$^+_eXZKajWZowMu}gps55QB|qkyoXL3w)El-46ZsGRPpv^!_X$-MQ#WyFA6 z*MONeH0@RmGF<7`6fNPXo7Fv3HQOKNQJRG|SwCE3zk;}L^lkn}&Zbd?jT4w{`i(={ zG3aP~fcsB%f3nn9UF&VjePm+h z@AX!W4xJx6wAJ+PRe38%E@tcn2%hE<4sTQPk2PE-(S+*rA z14(x8?Z+OTNqtOOhu>7jNwzPs97vvFXkXT`?_#Qy|bntPUWw+_d zg+cqF+p|yCd9JkWUvO;&Kblxo|d1`N-a*kKWpcp;qH zpP$N7+8eJa-VY>~{k?j(cAY|?Kpi7W^W*-6L%1A~EP7a_k!;I=0lidMmz;d~*&gfy z&fgn73njl(6ZY7)rAi+(%jQZ$1|EE%npy04? z9YA*t0>-Bcn2$X{BkOCwYBQbvfz7lk9I(|c#cM35reuB7MRvijS#UXUkn1b9n?=Xg zBkHcV6W*QD4f067yH&8Oq$33dSzv-liqy51* zGtLN2w7%-o8AOfaYRjWu3*{EARpL2`T9_7_o`k18rJ+RBLC^LU==r6qub}r;G>|Vp z^Ilf{OUCiVS59o$*J7`IhM+IOeJQ&`6ild%(M0|^1gN8QGp52|b2om_(yiO`}V14&CmPWZA za9nCX5?TI~$NDh(`}63Ryr8efJAY#h+p(c)!9z{KMAuhry>%aT8*34WO#XP-w31jZ zvk3;Wc7G4#N51=`Y@!A?Y+s|s3M-dAt!%zJTky=kT*SljSn`=&b$b>BM2xOR8?^C- zqZH%o=5KwC!Uh*$l^>#zYdy|xj=Y`YE@i281?2R$G00YurX#0`%DOMQJpj5`s~c*5 z^%b}{tBdLHOJG`R^qhzkik{GD?+3l!L7&>iwQzXOo=Ti=-e3D|_*Kc6>LL(73Xt6b zs&5V_JLJlyFyS2lBM`J)E$cV<3iKUZGa!H@R$1Bg zV!%;}8vD3z3m^?Z81Z&ld*Z8^DL)cA6O~$dIf2Odq#V2^vEw7Vs!3nmXetsx{;+qI(>NxY+^Um3^3q!pZ-FfEY8^ z`(qPefcTK`L!Ux?fdFdR_>~PdA3o5^u)txr>HFJRy5WN(5pkygXSc{|*G*g!DFlL-h5 zcO`JQr7;-pEuFr@GpH~^rej%8;p$d<5`4Ug9eO89@GFamYP7ud#1?ak%vEBL&~a+_F= zU4ASW?Q8LU$Ut!buA(??QhApH8Jv;Pi?dMssWWp#eBJU7?1 zM)Bxs>Lbk7@(6w2n83O&G20+;vsZ;|w@Wq}7)A0+?VcJpJmJm4r;o^f)h+dVE>2sn zlt>bc+4&p|0#wBF>DXQC{4a27Mx4CIr2_l8{=8P4CjrcAIxg5UdVz_lC^n!B>EoPL z6=2dZr~63!rBRqcoVMDfbU`{$jTi|CBkL(lcGlY4lXG#jlG*Nl!9<+{I0zdEBK&I9 zM~GArahlC`O$)NqBjh15%AwJ~!;#N7n&ZVvZ)&-2{ejAm4eR0Fmay7t{&)b-Co=R& z(CDM{nAe)bl_pZzq@KJI(DXisBq01sD9_i1uD@!2Y(g7uh)XG{kP(cc>bU74c1UND zlyMvT=lTRF-PVp)p7mlOn2u!r0`h%dd7dO>1t#KNwk+QtJ!L)r3lLshzF$P&2OgG~ zv=N>KTXA?3@c$W5pn-va_PeOs$9L0u0Tvaoo>`uk;-05GKAgfQaWRe;KHW6repPEe zHM(fnx+#=;Za)3CoYfWeQK=$M-~$EqzhMdFkUjY@wR(s=6tZc8DMn(I=;>K+U8r zT7tGsE5*%rH0iS-{>pk{fZ2F6XHqlurCKRsSFqmNl&DC8VqJ{7{QT!o?Y6go#kDdT z9Xc)>LZXwIn-ma<`ypFW3PA*o5(6<&Y(@25ya?rO{s*dcw8qUf==gyhWG!x|H%CwV z*YkBWS#E84uOt!j^d;n)Ksxy1blh-8f|~@#vCG#%mWlFkV|5urC}6TG*?!~M!o2v$ z>u+g#|K+I_w-~I>emE#6cE7?S{xNF3ds;=A#I6iiuszxkQLAd&4e?)??9_$8%S8!tY! zh{nc~FOk#RD_Bx#fwrmM7j@nq?n+7shOMfr`j2CbqZDv zZSKfK(LNp!+x}g&k7WF+q4Yvh)RzfI=KK=>ZFqqys+YpdyH$;oEe9ln9{X%mXDwKH z`d1uOFvpK26FddyNr4Alwg{XQp}G}{G;~AFCUHmE?@?yniISWAY?$+k%=QK+SQvgr z^jep-1WIRufo{6n>WY3}<_=n3@}{hp%FRqKEpaAfB3*8TOVF?z>=`-O9&2;7#hbo;;2sHYIX4Yufh>VaB!G%CBW z9#*hc|6=*@0zD38LAU#$A`vSUmHocK=hRDiEAW!f(SYn|5@HSWg|+QxYSI#%TRL zZ=o=9{^jfKb;SKFS(x(1@NgfRKO(`s$!4#@+`1@*%BZBE9TF@}IUbY4&oIzFh;YJ? zaH{7kk(`2H%Gw!Y2Qasu?Q<1a3eH4nkIF<>MXf*tlGG0jt(+liV9t<$Gn6^F%{;}2 z59f8O^*b~?mS2h^@LyY4<#{;BcU1E-hH)h=*wqU#ve(HKUwy_?l}<_ghnn$bqWaUH z07;q;F6J>F0Ii`;O7Oa0sV5=pZhflZ?aSk*E6nFA#3z*E?gvHp;ob1zO2^~nW35n`0G^1Zo0U4jZVyH;+b}Dore!{JH z$4GIFeQ_^AU+1;EL+RZ!!l?B~dYibT0dFK*YSh?$D3H($5GHk~knu-jB@_rJga^J* zoGwPljNt>v0=}S~F6c#(Z|2{VaE1gh2Z5E6Y>%TJp&bkJwv;UHrAAI1b{zX!1gPDt zclDmUtQ5Z(wtV2BSx|#(;`9?v29k8*%ST%lO_`dVgyT7R>_veA>p@OzM+OL|@-e&8uuZD(UXfA{CuK^h=w~9?dw&TmWrO8ZTisx5u z&C!47-q%@?Ih^eLKUbwebP8VY6w1KPk^6-agi$`>j!TaY(+d^sD^KA=vVaS<+q^NK zj4C4S3T3^bG4s!qQW8f&^@Cs%YWOH;GKMGEyD@4hf5X3ovzw?rC3Hey3YLR4*P zZyF35O(mca={w)$Ouv@|5C4*+KF1N+r4RYo|MfpW_(+QaX!kf)bFjP^htv529N@!$ zIkT=KXT2Y9mnlHDBSM!eV+9{FU`qOTt3mzgb59ud zo=zu>@Ki%w@OactvFX)VSm>*|ee*;Mu5xB|Q8nsB)MDC~ICO|iUnJ~8pD37sP`#OW z(K~Q92(aj@sIVtOOSsPOjRUaL-_Fj!6bxWNH89BA!s1ICrhbLu=9D{&iIf0fvP6Ss zolMcS^^=j9V1f+DGAmR$$rumu6H7Lz&VTAw&)@3#^bE3}V3p3pD zAZGLWweB&oCNHn(i?#t-;v990PZgzZ5G~2J?#e$LJ5|P^rFq4!CrJYTXzAxPW&|w! zfiO@7tqHWR38e2AGiQ*kE8GK^M&;_>Z0!?nLUbd?blm83+n8~G z2y|}?PScQBReqMGKQk2%yImaGw193FMEw$Ddjf52Bf_yA6(!wBQbR9DY@P9^5E=9E zgh()}C|{2?D;n!Bn5RDrE;C32PB=p!SHuJ=Vwxw z6qxJzoFKz3LtvtN1TwoN6ZpvBYQX(CRJ=om^G?zg#YijR@|iY7~@bXO$y`~H0x3DsXhg1^+9ji4{wD}Vc#FK9=5Xp1y{vGOH0dD?fY9!pbw~6^nqxd z>%;bapwf)<=+*+e&&}A{Qy^gzigi6S_Cb4J1dPM9%iWoC2*ixWX{bYMpn<57`_ZL; z=m3iCWX|$7ZK*@bmp%PC&W4uj1Mud#jU>S#@c0I*1Z|hl_rCBgF=7D5!f)Da+@G9J znF{CUyor9@uq*Mb1L`3@;(Z% zTZ`gB1X;J8f5exp9(^?RxiCclJ>kH|kmYkoxtEgXD&BD?ig49rbRHwxg8Obch)bm> ztoG+~{k}8kO`!{2cka%MtxxM5bn@5-DR+6eb2`2K1!bjN$LjNcWkF#Cp zMgI#}F2&_bB*kUTgtYvo0Z#J?NQoo|pN1m$HrL7J8uYl?(nW)y@#ilfNpB9Ep!h2U zq0)7xek6zr@uw*G+gf++FFgitia9vp=1>HlY`@!mjVyylnQfsy_jdO!LUM>J^_j-} z8r-VU&hL@XFti{W&eI6rs#!Q*i)<72{6y2W&4)8donIzTFOf{V8djm19G)ST@-e*r&hjcffuH+$eXf^1$!w>VKKhp(eSCE8oBu2|4auI?=;(UHhkW@uV>#@p z9_Q8K+`)Qvj0DXedXKmkIpSt#c z_~d^HfcPNa>5hkU^oC}jB)ggJAO{^CxO9-Px%Gdr1ps9bKYSZD;sqAIsE(M;8mcSV#36;Wl7cH?=`D+^Go@NP>C0D%~(mUO8isr0;V?&9AQ6zOJ!9T4X= zvpV~~b1Sc(>fAf3zM*CO;BMe`%Fs2}A5i8TKU3xrQ}BHnXWEhK2*!&>F? zFNf5tOr`yl?Lxoj1M#!+6!8DB@L_eITdW;$|LC3%+H1OqV6_FWZa4X|#3sFKX6{*Z9hS83)>}GBq#4wN(Np6koZh%B@-C}O*S#3e@kk%33~;RxrB&6!2cmUa zC0YNxe?Ak4pQG9T4n*Hcks22yX423(Mw<;(>uTX;4BE|8~G6;d`9&ID*h}{D|(wYM7jG|4Zu%X zHWO;xz*M+%gOoc01-LLXsSdGZACFA^>gP3A#A|> zSA{-IU^grvgm*s6LR}-WCcY1pZ`M@%buMmtUG<$^P$J*Qw#ARS$fAGL+t+OGKBBMC`Y#IqChP9<%{6|# z`_Ujy7QAZM7i@BfWx9VmBizVtsN4Z8XO+5A1*|;W$w)BHs*=s1HA0WLSr~E|7U8=Z zPFwM5%_pXrqv~c;&hQB4$aGru%5(UKhJ3lW)_%*J9l=*klH05A%wBt}j6~7#;aiMD zzy7lsk^>wyEV=;HO22hm!KN$Z{oUug<;PneyNf;T1&0wKnQ{DSeIKEJt0V2bE`4;> z`@Y>FvPfv({A#9GIQZ%8xh~%VL9zhC*tApn{is-42n~SpBdRx@{vxxvB9H?kw6!T+ zn_npJuSB14{%Ji24D#EV-qiv&FQ&}1e1`K2pQoYB;Z4OM2i)$dutdOe1!Z1!Gpri3 zdAue+{nlINXf+k&i=%vTA%Y5T|I}ynqbnZSgWrtA%1Ke~f@>>;-uRXgj#@m&r(|wq z>7v5w>+YUV-c%u@NjZzEfDMax*Db&YE?N*!$^$3yQnaDbl+_`*hn)eid>b%|a#p3NbDG@0xsBKEzYaDb*JtBeF*_Lxt2|eP zf@+pD6%pd{aQOyGxh7|LL(Te2(F9a?!mULOYO*UT-q;yG@#&EwERYjF(#GW{PRIe# zCv;EEjI4ONV8&`@6 zKI@livK7R6&bVQV%-FI@hGSQ}&(3Kg1UT)*$tULg>do_V%%CYO9H%)0B zyqXoEewgq0RGkcNxy+)Wq)T%5utnp(cN+@lnVk+vNEe@uDHWEJ7J#zi7Gl0j!tE05 zwPnneKZm)uK+cEhv-&t(zCkyd`&iq(Ac2}$a+WVWgM|K7-7GNLF02ntr}d2?uq)i*A746PfJPak4)XZN3)%1gS)2echw-)Jj z^!~-e7#ir}Uc-gs?O1O@89qhXM4m?*?zQR#;*B;;9(Rb6>ZQP`MZR}?4K;5LYIwdw z*ci~*p_XfIz&kdI*(mjetEvNDe!8Wmv8{$l5YM*96THFTSZc*G(Kg! zEbk#h=OL*Z{SH;a=2NALtzq9^pecfsEt#HVs0VrK6MqTq%caDXO6iWXmilIGBNBMi zbnX3uj^(!t9H20C19;L{KRuwtv(Es;RC^!tgUH#!kpXY5G$I)WoI<}P?+R9o*;=(E z0NxJm0u_J1h$`1J-DF0}#^-ozkz4NSFKMLBr{txrHtZ!n#XflqvzZqaNs&LkcK=xi zOV$e%`!1J}H>6CTxQJ;sT$0|2J1iBY&7ma zN7BxHXMCCAWWK^xRSmY$n*&S3kyR8kLO-UUi0R72HasTDk1dR-RWt=ln!1O5&y$DH z8F4^%88CJ9h6`jJBz0{@`Rbe^dX{zV!0i%@JmrB+2S7y&yhFAREFK`o`ewjejEjgd z0!fxQMII1`d=X{=n4zYHI0JL^O={m8Oyp8d8F!hzjWU3U12l%xD^qp3dWGnQk3_+96@+7XT$tW%(wSFBu59)dTDdfRj~!W3Hroj-~;Z3+k)I z-JtbX9SF>1(f$minFi-jg*oSQeH1L6kcKB#pVoFfGm~MG(mMCk=gD*R7oY8B_1biW ztfMg?HBTtsacW=sO1_K7n9f~pS6bE1bEgjEQ>H&)zgkFXt{9K+y>*PkhNLJ;18kxg zICX9hBkt{{{Iqu{DR5+_T_Mih71bf3vL4ag+eoZBZ^MA_tK-$R0g0F&vRY!(LY+04 zmaAb2?1o`vii9{R8(-%&;)bm|N~w43XIC+G;{GrHc1>=j$yoT`#Of(=L{sWTHW4!Q zODc<8IYwkj^nPsX)qXc$cN{H66)7TJ?iP8b#ClbR@3Lui!@P)G<{X9*2{ol}7bD-w zIuh{H)$doJAtuUEeJ4;Gr`+7{m{G!B+aB5Xc;dNZ3UJig%n~##7Sd z3l2PT?~^kr7S~qbK17Q%#U01+)3%C9n>t;J!&MQ&N_EIO=|4yGjeJw4ldl>g6h|>a z+DIM}tyx^G9orIGRH1Bk%gK=W5m~c3c8)3YJZ86M@efR*w#Qj=ZT?!^u&aBY?_#JZ z<}DwZEwV*RBA}1oACR+;S`N`*d7O1{X3Fs0%=`=c#8nwTyVuOo-aO$$TH)Y`tpw5; zC<+26>4eQsx}NhV{F0`{ZVn?%^CiZ6C5-fSUedapWAoeEe>={#4D*SPW!}_fX@yP> z*k?i$eM2o+ChAna9R&&L7yt3E`j+Y?(TY8$154mo?bkZ-?_~7t3vVEk{Kgyv%qpfn zMp`PN_!32qijvJ`OmMf+M!gk+QYwjuzU}nn>3JMk>Ij*&pLBY-YWWCh9zIxP$oTmq zFhW)Y>0K_WqJ*(8w!|@_tEjRcl3yGS0xUEycU3TEIPx!lxa;e{qfS&rW=6TAztpeS z(WPQI2MG>c?(dbxJv7U8>Pwxo=+Ad9 z;rFsNxU*9Jp7913P=KrtA?-MYC@0hHl!~!0KY^UJl|UqT;`1+mu4SZ8G33`~eDn2C z*R3Klnx!x_Ow3Ti6MlxZ#G&FIr!&qypX(K7!7SN&IK~w?DBFRR?KtpXAvvz}JD*&E zCYn3(!aDI#knZ52l^U*{cs`3JpywQ!Nk6FdXU@cYxdlv8o|!EY`?ujw9mKOmn5S4o z#n_255_M`jFXiAWwA2kh$n*NHFJkh^Q*W6h8=hR#-Y#qjln;W1>Zj#~*}e~w-7CJs zWb_V2)^bg5p}N9-H^c~X!hRDVtcu#L;gk)-(*1Fc|G#g7sk11XQ>+5)ENj zjm|`M{Y)G2^5@&AFw-3>g%)ho!dEUa2U|(q)riXYHRYetj43v(B1*7DAbFIg>hT7g zF@L0R!V9%Qf^LK~Od2J6!m^ZKChrxyixtrhpJu}nqCR|?mf!FkYoOFKRj&+H$_nKE4ilR5W-%VC?&Fb~T&EVs42k#>S9 z9IWY|KpV_tq|A*Zr+nqi$$9+`uo{QVp3M1R#f1$cl(6xU=9v*C1&6crxkz! zl1WoK%;oFzD9gr##i8ib_g8uvz;9>ah((qkkm+^TydZD5`C_;v`~SX5XXGn<$Eg7z zv%p}0|91d`Q2uOz0&NO{m;gI5GI-7?7|{dGOy!#^DakaRF&zSA_7!w|^2RSTIbEUl zAf0q`j|(GOni*ZrnCFEI%tl0AJAaOVfF=bU-{TfYm%iSl-zn|dV-dg>D`uagk_55H zYG}53a{j2mB*}WGz*Yo^Kui?ISt@I%`3-%;4rx?ge4!5XQx>os)?4mP?V5XSs{>N1 zV5Q0OTrt;Z5~KVvnKKOSH_BT6o#%%av^4KPCLsNe<>cQ$ZtkNGRH^} zgpo6#Jj*YfufN@&Qq3E-{HTZn}eK zZf!17zU4d5a4LyF$a8=B&4f=DxRRy$%9S2P73{Tg2U|D4>+@LH(q+RI{B460zY3Gf zFL5#EqP}oQv_pZ8A9K-a4kut~k*)v8j2^T;_=#}aO8WL(tWW!z=PV4rr8`E-1I|lC3zuKc4O{ zLyw=rDwb`?%Z>ooKdV}KiO9dw-KaEAINv zqX%6q*()L=jf%;cng1DQ9@+mfeEZ@#V6@f85Z3P=ugX`*TnEu?VeG;*KpaVEK-S`E zmH5eV;LKr>d*BLkc1)ofvC--4$3=|A9UUz<)1A0!CGB+ku;0|@wd${UrlW&(364Tw zr5`kH`1WfJ-KX#!rYNO=@7z-RSH6XsctHcblI88+K{^B?Wcho;;DTDe!d+7%%buxM zTN3(?QLTc*(A|ykSemc$eA_ZrF4)s?7}-r8Vd9M0Sq#5o;NhtzpUFIjsSF&L$xio< z8yw7M+qBP@kdOX%6FO=&16WIFzmYwo!?Nv942v`t;A)&Nke?QS$eEJQ>_w~jP7D2P zse4_7>F}1oouW-i>*^{o#&GdukF+4=IR{b}zN;#o>lt)|{X{M(Ecy19anqsBDxiPr zd5zvZ9yo&dn%2)!XQBXbi4+?k)Gg^$*Y6E$<_1M_e9uO}&$drN#oQ2k_06cq-;V`z z9fU7Z$r=+qh@fFzR9jHYVlZF$bHm9qjm2`|ok^Kq)sN@Tz(=3OKlp!9uaUiVl_gzn zuoN1UyY+luEAGI?;<0wQ>bNe3q|;)0B(biF=8+%&qLqLm2t3#w2wNQCWzRhAy9cdFwrHIvVTht|P+t@f=XB|I;^2 zC<&7Abe^ovfP5FK1^V(cX@K)XZpY|=u9OKE#edp*EO_+83krhLfpUVy>tI|lsK+<# z6Z}s6;@M}AF48x5qOk(hj)dqT5~C|&Vl^(Qg__>dl%_k3gKJa^cTQAvCe8R2vAEJF zubh4@NTm!|m41I&qcY4)MZMsDx?m)+fj3FVHi$O?l@OK%L`>{i8jPEzyBVQ0MkMSf zGy}ghB<}V1J)?a6mFL}G-ur*6J`p14{iOCvpv6Qum{KG6$5iCPr{YmGP_6{NhSw_% zaLA=YR~=#HihO0+HnjW{^>WQ z+}m7D-HQjyAp_zVgx8%{tMXD2%LE{Q z8f5AMiegofO{H-<)0Ke2E#XvM=Ec_Zf<_{!4VU{M5iwDSds!VMJ3#0(X~3azRLn}; zCxslIEE#ZZ4R9nIr)b9)*DtN5<5kK}G!ow$K3-SV%c_G# zo_31Sw_jgQ*zsj~VlpEtS6JvwLN;~go8=DNjRVGoUF}5~mf_;N)dF)E(5Y)Z9YceO z(%fZ;Gpt}xly0V3DpC2yHv*%`lk8ycxV^%y8Vt1=~bj`5OYEi!lX*fXAb&``dR>0}70ajOPK%*vGx1x;C@qvlL~IJ|bBt)DG$ z0?Et3c6Ep<=9|6OHtnEgVGC%=-%+5($lTfCA0#n+@;V!%Fl0@f|Zq=Ife zk}8u9V}I`LVN+)MBXk=aP+QOspQ#eoA>5di7UY_hYYP=gWmwCP-z;8 zUrFJQ2Ioh4$f%^xkfRActYpvj03YW>);|(C7PtjrY?Oh_Ie7;J#(%P9EH>QZ-_!{H zFiQPWQ?LTK?f!hj&w3{TVF77O7g`P{_QnN@h=D5$MRPx(Z1eAVbj39OoWygi$e?0K zd_jV8gY73*vR5O33A*~(h;C`Qu)tQ2bf-wZ{OqB|l8(ZY7(H`F3kYQSfGFk1m?aQ? zAoLhH(Mk}X|NO1yaIHygmRrw!Cr@3qH{jQ`w?|aN9?0%C zRknS^w(P3@+Pj1GnX#c~NA1k*D*O!f4d>aRMR7V< z=GKqc_oxH%qWGJZ90znDnDd=7Se1<@>?EV_b-{Epx}VNZVnjux3XnmXfi5%f_Bvfd z0&1|C-wH-yIOeX{!73LNfkFqn`TJra8by&HynJ7N06vwLAra zr_b{!muvRp9BC0@)LHXQ;(XkEms^oAj`4|iPfKxB5}2nMV~Jj3lsJ*WLu7Am9$}sW6L}{g7QerqVGob*c$9R z^Er|DW_?#@YtF_8Gpc^Xl42TXxX4(MQI}&dsX2DFlz6dZc#5BL=(B$&J2u25Y)*Xz>nnBWX75e>O7`pH+G%3i+q!T0R3%9Yo3Py04S0p z*NORJevD+QpY|qY#^g+;=w{Mso21+Q1jChSUpVgw4}X(2Zm( z(o+m-e_vs1chFw4(@$*{pMrL4UHjmi91QZ^x3mj;hN_u;FsToU>W4rg4{kHly}ul)J%@{pSF>=Ey*gYA6VQ48TvEYTl|y;6y%~&n zV)Spfk(4jo{DfoAA&vW+q`FI{=Gw9u5PtZrm(?J0bq|Q~z_uo53VZ!8Onuj$4!P>T zV!A;_E^N1=1@lSD5}vE&4e~`1KJv5Bmwqa4@;$MrD?-RVHGf`E)SmJya%{Njl*L5< z6pssi`)1R)P%dt@tFu5%P9&?>JC-2?dxKY{9Ty=;hr%>nLX48AD{?-1&HFk7yU)+N zmw&MyEF0ACr0TaeK&A1UAU9Saf)=mu)j6z7W`M5!0hO!&}=jX^d zUqzf&EQmEezLM-q$e%8Vap}%`r&KaX@yxjm+YSU}j0-1*$_GOfg}02}AGMITLMjL_ zr9Hu9`b9#?mZrnXVVNu+WNbc23ZZ5+nLT0$p7d*gWjQvSxhJ%p@4;6bgdo`FC6pV{ z>lNRtLZMa8Q&`5{JJx^?-y;{!w);2bOx>J*0WmE3#1F9cHmKCaT+4W zno4*BSi7ZsgyMg{q=fsEbc?9t>eoLF*ZuwdpI%9oz-HmTgx;#B?P;;To7vrXDYx(Y z@Qg{Q>d((wXWo=(Q{Mrsugxfn%|gJjE@U(^7OP`PF(@j3$;ez65GpbxFSkB%tY|8B z46^peM6xWtvo1v-$QFrDv_i=^c{SUPMyfP6)07DSHO4q;iY_(g?8|TBth)P7B%s?k zBH|ruq*zUv>+`sGPBF`|6C)pN}F_>_4KE~y2Kjqw`NH^M}GnR+Yz z8ebb<3eFyd4Y2Qz#85csHl=x<1noCw`Y<@pE}{)HQ1l%mu#nK&!9;MPiVg>}@w_My zl??S{gc<7&A`1e36X~h{?+w|VI?cQkY~7M%Lj=_o9i>+*K4CUJ1DLsVvp-fZTpiLe z@LwUZ&-Z`ETVB|&B_)M8s|7VE*wy%LGf#1+73aYaq+fV!@#6HN)2Sc>TBwC!N0pce--}74K<;pL2uYvu!$N+` zQbw`G-WJII(yP+TDkO>Y*r`GFSCkFL`}BPTu(Jnx&^eqd#S9 zU=fpJK|E&@;}j-NK*Bp~p-n%{$9OvEECj3R+=G4OgV(5z8ZRDtu095P4tKIweS{0a zR>qhYH}{qYzl-4!+x*ODUm0l33E#VA0) zN+r}@3W}W8upHP1-t%p~9U|!@hHr;Sr3;E7Pzs>zbXN=pU<&|)YIAoVMc_e5f z)knU8=&^MVS1;@1n_s#ix&z3ISKQMhJU)j*emgEO-RCa6wqdC~*S#Q$*1yK~?e~KX z<*GfVBh_e(tA_gy%^(es%Kvt(X|wmGiw_Yfwvg#bjkanRF~T0B-@eDk>_Ggr>!8#`+( z(An(}^RbxIVB0PrVigLI-_U8v=K5-SOF)O9l984)!Ir9hQe@(M%El^}968PNc-v#G zQV8_U!pKedzRX-k%#JAr{+QAG6YoyA-VHM#(zZoAiCilG{;JA%z$jyKKCkJ?XEQuU8-i0^X$|_9LpK=)8^Kg@@sM|??Wqn#7tfzjtZfc zy5l0s&O-JvYqn_%^6b$5v7B_NJ+KU&;*! zc0S?^5otnQI(9DwQ1}g}s$YWscxR%R4T1^sulFvIfECNQB1QP}4~9fWCQEvf!~oP7 zK$54#XV{5{4OH#gl>Q&ikk0~s@wswfaVxx(&|dDxAOE?g{sS%3P8>7CXlj2Pt5|aW zq7xgWeo^Z!BuOW?*X>b!uC-?14>mWq?)vqP9B}e2V{%3*c>I~YZl2UiFOZi!{A8#)V zBrPkcc(+J+v1F^Ngz&^E~5xp8fqdM8$V3M^{2ax3H5q!dRiqBqeadEXK zKxyGM(pe7vVO8;8wZ(=`kS`)3MESeK!ymin@iiWE%_5l}ghLWOIF49dChX4~Lnp6? zw*{uZ-B%dcEqSiItz*t!)s}bOW^&;@_GF-NwfAEZ*k!VRy}SJLev_a0<1L-tsy21?@N|TXlmtfI5mY!IG+A$5EQj6)5Ky zrm_6&jG9-B-6C78jfw|x8FuE36jfkkqkeRVU)D!u9aEN$X}1UVXYAT;`^c2Ijk4|Z zxa+Dva!f%Jehlr>^LeIA~zleU;7)Q5nQ+*y;N|u-QM) zElfoSnIJ|zR|1^qQ2ac$n;lKtWpUmNGkZ|+3wBs1^aT+LA!3oa{uq}G*HP-uF8^$U z3^$%U$LFqRyK-XOZwlvedkAQ#KZ;Lw*B;-sk{5*RBP~m#? zlt3+cl|3`n#4f!uR3eT^Xb;#}h~1C^hXzaRFC7;MfuFpSogQ-dV5yckZ)bjN(vlll zRsLM+)l(9ubJ3$m_5S_pz>yl(nZRe;jM~5F!6gNrjzGIgmYsV(ejE)rh}gJtPiXK5IOVPq!p6VUuBcG}$!;Juib;s3tvsSgCI(=uu z7GYn^ZxSDeF`^Vqiq|SBr=ts+t=OL_OJFFjZv4Q+OSq;xWF17Yta-~$WFDi zE=)bGMnzX>XPGV~;1oqxJl42o?%)3rM3nppq+ed}$7Rb;RT zuFDUY+`isgviWPl6WD0a-S4L1+R~rquU+k<);g0O?`9D$#T~|v#XI{krzl1_j@IW# zPN8OzgOG`xV4SZ8DB-DGLD|b2by=w&WWpNE<&*FqAXW}u8myz#>DK2;fW*!2_!rUg)Ca_;3-@)dF&5&&;`*L-(J#Nm+39YPbS7!} zRwQASenO$TF%OWWJ31OuwE{>ERYWeG7LJ8Rs}d+j{~Yn#u-(En(zlhv5^xKPW23;1 zyNh6W?6@nLbEX82i9&!mDUgFw;%k?2tge}2FV;`!M5m%zN?MueSlJlU{mtA}{n^YP zFeAksTG^E7<}Q*cmQU@!|`HSrZzs%K?3&%`Ky$$h(nrztNkBzW6)vjgiuS)GVKJ3qmbUXijY0P3=Vj&*q0erc}^O~m(e)@|-anF)LM2Ho&xFZQYThrMz zI!10IG^{*C{T3nNFwfT>gJo_F!R1d=K-K0Mri4_+RcJ7Na5r^jZ?rCiJi&Wg& z1Ss4lIY_VZPyK?E#iJWFAH3gR0}XuKyG}{I5k$&J1*_}fnpPt~>4@@k_D!~FRzk=3 z^U1z@k`rZXPia>~8FDFu8PHzC4Y%7W=gC79+iThb1~NyyNB*iZHlm~b`}i%r;4a<_ zPb}%bDlzW(-gmt|r0@(Ea)3*H`xn!t=~;KYX#!*T(ST;V{k{d-5z|)W__vP01b4Cn z))dc}_59~bbLZU|3Lr|-;bg}tC+)nD&XZT+XM`KVV;Os>FA;Wr_y|O+RH-)Wv_Me> zV4??zUMaW$q;^x`SCk_ z0ZG`hLAx&1a%7wc^oZbhiX{9Qmq;Gilh`{BFMR4tPknhu8TuCDf_WqajiDCv=4g!a zATfMU*s^M5BmVv^*4d9_^a{|9>1W381IU;XVT?<=h;w`1ZJK@d!I^QM4IdjeK_oL+&m zurH5#&DMZ7A|V1kO5sb9*E4^871|YnDM5{4lB~(%9N)}p$FgyfsH^{5H>m`#cJ62@ z1k+0af#TLE!%lnGC@8uNz!!C8Mzj6j{BukF99roK5Nv;-AB8D-B3jL_7N%Ku=|7(9 z#|S^XT^Zl8O7{0xtPOrx%Y2X2rHiR@*kW9oI$XeC9Z4BfcME@Q zRy)o$3^syc^Jdb{nC#{Z+v77UeqLYqr3Q+Tw!C2%WRJGImf_=?Mu7TJOJ#dD^E^6( z=Lh7_4)egXF>j`Q4F}(2r}7cF?tgs>@{IrHG;*fLMbS}6*4B_(p4_mku5qQOz3N~* zi-0$;g5-Glro+5iFbXAjyx|*P6d@_=GcZk-r3(oYSOC;7Kr-givi|#Ar;6{))joQo zS&xGVQ4NF8Yqc{hfCWs#K^JWmpo4tZG=K`r3lrP8)^sbwD)$8f{ytp`>yikjWRYx| z)YUXdjR@r%uk^p;xo2hIJg?omS+!>Oeza8nnso}AHh6qkpOqHwWG{RrYavG1;@5e|^{ABzT+m1go*gx<6*Go?(x1Z4oUcyFx0i0(xQa*d6-e|I)Pt@tV zF19;=hdcd;4gFP7EO+c^a-r}%>6q0YSl(}!E*cs!GS~33u8{sQp`%?|X`)H_`~eS} zCD-i_`e<$>N#i3XoPz6ASU)U2of321bxh7VPfUMi;stshM%aV+!aQyobp8ig(moj; zXEL5oUoAzI+H>lyzseoaxoG8#e(qmIu>JB%uw@eXm{V3HAZazNdZ-gO6dsEWGbI-C zPUgD93vcVaJM!QPxv29B&$_D-lw|R9iY+#r$CLvoRlrDvVg}97)vFBd$yTUDJQ^v` zQ8s6MZf^7QLijzbyi5vxM`*0|64{g#PXv9KDANsTX@M_em+ z%~@S_o^xH9!X26r9#mVZvt~zK+uPvoCm_yS(m~(E5kIbv?bXh(V)Wm$ua$*EO|yPF zJJoBCY;;p4+>=Z|Q|f-tt~*@MK-Tp-etP*zqWR6Jx%1>N@s(G2Id3m%^*JgNjnCLO z$8P_th8zK=K-_k$R|6yQERK8G!!gAp&cDawAAS95HRAY5ircv4&LRv*c~|M!++I|) zo(wEq0c&6IBq|D`l|32_5yl5hqFj3gmi+#IX)oOS08Ti3{BYSpkqmKut(Yko_5ln- zB7!*LECG%XtJ)*(gb#q+h1|yVC&`pI#PF;px$Pyz!%+wV$ff->_hfql#flr@G)$k0@slfkcU zjk2|uiR#-a`~UHD)=^QeT^k>|8|iKk2c-mt4iTg~W&j1Gk?uxP>5>?_M5Jp#5RP<9 zigXX15)yvTc+UI%=UU8Kt~Jlx&%O7xuj{voIDfvTP!d+w*Cg%n|M8u51(EoCe3NSv z5L;OEiPG*;mC2Gh!e@foTt$#b`n zogJS_*)&7^M!vSyjqY1G=7&dk(TM&T4qRLan2*d)a9}WJufe52WXI>FRQu2Q0&iQF zxcb?hpEe5O_h(99-`VDTa{Qh<8>zA7b9waqezB3{xXrCMgq}Fp5h33n)s68DHm4aN z?a!a5Q0ESQnBv~mT)Vfi=LQ!@9s9RUUKIU3knK@}D#s)yf=%vBf3 z#S)5G(CeOe0|nA9D~m@#Pdm;aUnxMxV}EYPuBwiHgC+Nj$NsqtT)tcd;u2Bfr4@X) zQ<`^_s9(ZgB@>lNlSRZcUDQOa#=Qw(@Az}`mDv#L+Ouj_sZbq!w}%Eo{aU1f|84E+ zWW6kq2pmz@mM^4=^GGiLtIMUE^xCscDKzIkv^3%YwX`GKlEP@izBG-_=9!YLD}Uk|1{N!YY};Rg+cmgR&As;kbxUh#5=;_cUBe*AqW zkT<}wf10$3SM2C7x3gXLai>a|bntE7o`9~7(q;5gMqkKUz%P-nATi&Ld(z4}wpr>$ zg^YI*!DSPihMjc|(qQ`dxxMcoKJ~2+yZ-WrA~ti3^He?l&y}1kC>EP_(KO50@GEd6 zjvH8JZB|l-XkQ023ne(1Nq=n*MAF=dWxR7j`WSi-eIu9AERxd|I>>m0elG~&!}5}o zl^$K{3;K%3i}N!109&G*zU;Ei;9bU7SM9lMf%glCZ@u|U46u>AS-X>3_xVS3u$%uH za*gUBAPdIGt&!82W@v^00UKPBUx0VogXf0KB1`R#fjHT82sfx@Tk0sr{5s8C4mRrp z{AmWVg?g4Jb7MhN%fCM_+jml+;77N>nFNDY0N~Vj2?2)&>6^JRHb6=_u+xP6C#BGG znfGya1kaf#k0^lTaLj(cf>`!HNb;hU#(S8D&Oq`@P-v8#o<-}BB(%_ps2J%3xs0hx z_1gU@mg5HV(np?(9X(MGAJcyzZK#he8CX@}5@`JD#wUJ9oHm|ezVkeX(E7W@QF@?m z)#aaqgH=DGO51qGK=XG^N^QYQYyoQ|;};4~s5ciA4X`w&%WDWlPkzn8_83TG+%ijB z6$N7o<&H76>3;Or!`)a7#$K6(Lwzl!KBL0}>f};iR5?3$AT+FrFhyaZCqp4Kb^bM~ zF^eC3>9CWa2n|u6y0h(l5m&?1yEkL#noW^GHdRH0!&t74q(bMLlY-B!%x6DJyiXTt zHELS=&lxDBz^$3vjf(0y0@)~_I9V&V*khL*Ov#;#{~p^zH*1 zQdem3-LFsl!H<3}=xOs)oB6ET$y_GN&%wrNAF*YwEq?u2+*fx5{*r zYNTcP?mgzR9dhTAI}E(&K#BrW^dVvD2HSVA$KqlS2GcPJRmcPb*qm?_D^W?C^6#l&{&T|I2R{n15efphYfqPa*g-4v z9S8GNTQ@(e?@SnEf*4Q~9#njmLCTL3bexnBfEj|W4qgP%M?GKf_r9(bG2iikTakq# z=9@Jr*aaTSec?K({uDlQ2G&Il#2T*5zh0Y{?sP?ZLkef@8T_MHNy;z_eJ)5Wm~f}V zTZ3v|ksR>3K-)`mSorE68pY&1I($EeO_+LWHzWMxdo}NPwnC)wBul89@?!CeUm%ML z*6C|I`@s{9DZc7hv*3Bg!w?vwS;uEanQ{lHdAgXnjY@&!%p$XP#e@W;tatakcU5iP z@dCXEZ(q;D!LeVMDIBn!eWQMO*-waL|R$GdD=X;isgj$cmtpO zGPF!zVI%`x(hx_1ue~9(e|$l@W@AXbPL3<%z-R4j{;YNDRIXf~C1nqanY=%mSv4VU zn8~;-O(ls)x9Vawa}(v7?Z=i8t*pBw*_32VSFn9x)ZkbNr|?Y7DfP6Gh|oIy_b}|b%vAyS-n}YNXNxrRo*=@6x@K7 z@97G_q4GXzL9xJ=EI})g^v+^E4^3bR!ME!t-ocmNKI`<$NJ7=GpHbE|<4;{xs&S(M zb<76Yl^9xJL!4H@Hn5(A{Nl56lj%iAzE>%Edd;8RijbCK(QHw}UX=@iLcFeFf@zg! zXpi9sJT*D-SRsn4Q(7*uisITax!EBT+k*fr`b6O7riEw7B_&cb7>M|`IFweUG3eBn zc73J9s!Cv6&|x?@eBmXeqg{mlyTr>wMrfMWPCK}sC zt*Fl{ojg0om89x=hEVRMkx^{TB}?T&oZOsoJ1ko)z*RBCpmEy>o7o)XVmqmN%V9n@ zPlE{J+Sh4golObc|Cl;Ygve|0ABfZlSSoPj_9p@#Z%D|<7_{a3*g%qrl%OCyBxta1 zLUKvl`ThEUcU8DO?S?TH`gLc@L$RDU^sQXW*9u6Vec|3ql`u<^T`wD62O^cDEwT4pG31=Oy#vLc?1hd;jwCH?N^v(w(zA506^_T0I)jGdYZVB5SA8l%NqFPZWS$W({AyB{Wt65fowViC4cSLjV$7|*0M30dhU`cF> znJs2f+m*7{Se^QYanE&8h8S=o#Ux;*x53lJ;SA$;?|GERaAct?c8SQe4#s*%^rJJg;Pd_@`ZoRqZ z3c9cfp4o3Z9en7DIwq)E45;!|zZ`m2n~tfBJq9Mt&0jVj`K(doMWdR!-oL<6;KKjr z9nj~!0;nC|oSLdoBPod!9IS$QdyL1|TBVbW`Ao>SUULn`U(by7(9zpv?eXc#>iF|X zxCukXM_KbRaD;f1l*vk6-#gtYU8`cI;#y5Py+a2TD>5o!o1iVqs2)ZO_C1f04+nRE z!_@0bpBz?%b=645y6Eb^EM@(!F=;U)Y&%c6%|$-15+{$YQq1Hsrm2fDgU_oSjV=-b zgPE0W>CHY*1T3WEEck>U8l8ToZEAa^6DT6AWPY^C77|GQi08rPQ&X0?&q91J^r^n2 z)#aL%>mK?YP~rw;W~7#W-OG*-G>(9o-MhFgTBg8t(kV~GwJe3w*a+BK2a)^N=?J(% z5&_qoGq>~%)?sf8yw?hnMC0SO`FO6{i96vDHEG>RG{MxdAkzBfBGA_0_ZL_m>|Fp# z_*^^}y=+hXZ8__l#>epV(|@b(K#{$@j>ElYkeq-ljW&Bc!<8%4@Bhn5+?#HI{I>k7 zcWm4JD97L59~AQW^XDaBXT&Dek!zKuM#ih9xE80Ai{`J4Z-Q^;m6@59$aa6~C%D>6 zJPz<1aWJcIQj%Q7(=?ig%GrF~$Dw8AG@*Lz{Lr4Rdt60bxb!6`RwlL7V1^=GTXHsP z1w-n1JHR>LFbs>ws8Ky%xee}yuDQ<)PFsJlFGVe0YRmj*&7E@p&WpivMwsVk6E%z3 zV~};c<$MZ{JkyJSvn2K(@s>H`d&PSd^HhoCF+nm8bj5}4!QaK)UZ1!%C@vG2br{tz zaN~Dt(7bp5SU5Ja$w7-w0|qJOF(N)7gX;X9AUU{_w0&8PqqQa8(usN``)BQ!*wF$h zB+n2XjwkU+LmPZO?gPKBmG+l6#~Hq47fNmO(c!Z*^JUWOzOrGq%(LNt3}rJnm^6xt zs}9Hvr@*)}G=rOVh_tedd?5Akm%jhQ8g_6g#}Y)cA9DH)T^a59zYl>izWm#~m0%a+ zkxyU59p(L9k3bL^$fXO58l<)92YmOV3uR-#8>=0$(_-q3zyjEv+sBWVPahSm9@J?t(n!Nxdmcp3Xa%8TUQr5bU>30X)mR*SIaqP+j^is^haZx|%#=xToMzf* z=Y3+*h=On{LHKkV+HdWWd9MC}Yiog`pwIN^`sQkhL~WPWRbJH<$2Rq7z%HR00sNkW z?Bkxgu=P?^IYtO*u@Z)>mWlBWqyxr0Oxk{Zs{wmxlY#Bh7*x*w)aak8u3`3)P>7{?ujSA+YOa{ofKLFw9DS+5R z2g>Av9SX#<7*Bq>!=ZRAXFB#=PrsqABr*LZ@0rCBDf4 zzHD}+;^IL|3O4eeZeB?2$~fTdqE*#vN*9jXNmL#M=sCJXe$L5!SJ@CdAH;`)4M7L% zP~=qm8|7*UHG1MiOG7db`j3S#m``4ogf86a)w_p|q<}v3!j7BazKY;S^{??|n$f1T zR$5?gWst=a0peuj87pXW@2w59je<1zu%fQ7)q@Xh3$&2jkayrWcr&P}uXn zDm%i*rmc~o?k$6x`ysC6I4|1CC7KNUJFK@oLn{(*{u7KS(MV4+ahM|;s;13=6M;<# zyp--3QBC}>3ta@G93SW^l=%t`fZJAgW-pzWVqKjBggrdav4YIGLi>TtF@{VCiZ|^u znZ5LOTjtModmu{mIjIJWBUiv}^m@HP0`52FzvTXNO#E3HX5Jy7F|5o2G!x(<{hBpr z28y#Vp0=1zhWCl3?KtTX`$@=Rh%LkMYbn-D&qFrb&Jf~QE#FLn=M0+3OjayUN7TZ( z>D(n%2yInBj@)>ov&VQ^o9^?K&^M)!1#M%~xDFwFt;D_GcY%!^Vg|4iqw8h8Z>gNj>5S_sdmXrK%N?YN>nut;uGV&-a6Eto@6FA2==YrA-{K&`dX?bH`70=4g8cl_n$&)} zPTG)o`UhY(Y;a8U)Z!+W$@?_9{6l08#Fskv?;8v*Ep_BO_D%C{N^=#3bE)e1ZNIRi z;f)Tuos_wwFgq`#Mgswxqsy{RP*mKLC;-fNb+`N{P!gDE^q>HWpiUH-=5KwF%+Up) z&W4x7g8+ITjd$Dp;@|!Tg^W3_w2>kR8T9k}ISI6UKBMlr?#Nj`(VfoY9pv|-@B`dF zWPcL7)Sih};tR4Ne-jsRyGB>SOzXRR*G@)hh71BusZ?vl-Lxe%F2x)@q>C#?g|IN| zEa?$6Lr8fX=w4*|ycj-RR&K;E$Ua4xnz6UJRjR)&x)Mdd)>#9d86e#NW5F|#2EKEN z{rr6=><*si3|ci27F3>_*}b)Rn$>e6Zpt(Q>MzFc*j&39@3V50bg}bVkkS*^fMD>? zf~Dt|D1+2@o8ITfH}V6Xqk2p|Qri?EOP*U)77W=tQ*GE@k8UB$%@YBir{|p2jNx}# z-?9qEUHy(G1oJI3HV_T`ISV*(fqOIs z2z6}xci!XpjLsq_cNiZlcS@fym_~mK}VOz{s2y}Oj2|Fz))UQn97Q64x}nY zTKfmN4T=rxVZU%08mx81eFX`?ZPKc_XaZ}WMTDo^M77zzreks1Ljd{%G}Zd`KJai) zivZE5r3A>bOdN6&7ljZ5e|M8gQGU?3b?dFJOX>7!i>;50GL>yp`z-|_|E59u15Wt| zzjGL7KGaDE2Fo6Do5lAZmK^xig=)&PsDBf|h%Us9sH6nqPK%oHV?V&b=byXojcL%e zz!|BZrVd%a6>`T`L*O)bYZ}BxTa?0fJsKHWRl%>h6}!3nTE-It+P!f7i@TFe$jR)G z>J~JwD=|HU8%!^T5N^sD@ggFFikIu!FdpVwgKYN^`;~m4&i)DU{BXr8|3E&CQc&(+ z#Z4pXtytUO;ml{l_FetI5;g$5yhU3A%!eo*4@wdk1F+#@1>^O(zxWr{nJ!VfTnqs1 z#ReT8EZ-ma03VG)N$DQB>unu-ZO0^kj!CY5ng8(w_)SM$e?dcwvw@63tJFbgsPjA4 zzfdx-Q>N!dP3d72>rvBE{l&TKm(?H6T&76h=-NKAlvp}E37VHS_s3s2&{cKeDONa< z?xbCCDa-_5Vosq&%p(y$cu>xN1lX3!m8`uW5)BNp%(%7UwxhSpzX+D6OU!SL#7f-D>(>5T%dXL30~sYty9v{o>O;!4p@# zNN=qvElD_!>}qo;yK zo6st^HeE7rM)CSgN#|lug+gn_-|}|3xIhnY72&@@1X88<}=iVL@=i@Dv4`6t)k7L81WTR^?K*5^j}=6Mf8Fq1QVk?YpB3|hy@66l)SWxT)- zSvTmJMf7QIe@}OUjP`8rXT=h?NwMB*m9TepYKYu58c2g?TYNb~JXD?AgIa8!LW zoK2@si1tI5rqSX8M>}o-%HQ?xzW1xf8eUOAnwt;&u`AvQD*B=E^0QmKzHlmz(#>@% z)H=0{TJ~XT$WWLDH?U@KOKsHVOk~^Mwdc z??xov2Cr1YpN|@yo}5(sEn_EU4#oMCDn5@<0k?yV)`o;?k(bNYUTxo&X>c1>sOmZ? zIu~U3&)yZ{JJruQ&90~*a=YcJQidX|^4v3_D?57DV`NJD-tA4$LoUN-WYpnR?I#xj z(s8uw;ewW(DGovO>5tsSi9Ub#40b&BAbqrloD~C6G0q~v@N{5l;d`Pvr>lwV_`&VU zXM_qM`*OvE9Ib%2l>clTf5iIL)_a10ojqk@v95NfwFUfi9oWmBk1({#CX^ok`+f2t zJ$6v!r$U~8!kKSZ6v8$4B>PNOCm)($tNy)xQL6w-EVGZ9-R0P=WIVp#V6ALWi07=) zCfa+y*H7v=QxPtSZU8 z_kIN;#Sm*J*`iw`m~QxCOn{IaTcH^q?>_U5 zjcQ<@>2M8j{u+k5f>y77P-`Xs7*=@X=(@W&VnJTi#|<7;9r*rcfSO-p*~uoQdTR9P ztdVQW=8y+E6)Pl@P$LVN<~*uz1}SYvh16Yws}3c9U0b*fL^Y%I2VU| zRM2PhKKQpXwT%Ul4m;$5V)+uMYKC#gd z{erLd`LiX?e3(t1w2b2A!0|5z@ewicVDQzo4vtjn2#2W&KMjRLWb>;yb}M?Rzj^?Z z)4GHKVI|`!(%PVWCk|A==%Lc0>afSo3Lg4v%-l*hNRYW$v8m7JzO#5A4#P~Q7;pUI zS*eTWd%jMuUdRYBPQhdakRk4-LndLQHb;=X6Yk$D7?WSL4$js|1QUD=q=71!X`3v^90myRwgiS zXFQNgB8i3j@3#(IH^0}YzeWSV&yyyzUY*ZG((N0Z0&?j<%4L2jG71>u?`4Ss{S=Np zEm(2eEmp+k)N_t)mO{ct`w+ywp~KcUA?p4}TY5_GTSjK;?z>IdO>HX%HPGYfc^=4a zyzBecz;<#;p5{q;4T^BiTWMF>bdt*O>gnx{iaDBm^NJnl9^K#xmBiq+TTB4m zpw8Nv!2FiUEZ^E8FtF_u%t(9lXlQUBdTrPM>_-&lm_4bwlRn;{Kx3z;{O^y+&IJP?RLV#$67pb-BCi9E(DQw(FVlV1_O64h> z6{PfX9y1@eSIdqu!rL7wJCAl=mka!ADFI+fsdnhv`Qs9_XU4)mYdN&30AgAf+gt;X zn7KBvpFuG8!Db-2ATt@f!YFcby-X+dK`D zDt;@)=@Y5+ZpV7{#6B_7GsJ{XFa7e*M~U|j#oG(Z4Y$%!s>3^%D9tza2aKdSVsG@Sq4GmB*T~6QLN=T*M@;?S?z2mGZ^ z=)zPat)%R;%%~;9v?WOwq^n635n&^m*6{zFEOJqwy%>Wxq}5I616o(Y2wXP$lRVX_ zDW@oawj@YdkG@Z~p*loYVlS*0MzXLK>O!24q18Lk9fIWzIXQ*o4+R$LJVD1vB}oI~ z9DK9cB5}I`WiJ*085xi^A-JKYZok$F32JbXyx_q8W*GpPw zswq+Z6I2rdKsEI8KNvorpt)8|n^PZ~3yH=Wyu(gWTM2+Gr4fWuc*c#{%~E;xenOj~ zQ`NScQ^VkzKS`BUU~{{*wb0wkcQ;4+5MlkZKk;;49TVPVeHdy)NFK#Q*5lu=P~wef($JRzHS(+FZ16SLfBWKOB%)W>%x82858pu7#ECG1R>cPs zxNC-D2lk~rY=M9E3N4#?5@ZV#7KJ~GOz_W9*U(Y|#kLjh``d(ahdp#+C{oc4bi`@J z{nAo*Zs7SO?vd-eIq`$W-|;7LMW>RcUUQ~X!qJ|FV_4%GVx!o`9S9gcr}y87&|Jb+ zZWCRvqKzA9Vhl7L*LILuENZCBpnD~eG%VI7uUfc-uoIiH^nfCVJ0T;{)SJu?O=4mMr3e)yE@#}=>GtIO%hoBNiOtaP3h zXg0avmx_DE{@M;T*yWNH@<(~eF9=~OrUgf|ab<~bAm#&9p^*8Vx8($ZWjD_f`I_^| z|J;fn7YRrt1Uj{kF}(u~ZcY?BxQQ?IdUezXV+Q~@mf~9Y&iN(Jk|{Dv+1L1h)Z7J) zF%Jqz`_OfgWVFp8yS1C0K#UOiJ=n1mQbOFv#30rNB49m}#sqE|Vc4cYf1$n8p@~_Z z)nZu16=CF}cXGEN-o2>$<$Jhz1bcLLTN%{aKDB2fOk<16N3hT@qmRKLm1HxeI%l*| zqpkSgm?IAlQf=mw*{_OuKfH%_PRBdc!6(!wfLDt&!_1G@?4mAX6=mWoBt!7Y$$g4u z0;Z^}pjI5go38iy6eO^jI*el2ahSxwNiqaoPw1{j5lj#2_avV5N~WPvSaW%IPX>gd zeAUxJH375|$AiSWh}6&5{-Cra*C>M{KR!I(2T*c0c|>&x6|lnx!~+(vm>j2PK; zU_K^hN9S*tkvHca%X14nacJyu&$7Q@w7Ay(Ers=&d*8^-h*R6DGtVK2xEGW^%fu7} z!s5ZT-Zng0YlNaJU+NvNOgTyA#S1rwZYiXt|4*r=5rguA6t%PMJOb?Y}XCBx-< zW<4t;`X#H96~o5BEgQfk$@kTP|7tyJlGuou&)p-UmLfIT_|Ij=4wKj~3~tC&PAE5s zuUJxIF3Qjq=BNCGEE`|cwF!##)@z~OPW&r z`Bboy^%k>>`a}UTsMd;|kjVVbPozm~llg0d=0~wS|LA2bkp--S`Zuh1ZvJskgN{dH zP?-(B-WJl_osTN`t5L%*%^+SZ$-tz?wgdW$u zH-j|SS%t}6MV0J)9XXG523f?>KJLH%L$^*|UWzT5$r}MmPFWN)Tcb`(wA&ixZ5AD* zAqYi!srq->2~yxiO<2~jTc<@^H|b#V=j z6fC9f6!P&+Ye;21quhrBvEHU7a|JZUL$3l0_b@$f>(2}7>JA{vk6@A1pN3tllWH{7 z6J8ALpG|W<)#nfDFg~4AWzD7nJfp_B`Bkb!&2&`iyF(al-fb&?mlWb{(}A>cB&2h+MdyrVh?*AdP6 zbZfasSejtj^@(Ib(cg0d#rud%+@(y$=vER6Dxn=HjnkIhj3Ku5Ti|gL#1k){+ zIyn+=sS}Zw&gmb&u4crVzL|k^{&&p=0>z;e3VRH=zmx!**Mq+XLSVVk;g5v{=-6z;DtmpQ0T-^C3qb#$;i9^DRG?7L}4L2!7NM`l>aWnUYmKO;) zhvA7j;yFmV2FPIlwB1;(d2dMPD;IGb(S^Y7mlOhbrZXk+O^6MAGV>YFH;gO;jfbGZ z|9oCyGq`!EU0bWB9h;`deZjYVds%`!{r!OQfEUW8PJKCF@-!aD5aRwZkvsy-xV|f1 z;Gts7q!e;!)&~>UL-#JMy2;e~$%xe{=2o7QVDp5`hwt4_kG4;rp0yR|aeqB2f`JM*E~Ks|4fuIOeEDm{|3(q zd#w=+=((1poZcH+q7js+)nx&|@b z40!@2IA*pZSI=PeWrxj`n2g(#Uz1l{k(9qbaA9|b zBoiHvhzRoZY+J5dW9J`wcW#34YXl3@#o+toG8y$T7~Jy(-F

9|+4xb(sDQ5dp(I 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

DD%ZNAz6dGs(B8U-^e}9Vk|G{-wS z{66?Z!&p~U3+14{K*d~MvsJ~{(KTL=&m%bg(wG||$2za5slUovrl!FLVaEf#>f5kC%|Wtkp#Y!~;mZG(P^UOya=mu_EHk$N z%V*3O)GnBtF%TKIFM{oFk}iu+nsNOiFrW)w24>tBOU}sYD5`1kxrXG=?E|}0;;Ex1 z2Go$NUSKebtKdhYe?r}l!R-GlC{ywtmNxhQ0%hF3p$9M64-*1Lt7-lcb-22?~oacZ3=XdsZ zyiUzA7331toSbkg%VqT?$j6SC9M=gF!_XkD!@OKug%qJ8`BqAp_%{=F98nO9Mwj@E zl3~IVXyV>O#iSr+hc_1T<0)}Lcf`{9n6xbyR_r#kQ*fULNbdM9Sz_?A8G^UEprH|;(nKytHFb?W~alCL}7YCq_RY%C0oom&j2Qft=?-3R47YN zO9^qp`@!9P9)6}J&6$I$4qF9Ye3uE4mF_|Ht;ss#s*fQh<3|jT+XtjJ70?JUICboj zw)g1RzHEY#novi5)8u&zc|)K4#JP{M3ojF0Xa!7S-G?B#sfuajaYQ-PJV={~VBg^} zV%t4u;<;yWji~vEZJdXW6fh+Sx!o^@C%Na>YCH9`quAeAM}4Lx=SyYj|8AhoKd~`I zf!#Md=<}nHl7xlMZm>QMrFSpsJC+EToEwaoJWxkXZe%5(afMbZ`@^Y5>x7Bxlh{d# z6rMvG%aj~PkhWxGG%jz5swF+Py1;4RjuPX>Gs)xV#%WJ>KCG&F!znP=&_n}F9u6H~ zp#T?N8L;{2t-N<9A2enE{U$@PB4|U=HT-WW33OBK8wiy@xtO(D?Be0{`LOa>>j$&~ zHz*%HODt@(Dc*VdE*PNrk-ytrM86_oM(ku*U$q_zwe_ueaw4Nws|h?$T1AC%$kiZl zKr~s}v>p9$l!pDj;y6w1Yc}om1ZFSS{MCX9C2e$zgDPa6I8~Q`p7F6`CZ+ zk+Ej+Y)RrKag^Lj-&H4YMp~tN9oQ$RqxRBziSVJAI>t`Hf zMcY07^45v0ySuzojnC*4_T!0A`_9Ri8fU*c*w5}WzI0~y>iGM^f!I~|&D=Ng_cghd zMEPpQ+NXhfP;Y}XKUJ4sf!+)K0$2sG(QStRR>}TzSfsBgDlc^E3fv0+QC+9bd>>32Iw9ZJBWGQ*X1-ZLMSkS_+Xs3c#%oadtzxR zL&+N#;+4=Wd={(K5>hF;t%LLd2<$ z8(Sc6<9zTJbr7sSK(5avG;O-8kYB%am#&ce|hY=={vRg2!jft>@^AzHEEZIOIB)X&Z-1QTMJ+6Y`PVPubFnfFO zeW{nJ^~sgm8(IZJQN6?m*60w3$xo2A(Y;yqt0!WgiG=ptd{j--UDCg61l_H0*#2I0xT$|6IiU{o}owr0A|l3&jOtRnB{GDbw(rAA<&lOQj_(g&-ZeWH(@PW8;}3)0IxVj${?(n!cF#@ zzEF6-?fsg9G6m3Ck-~@v$rr{wVEsx3j0aVM$8U;Ol8S$K&^htTP~ApJ*-a_2EPK3h z9P>R=qXY^QY8g?(9y)pn<;pW@y*Sh7>KY0ygMaowoJ2x)i0=21Bed?*PzCFg9x?F= z0~<<%w`9b{qiKRD8`n8vvCJ%oC_=xaA&%i}-og>@FH|&q!sU@tpT1KX?mSJ`8CNMd zC7BA_d1pDRwX>DhlyAo)B_>+(C5Tkxu6zgZcSto6A=9uvhvaLDDpi1(FY%0NlcPMdU>0L9~hL z0h6JDDqdcy?A_oBE3kp8SaM@8xw|EAw`c_NU1_I@Qe+fH675`MmE2UVR#jDCRaZq` z_TL4$adxBO#!ie~@8wS6miDXJI}-Bpd3C1iy1JEvOBmY|#9kFWlYoQEljFb~A(G3e zn(SV=J{}ITf;FhwhH@OMyQmvES`BGHbiSiabv7ZA3LhYle=i&w9q!-cqxyOBVP775 zsO7k&voLcSvWQ|-sbfQuB^xo3IR$20&BS>XMqFx<`%kcsB%_(3=Y?wnb;En0_;f&s{b)(JhVL2Cm z8gx{#ii{I3QBqrlm*XBe5nRb`x!oaPcl(3~o*?SIv=Hw`{-l=yznsXG@m6u=SHJ43 zC-DE>KGB=~x-dEUm+4TD)wi%Xhf>M+ViNL^LidcACT(VF%bPX&d(pzDI<9Bq`ok~i z_-~{alG1dA_w9FDRw0FzX=_>rTW^uvS)aI{v7mIy4J|EZU~f+u z;0^wAAw8Vt2D`WL6zi2nxP0*U#N^}xxmtaAs<(T>YW)1-9k#3cucVbl#}y^e8g%=O z;1WYs#6{@Nt*vH(wzECpVn{J z_xQ^)Y(a*wIm0=>n>G93xw~w|RdJy9*Te2_-E*2#xF;ad{%+=xDKCi~b^@kHt0p)J zq8T6p$1v_tec%X4l8wb#Qytm?mZi*dup*#$2eTPQU;>H;bcG>Ta_TjSbpzrF_}?hs zYK^K!5iE~}eJj9KdsrN3$`2DixnuX9b&d4C=Dl6SAYMk8W1c0eW9HKo!lYYMpaX`W zKeNK4choL7nrM5^x%_p(A+DxKjB6K^{%Nfj=Sz8sUUv!w4SXlsQ zPxhPRyu?E-G>2%he%y$ZqlBAfmp_bz{F_Za&BHe3YILxKLIZWo^d4_tQtQKNooUm9d( zWuZ*5zSRFNlDR&R2^>9=IkJ+8;J@DI?~|C{gB<$DYhNE~_dWINdb*W;d~jDR?@0RD z7FY)qs#A>k)Aa;vR!8|FN6G>NV)gJI0)04tT@00e%E?(K@o~+iX}IL7)+V<&uC&r{ z%{O{NGiE}FyE|?@f^C z0Wt7ukI1EU@=jC7N`dW?WeXL@7voUm@a)gcaca9bQSu%HPX5T+iXWm#IDfr*%WnKdz+%seLC1q>(D!IGE zNhQ>9uZK|!J``=+lH#5L6x0-BN!K<%Z;PO-;4?oxG9{w+9tKbaU{ZwQ;_zA2$*+xN z2U{0@M!tEB_R;f!n@gMRydFIMc0?HCZxi#sC;1%tb;ED}>;_=79DngqW`B4YX!Hi~ z6np`dBy*pi1s-FsO#LRF`cu|=*{u|(nRU8cPP#1i1zz;+Ez4XjpP&e38b~_-b^AB9 zZZ?5HniD7|mv{652TubjuXmZR6fV}{uQ&pB2?NQ^um75x&wAz9UchCJF}n%?&IJTw z#S{5-Tl#7*ei?g_-4+^n(+YhxAalx&bdNiVj-0Ga4c;AbCTw6*(@MEmd{=#s9OrFZ zhWPuG`HpFFyX?R{Ee{Zd3VBMYZor+OYNm<_Rq*d=ywwk(M67f9VLxFRw-S_vrL_lP zRt{`oPVdS4{6`obGf|Aq+ASE+sVtX?a8p{dc>-~8PG2Oo+nBbiXTVtLd=;(((dkK4 z+_@;YC>#B)9X;w9htnm-vV?}dA}C#(-th54dt99`+qJyoy|is1|6^^ra(6@X7!RJX z767zEU6^st#W?H~7JJsub9T#d1arFEIT=MtOIJyH$efDhom*NmDUCiqam0E#GB=wD zAik0;>2O94z5Rq!MiC^gtUiNoU#CG*rhqB!rU%>_e~>tP8`JwE0@>XKy38?f<=R{f znt)>Rk#nivPNW@iIXWRaeujqf=-mhU^)Hykbn?Id*_NN`{my^oIbm>p*mt-;#J{ZG zx}v`8v~c8fqH?{)ym)nat`fh8Z@!D~y^HEtLf&+%Q`MjU>64Cdx#$H7-gM@tDdy1& zC$S6dr>A0OK4>c7J@dl_p>Ce`?#Fn)qJ~Qq>HUwOoYqD9R&Z7GKFJ6Iu}9ywM}IO{ zb)jZgu@?(meFFT&7qeIAZP(|x-eWAOKSU^ke(ozPf>0 zspKYECCfOLzh_!`a|GBT9riDRGg$EX&6m;z0!1Ot9Nj{nmBlbxJ8zcqKCgHz3G}Bd zM|b-xvUvjX>*LIbTd^^H`uz^>puRBIgHbVrPN{fCW163G(nisOtp_(g^`sM(+8&^i zmc7Vp+ukqb_&y-_@RPN!XA9twJMNh^TFG0&C}`j7>RD;RXT4}vye!wtm z?f_wvW)Cs6gj`5eFQ0LzN#2U!Td|XUEAEFl$||<#tc)7%gbC7Rrmp? zc>vXz*b}E)6Lr<{VK%3ytJtao$^S)ez^0I`Z3a*~-tDc86Vd@A!0U6?slc#U!IPWIKqv33 zPDpNOevsUjO;c=V{MB0g(t$MgVE0zr?yZ~81pSL5HCRJ)f2x0s!1iG7oys%+Htg}@ z4Q^tWHg}H}SbyNw1Bo_DfVwKP->lVTwk^v!0dEow1lgGT1|&Lmsu!zOof;yt_y@!- zO#7O-zvS8qqvqDFJ@&i}$vsPPU;E_z_`bO%QWK{o)X8NwqFmG4smCs{K+7jfuTz;w z9GCC9#T2GnEh@(cqT#m^%lZ_Gt3W+t|E-CUxqj1z=vn+hRw&ed;EwX#F33VyyrF3A zPZsXim^?LM8X5~6a`73bFruL{#Y*be7-~kjUZ{hccA2Yx{p9OiXAZMQl{of*7DV&o zx78vZzi~n2&n!nCLHthA*^oMrY|*{7iir z!}fJW=K<=8byXRjd(Mmy%MywM5x|9(V$^f*>&qV(PaMdjOdB|Q3L9Az=6AvdR?_-S z6K1=^G_8g^cCE@j&D_)?EAth)h7W9zDUUs$hcBDaa_3@Nq5mK0J)6HA45+sT2mZeJ zVSfJPVheG_147+EG;zI`&V~X{`Ef!2;;?PNs%;`7;H)%|uI*~GEvLNiwL7i?c`VQ!ra`-URWIHMgCMb zb#?ssDSGg4e@{xF?wTlA97nrSJx>+&DTl||hrAXb0;<80dP@N_kJvu8klk&=E+)RE zvuj5KmXDTqYKs9gOB0Qd;~5cI`rpE==j%xmVcJ?r++EhPiAOW%LiIYSn6$A=id8c% z(^sw%Xy?4~I)j(}kH0c$P)du%oveuV)+lU=r>hO-Pi87O*qbc|Sjf=h^?0Yg$oZiZ z_he0zAuMP#D;WL58OETPK}xQ>&P2wKU{lGPYvh+EfSG;lO2mka9l!A~cc(YUm8fLr zRy^V2jAUx=cC0v<9mkxzAJAE`^a@Vp#Iu)jPURp17u-xD(QSuV@O6ENL`J`xO%tEr z7-q$NsZZsgS@jFwKP3>@1)dgi`89&i46irL!;$8DROY%Sn44GA4Ku6etsQCiJH}rJdVO}d{p2hd|C>d)}e#>mUgZ8`rnx) zG2Ob5?o|(697s;yyiF}m%)(BcM1Gq)-^z5&DDEz~WyXdzks8dLi{Wvk#YIfe)X0x~ zog>PO04&=ZvLF#XaiWzrb{)J*lN}AUtWygIu9gQXzcL74-1TErJCrmkpb#8PFF@m! zbC7+pU063W;#N`Lp|4J?)w`#El*vMY_*CGo0CD5MjakU;p=b{GLFcdbj5mb~DYa^g zFL*e<5?Q!#7%z2JnE%N~sD0?a9%JAxiAH-eSc3sC$k6$|Q1g>Jc1!0OO|Rjm>Ek)g zrT#kWqb%4bvUrL?3PI6bCD|ihDtMkU@j5QtiXc_I%>AnIJ-q=`>%m_hS%7m<;rdT+ zxKU_huG1O@%>Nu*uYRF6|FN}``8THRB<7?XamI5oU3EzpM(&M~ScnD?kp3sDE>~~- zMlgO_Zl7+rogh&2G9$JfNPy#(#P!rJt`@G(_nE&n;+yv81y<#43v-OqIrsmZW`z+sx-{kXM{b}H98Sp z!=s1|4b|+T{K=qquPgi+hq%CY#vv_eZSpn4Vcdh5BTXw)l057~gQIwL zB5~$IE1oREJNdt@$dri4kK{p~ayi$5acALipd+4-Z=3U&XG)u` zEa&VHtsY{x=JxLgO4ATmX?Z2NOYZ^o{k);pA7@Nnx*~g zzin64nI*G#5@hv>MYp4B4Cn|xWs)lTq|{^)nduCeB2sa$fP zn@zq^OY?Ju6~q|5R~ZryCMK$6n%|36xQj!7oZOj_-0@rSykL`v#l!`o<;}U;>w>%$ ze6AM$ZH)d<%>Oph_hHLRHSr++pVcsX2+ak-7wBMbMW21?|-56G=9@} zXKB9Jcbccw$|yskad`I0R#$45+CMPZE@puSJOM+zhJM2%-<+7>-2?P>n)t`VMbv>eSCpR?LC5hH$iCy!np}>xRydnO!3!zr@t5&wD)csTd1!Z_FmpgIh(tU)% zU?gVR%wGB@^v`M?w%9-V+$(js5?6w!Of{>edTP3w!&N!d`(s-9WI0>@?y9DZ>o3}P zY24~%lkueRYRDQWXu}%x(jZera*T$bF?mh7wSY8{J#~PL>;nx|^WjyNq+Zx? zzek*7w&%cc_&r#(mHB0)M8?{M9S9@+)xJNEre*%+r;AyR+;2*8)lhSSXPX2KHoQy@ z;I;bgh={82DBN`+!OEuO)Ed<1=8?PY_mC8hOXnP_boCWl;9uWl*Jv!Fy&SZkiOo(V)4_pj>i^QA77ky_#fg6~C&bm1%sccpAY=r(3!1NUo#_W| zXm9guHbQQoHxW1C*L&f7J~HzVp2SJea(>)7GkcF!DO1DfO}Arr!5*x+m1`WsW6~@H>{ex z(=(Tz&%=ZKbi}RGSAdO*Z8{?Q32=m|RU0lf$64(o0M$ zU;ZJcx3N#YzpU2zfuburxD0pQ63j!vG4+hLayx_2SQy((x~;>e#qGN|r!5xb&R%m% z)-&goorVPCn!FFaSUPZ)x{EVNGi!Cs6`S1_$dZ~mKeu6N!Eg$LJ~4-PvYf-(pOTC(URAkO{{r(yT zdY)v3bo2A^z39tF*k5kWUX1~>$mg#bsZbQ$^?AnIPxZu&EJ+DC$6yqgm&-|M`u#8O>-JKFzhyU_`tzhHtMoC+18SU# z9M+#7X0B$%$=6UB8+d1Ro^fm}VU}dA47(q|JmEyo9e*tk{Geu)mipY*;6Lx!?@z}3Jbq_M zf&1D^@t5CZywKa`E|@V);1wnk*#?XQNcB5v3P1uN)C(ZFS>2#H6sthgU!Ue)pW05} zJjAav=77L>aRD4MJnhX#lB)0Bv!8MOl!mdMt1?+1-@#R~lfp806N28O3HKuRo6Fw{ zCNRi8?yC{u;{x3N58e~{9yq%$qq?$Qfm!j(zmW^!Jor5b%ISZu1mPZhixZ^Pm?$Pi zcRW?RcV3tGCT%6BpxyOpJne1nPs>p4?-}FftaH(%i+8o2!(e;ie*Zu(;Q!W`RlFNkux^)cYSG=bTsB2;U6jwoA$Am-Gq5-xnxd zl8IGpF4Y?b{j)kURKifS_;||dk+MXDd%tJ-k&_|#zh=MRubu;sM_f#-V_;x_UMkk% zj%VWeKUnLkP-vJEXE+sHZF)gb5`~N4Ex{uIWZk4Jh5MYf2NEYn@Hy1XiyXo&+VLSf=Y;(Vj&)5 zlBN+!n$S-l&VL9z)m(Bd@a)|4^)5^=e5QTRl;4dL#D+gzNsRGG$I!TEXJ3yN$ED=z zYEi=9aA?~^i%PNEsJO>r;b|w0 zB*=9&KAJEKy4EwN?VE$^2iRRJ$k+Uh7XY;vlrTbg`5~Oo>qQU94U!#Xx|6u?88oO9xMB#h(VMryYo`=y+_ib5errpgj{|XW_pCHvqjb0Q`Y?BX>Iyg#1Tu%T-r(CD zZO{LWM_KNR-@8Gzw!Z^5wCwG`jnV+FWNSS+rH-EVU<980cL4)2* z3RrS8s~7cn`$6sjUbko`30O>1V7u&H^U)6gmu#Ii+BN$)0-RZ*Gm3^16;J3ii=q`BA^ zK;`IpQ*)OU{@ve{3)<8uBNx!J-1=gl)x`;|z4I&ckW*kbUQBBuB4xm75Jmh9n&r+L zTu_Xjed0;A>k*}~cpUZ-l$t;2nHu_2uX2lXgDZiZfAiHRbt_UwB$fK2BN88}U-rv! zfdSS#l=s}e>C-N=vozKpx%+6i{y#GAmkpndlNTb-B{Gkbf18+@Emd8lwBdjn{Le)I zLAUkc=>_b1XMr(jgzTc7%p$WSTkzk270_cA}j!>O#ItWV&8f5 zK@g}F5b0bA1AqdIKh@4GJk%#AW+pc`ce#uCN&tkq;VT1_>K5N-B%5y@>e>gx28$I; zm{{3=?T*B|#a$A)F}tq&*2Vl~q#0%?NVwnRi6(^rQ>$`PLpDejXcj4L#v_Z$Q1h)} zr6+NnTdk{#ZTO?b^m6K7#0nQrz_TtCE6R)hY98>`Y(PhGGw$VqL8gQT?ev40KW=CtM>^Eujiu(7Jb7V^q!*CKQGYg*bOLzeC4 z?uZ9-TXQ$?j-%r)P7Ee2YDlz8UwN0~GdTp8D!-;fFnHhZoA7>mm6h5!qd9*^sn{Eu z=B!d#HjWU3Gu{q0ytw?nMmM;<-%H#lAE7WbHz|}>xxvR33$J5lVqzNH1oG%?yVLwW zkKxw%-<}^lvk(4fRk-PUWG}hVQ^}a6NzEs(BQKYh?i;txIVWuc>RkXq;2PN_>qUS3 z1(EdWfOZ6WLU^%|`I2M)eExVz=Cbq}4|Fnuz0k_a&feZSce#jd19P%n%>poH@{0LY3dK)e16$NmyFo_cD2zz@s-Ecp5$Fb>$YU3v>u;z12rrNC8H zJ%QKQYboRSO>~-huleQIKtM3O5s()y=N4kwwR1qA0JLEMe&7Xwj=s2wPHyK%PJYL* zz+*S|zwfz%*~j&$n|G@@drwmAnZuTfeK=a)SfS@yGsS)?)x3#AaY7Z`WR*svvoyLW z8BHW6M<52bufE?X{Yke#%pO}7)Pq|ZAnj!fNpJVLUHN%R?v7g>7$))cfwMivS-?Uz z;nTZXJfiSf#BZV5BLt8PgLL=nLd4wAMi?H-C|Nz%F@Zd&IcM|N%|r|A^`SY!Y{YALWiE4CBV9Kg-=Dk zBl`o+26>5}pr_R3JhZ7{m5b-r>p^xhCn@ZG1%Era~wYcO; zzc##r;4@T}LLb2t+)k80gSAd4zVk~vW#bI-b6%Rpz9AkA*^Jz~Xc zy_{)dWCm3I_vcq3{3kg7#`rw-pLn|17qHd0YXuZ%Zv+a5s+N0M&zUb!gnLiS51#aF zx2-y~5&(6+zCUnaHvY`;w>*5XZ9Ytq$LGBSx0r{LAHcTveU zD8=#C@@T@?NNm5XerteP?@9;0T*|#?`IISeA5;fg+BO@zwF6^Wm2$IN$)iHpCxRJ1 zel6QHO|QE}f$T6=8hMnN^yKkf6Q70M?h1A$?R?4DRkzK$&gI^MwuzxS;o2YdlriFlAYi?6vQbX-;vV3U9x|oNh~lN(#rs&gpyjPV1S4R{O|>wdABf|hVduuftA47!@t4Dmdppp4;Pt;O|F`Ftj*HIA z^YLG!rB7P`oteP@$Tm>qYIWh_(@o7U0!S>b2yfIcVCY^}PR`O}>E*|}^T(~!fmeuY zA3xy3M;oFyh2eO_-R$2A-Af4RTkZZjj5;K+&H$aFPE4-)|34EjNyCoCUkU zoHnw+O_xhvzbz}~uCGbtn~(Md$XE%-vuDB@bOb0U{@%JWZy_sG*2L~tB=tteX_UX zX;SPiNfGFcv0U*L9#OT%;O!)fF97tjg!NWVlPohzQFrG@NsbHI{W|yi7O7B!2mJ$z z87lI^)vqIzNm&VlV)_b)HYKdsUImA7aX0M~l9gb{3B z!R!7%my_al#ElhdDgeq3gQi3C5J zz0=c?6cR+m#6Vo1#X=GJ$UsXa7q{KpzPV5}6>KR9WyB%2BSG5V{8jK`0GD0r!s$4zwo=ORm(MO+&e1HV1O*$6v$ zXL5Q9A(cl9@FMa_Oi30y2RX^!)^J5cQ(6@GWI)nu^qMGuwvHco@O`MM`0>+UV;&l1 z$b&VWG>PQOro#{MZ3K3r-Y@mc23scGs#cl{Y#a_a{EwPD{-=Wdjw!flQYiP1d&a2) z!^mvo<*)F051MipyJCPtTcn$rkdoyDtD)ToTJ<~9N+{eduV!37P~EKO{X2^HT{}bj zPLFEKCEPI94YGgu!H*!hc3ZXFIiywU8@|yyijT-0AK+!)qMS9V+MD2~KP-K`V(sSs zrMg9!CPxGK0;+v$>^*7}%Z7m)Y4P{IJa4d~m%Pjt^i$p`j_I=k`N#{4Hf?v+U1GYD zh^c2dMLRj_NkC^aTw-1z)^pWYF|p(g55f?WnY$8OCXrbj%#I^Ne7}X+j(?{zD2MMi zH+v)vZd3e`t1iJ)I`VM%gt!7Vke?62d}_CAojR0|~F<>;pU&)xp3Ty`a409Y|@Os10*9@B1W zybU>-Z$jRBF~5HwJTirmBz(($FpxH_OYYt8Eu>DXeFq1<6uf-#1TB82xq#2hl1aKN zTA^&#SgB)4)9wolN@aqYL~PlC z^g7&+69k-hL0r}^PMy|7eWZVvdHkL?kXI>=^r&2KFyJ1=ZJ1NHql`C>pH$!iZ*~~K z3cRwc=b{w@UxB|6Lqtd-2~mhhB8(4T`-4WZb|!IHmg1H;2K4qhTV5wLp%Wq!eZVhT zcH_#Ge|jg*9%Lc#1%Y`1I+Fg43Z7%{=1j`pmB7Q>Jg3Ko)w&gDiN@T*LQTToev*>too+6MJNGuCpg7mL+D;=hg9G4|J>$-*T9{iz>%|0XDF2 zq6qrpT=L(;(U+PVv*ewZzDA2=;C7r23|UHI3d)iVQHJv4l8!nUZz5GJ=F6%5${3te z)RYyeFFUM1XsYikoWIG)uNzbBE!ajZ8)TmRsXJTO`Fij1ZvY-O@mHv!5MZgs0JhW{ zGw;32vh&{pCUzbz-96XzBmz9*6$adiCSUTY@@JS+I`=NP#8vRZ!?H$m>sY@IX4Btx znB5x{TeNU#7GBeSo=)ix_t98vSeGcKGi$lt%b5 zO(@3>E>BYQLcKLLq~QRGr+as^bKP>Zye^vlJtDp)UoCjKBc-Ql+-(<6(I}~loh77{ zVT6GKrMdahy;P4$R;$l6MAPTg>6l~0^kiK2M{M5{C!@F*1ZR++OTM9p%GP9PRCHjQ z^PbOMAYtV}Rb%8EN%Vo30hPvoLqbc+KNB<+)(c4!+H3os$f1jRHEGSPf9`gM`onc+ zm0~4%S>6U+jzA9P2h^}fd$YxQYohS5{*Q_}y>btMvOM&v2)qpcs!9~PC*&!#dpUO1 zWLDtviZENNh&x!~dB>ar<3ZMhs+=~#43gA<8#vO1GtK#N6h_~T>q5lL;|9IeZ(pf{ zkw3)C8#2;+HuLpGyV(d0UrD!8F?&qRc9fd{4POydbT=qhLj`Kaax& zfpR9;kV1JhB1@YgM7Qp4$|x~sh{Iqe?ULfdpw*>48V0RW7?75))jw%gQqg&e8Y=|Q0Ma8*S)gGwvnxqhMVio?zn z1<{+4&`nU9RCM+^QRP^3#I1S=W0SMV9}%+I)nnqeqYLQ*QjQbC-Hw+SS1u6y%Fr>s z8K&xBTnLgcig!P+GhYW%lA870Cqmy${wZwzN(~hqBYP(ypp_us+RM=$k90{?%o^h3 z@(OvGI07crdmHmYG(i-11Yc=$SCE)%dsF%uX48|WW2V&B4Gn5aD8oxpqgBH*h75?k z#1Rw&Eurk4t|RSuO)eVqb?`O+E%K-G2Nz41?>y`zm44s)`k(!;GO2npnEl$dmME`= zpO;TQQjmho7_xKEA;0KD0=P+r!N2Y{I988Cl>e{0KtDls_v38u3`RuUeH~mDy!eSf z@*?1QBf)oe%LmaUa|a*+>K9Beoh>Rz&Y5!Tj5cTWK%;*}7zi2p#nSf^Ma;e^qdgc% z#E^+vpqH@wN$t=<)BDeq4mfS>*9RitI;yXkhDQ(;Z^IEeHRR(qUT#sPT8bczS5_26 zJ&Vhe=^(CmtRM$4XTB%TXLYsBldJ=Lbqg!=XzF0HADY?P7muZtA#nHpKhRI$(5vu%}Jj?iL%;R}_vWuaq?tkNl zi|4;C04201Sn^xKUM~&uITt@!K@FWCz+J<6Hhw@Va7Uc`_P7i;l+Ivar( zWb>0@?v*i|IZ{7aNeSccE!5*KEgj(~0C_avJzdKvA`eo7C&KOBwK%Lg{l{WotnR(%eUta?!G!Fb*^q zm}8ocKmX^@TTYGUxssidojaLt++|0HJlPEL70?;Um5zE2l8yu*+z6ju{Q$Xe=6BOY zV){UkihAK*r5eifcGL6sb4DF8yCtkbn&eSqk;1Gt1J@mo>G~bk^Orc%r}$zQR0-g{8%{T?h!_K-!5TGl{S^_H*ioG>5%7s`%k z0HBfO-Ts8^5i?N#l8!{vi?U*SaX`NZi9Ak3Ckc!cWg}hs`bvZpAzw~>SXC(S%O*~j1zfy^PA^I( zs~ldhqafb2M;2Xb7sZ1_}Idt&OL$b+tE8iSswyFs}=(jNC8=%p3<^bXhg?v8aGsTG_i|Yfnkqhde1hkhkY3&dDN58!5{han|dJI)I&D0MHzJH{C7?N{tvH_eKWKNne69$p#XJ# zUu2^Y>Pc2g*V-J{g|A4S5;Mu1N$@g?C_j@Rl)t`FL2izHyy-)7sK}#Ej#_~J+3%0b z;)Zs$Q%WFwR$uJYFcW<@l^Fb68ABONyYaB^SiSN-sKbUzs0a^g_KgJ^VlrEy==wfh z4qC9?#-K_ZxBuHI zNs}ovr26cp!J0+=k9#dYXo65-I9|b&yxg4F4n(Us9x7r)8)7=SLI@M;HpEHQ+2!yS+*{Uzs)NcukXRIr}6g{~Iy>N**d-=N5k9GQ8oNDElBEnu*J^!F=i;0Ck2h>Iw-y=N>bb zIj`1?n3ML#Oshe__$aB{WKzoAy1yR~RWkNYfIb6E}5XeLGtfi8*C+?R5FKLTi*QH8sap!4Z0#GVSkEc(+;_zH`2;18s>v<>HX+&!_zD*Z<; zcc6Klf%`t>LV+~aENbV3mwNM*u%cvH16Rp0YOzNb`*l!RW$j+EJQDB}14N0&S|Nim zsOVO9N_h-}XD|iNjH)6L)d(4se(x{w`#reM2tesLi_0Smw0ob80`NwV3+v#8U#bWQ z6S?5=9p;$91CIFUEWKvoQFyCxm|bF}k7^KHP&Jwv{M{{z%#C3euxiVA!qu#*x~>2& z4Kfm!2boeG%)~n)!fP;rvYfE6I93UwlSj>_g9IXcwB*;3?fQ`Xd+*+@prP%~JL7ts z3{Hr&14NMUM0C6%7iKw;&#H`OR1@nHBpPX1g8NYKPq#wnx>QQrM~A_9_3G%sbpREZ zqXz&$L`z>?HwCv-hWF*3U-04dcgbT0T}eyS8vL}ya2e6gD-tktM|q+PoDjM&i5Yz!#;(iyX0Q`%k)XK zq-S|8hXbJu?&!Yiw_%`R4^k{DNfZPigD-7EuN!}>nR{WF?*Fw;(t^r*h{T2xRd>PP zb!#ab1U*LCz;G(Z<82<_iAsc|jyklXpZu*a{7xjhMx=7Unl>tGxArYK;l7*7*ool7 zxe_sb(uk=cG0~!>EUVST9F0{X1w8G-xnL`Xa$R;A(3)0(!dD4hAQ>}tS@Jom6!=Y& zHE*9iu_YgNd05JIOGKMlCo+a}#d}Wr`RIz>>rDm{Ki0>3 z$Dd!!^_e=PB%_1pRgjLuj92`9^1-HQUT|46X*`DKTVj1l#w?=9FJx*KvRNlz=;G(v zpr_-?@*ZRW`M8F80+Ltsen#sIew4~!&LDfoXo=;0w@E5%+WVlpPPs7)?lnWw)A;Ij zSXiG?LUkQcD#h{d5YcKlMb`Aho(uB_&hQY-kUBOk)szZvn>(Yqj4kCqi@oSgj(I~O z_6=)b{l?G2|Iiu;bH~lkdPL>xc;9fEt}{wy;jV`knM=pq@fC?4Qa#tPYllDV|B1)y z`bd%Ir-FyR9gFoa>A?qLNP@=;->8Co%L$Y#XP(Njh5H7xGI0bs9xHWx!dOao*N-_- zEEr#a_fk_^Wg*y%X2!Vx_o? za;vyGvw(>zd*UC5**ta+FmbCZvszrqVqPuWx3{#P-;3HY%XNNvSpNzeG=9^=haZE_Ffq zkW(y2&AD{^obB6=yTopkiJBj6(2EB5p3y}FE*pRZhprCNFP}241VInF2_x#Ghk&xW z9+Ns3JcFYxmO;liM{s?@d$q_{M1c;`?Wfi@-^e}A znq@rO-*@&9TLYTmoS4fZIHhwvo9_d!l!x!2tn&Xcbryb2x9{8EU@*FoM!KX+#s-W~ zNPe~lI~802}+HU?gr`ZP8AT8XSetF{=J@m;j?Skd7bBZ9Pa}wd9|^` zG1TRlrz=`mBOaTVmi3ehK5fuX6W>7?Oc##DLuDkL&MrLn1|N1t#A|Y|wC>oZ(l7L} zEPn63EYriZXN9+;#E|%$UyCJp8D&X=u8hBO1Ndqe@PZJYOR<=$QJH|$?I)LbxfP3O zh#O-~93jr$p-?Kg(BAiW?uIz?RMRZe5!AnD^oCujs=rUvd;MU{{tNRfO}?-kp&-s* z(F33CZY0t?md0#`J)bRU{jVbY3x#@YComeCx{7Zva`P2AnVKyr*ql}$XNs@IH9JKJ zJe`1UM;DAzTR@mSzpWpPYVZfK(@-QMfz?U^2%f#CX3bN;n)pl=c?)rAE5?^}Oe(jY z{pOeuYMg-ZbF@0;HfLy170IlJ4rhEg#=0%?T-4S=HZj6{#rV^Nlh@0uhmqTAmJObc zQqN)7d>%lno%lFaK~4h5j!t$Evjz;D4ad-cD;~T-X`OV1PYloDW6Dc>_Jc2eyPe(G z+UJ_wIcHsi;x{G0B2aXDN~e0x?<64aH*u2CO}6;*lW5 zxG&<&G3lc*Mp{eki+i{ZFPxs5xb5-rB4K!u_Dsd&_8=RP!O}2=A zZ1TEZ_f=`#9%OY3aV@g56J3KFrPh9;ZqSJ9v#sYU*HmTm6at&CHzrA*R&xJVKhX^a zq!*95W2t|iGq_%=F7`#E3SlR-$#tJd{#*1u{P=euFu$<~fDfe12)$?GxYOOTL#Fko=jGGa$_B6Ql^B!z-U^1o4qF zC3Q(6a*~^r4!nw_0CFv_2@V>t)j#Dizu0oDAqk77#G@BtntGZ|bWt*DOVZ3J)KLE7 zPvXAOPaTk20+5@s-r9ZVrQR*$SZleSpex)OzF%Dn$99l(L_R8&HOgvxj$k{}!&SF6MD zmdEZN(W+W1B9g9^GmPNPjK*xM*lT8q+?m*lN&4~MQ~!;j{MU)jH;uo53IjA{l*uFl zqJd&aszu7;7?>(h4p`NpzQ^(gUKN9_S++X>Z9Sbh1mefPWf9CdzePEDQh8E>w+cSP zC~yL?Nv^(^5@0|mtGz|11aPDZ24giE;>Y9gAkW~T6VFYdlm9EP_FVxiae6`VF3tng z&LFO_a6`NIUMu5Rf@~n~E7862w@#kT?8aGNL&><(p~E%}whCalK`H{Zp~>gwIu6;> zdghXRrtKm9HH0*q1X*q8QfG%Sdi}{D1UwlUZV(>-df%#cl z#s9sJ_Fw-4r3-sXlA{9ao7PMU{}S_{Dl1D~HppV(A}jqg&%yDky`h&m>Ouz!P({V% z*r<$yq>>t9(wcYyq;4u&)IqnPGyQZQ z2WjN?Cl<4?u$+m{QY^1@!ve@z_AP86;J5Qq;R<+=WXurGB5}0;{T4h0j4bTtd7?u< z`-4Jjhpy4w+PJdqFuylNM#(7@`EzLx0H7HA;x3NUQ1pYue;v7(<=I^57X&sC3gT|n zz+1)j8eGE+WSVU7{5P#%h9gTj+iEt03o5wpiE6g(4RyXGi5MyBN*`^Po|(_4A&uQ_ z{;m;%k+opxb?%D4mul|jHdf0)dET-2(32_*`!D*`xN=8Yi{3ZoW{4z2-x_W16is!< zPVcN-LI%Cx=;6bX>jF&DwLw)m)Nm$N^Gf?ay{nYSYzJ<$dhwGFPNkL#J(rHU!2fRh zZ{~kLH<^qFfAV_R>KPha@C2*=wv!%5$nQ!V5tk5)fD=KtN$b8>HIcJz4v%$8wtcqG zFiuNI?dQy20St;IjE7m-JeRih0H`#-V_Xr;O01~B;1SPnIeoLiev?wZZr57AqRRr* z>Wk-^K1tw53kmPkvb6D}giT(P&Qs}eQ|v0mmN5w{`{;;j1myp~EZ-t0-!K zjB1OnVl;U=vdgW=b4KxT#C(cEj|}p4le6JdgYPyFATQ$+s`YnE(>FWy}`KU<4? z_sm)FFX-wKT8p!nGW==tMRuCiuL>3O;g~@0X$D)@R&0=WmG~AUn>S3%^rvDh2}$8O z*o?15w-Whye|gPEeN%KL^jHCW~=Gpy2_ zQ1qIo5W?$K_gHcRJz$X>+)-)=eLsrkX-~6HLTrpU$82ABG}|68@;-`x_fz#Eugz6j zsKvJGY;3(xgT5f2`*gPqH7iR#rekcLA^_oLphNQ6|gXbwi%5z3(=I^IB^b&_x7XgfvFcZGPrYPut%c2jj zU;YC(R}sLtH*&XD%CSwnS$0T&QppPTbV1~gIr&oQD?CYihtOCo$WoJt-Qa=w&I|Bb zb2AY@nr=z9vq*$Q8gO4G9Z*>2ASCT?r9%QX>t*elA+6#W%wkJZY~zvs0IH~se4wT^ z?O88Yt{VlX4JtsTszMma2Jzk7s5{zT@|y1+&kP9LNQ1>~TC;-NZx$R6eGzQgO=^;3 zA??NK`O=6MDGr?&Y+X=T8BwevSq>pJ3r1pwe6ZBGb3(oETmM5dCq7_G9OyFsbLSA4 zoT8y$d}$-)<9D8o2HvBVN950|SALev>wR{~M& z?Rv*jZrb}*pC!$Y_^w_ONRFnao@euU{P%5rW&gcBz#5Ch-H(_~yEx2?1FIe`cf(0F z4)bFa3a&c^aHw>_UoJ|3NgX}&MT91!!7=Kjy|9hQz~{yw5s)q>L&8jcQ3p;XJq@hz z7kW@hc=B>P5nF%cy;AHw=t>o(^1-Ql~E=Ba^iuk^bzXyU-60= zEB1YH#!G=4)0(Kv`-q1=fXBt}SPupQ!+ytbF*ZqjS#b_Io7jS958P{Ulb;T$rS-Ov zz*3n)$EuyjztyMA!-z@or63P+ZDgNg8rkYie!?lQ#BWdl5g_AL$Iz0Bhcn8v0oyBE zQ~f|dz?2~~3F`i0gtAe&fsa6SL~>{q<1&(e)hP6i4|v zEw^frV3NMgpxP(*cn=<7X|E=N|HBND{GFSbGQ zkl_Bd8pjAUy+*rLNNMO5B=bGu+Zb|5!|esljJO5MV0V#5&we}3bfcVcoKz!K2a2qY zb98nqyB|lanysTUITrdusNV!;sYbS^y8WOVljff7Lf%uAAm$2aBuY;)BZs)g;uFdJ z6r&i0v-MIA`VPn|ms@fG%Q#*8igq9`1My+5mGWg1Z@kWzGJ2M<|72W0Wkm9!$Io@T zb>gK0O|c%?j}#OemDiH^poa(+4JMymRG7e6dE zN*jvjA}>MgOUm}EBDqPlM@GtzrM+0sKtTbOUwT1=9~$el7|Z1&`ghSqCz0_IIvkff65u` zn@(4XFaXcY^X{1`vu@h)pjERB(a<6K9X84W`9MRQc#Kp1&C*SY{Alne{Kv%00-cX8 zRfRylQY`2*(xMt;H&X90dFxk#yV4<=>ZIR&DT5UHkCF~v&}zF4ZmyOGP~}&GwJXPF z@er+24hEAHjO*(FzVJu>bF7w}8=tFu+RzhtJlih9m?fsQ=-K5><6N?6CW)(}03^R5 zC2z`L&r~%$<%S8nM!yD>ckY=o9grgEsXnK5(^G-`ufN&%{VRu{3fEqo)8j)IT0?W6 z)DccHEJ;CuaF>P3)J{&EwEjM!y%L_v z&W(z(zGT1ez7_*!to2(I@g%M?Oq$&G$6<=i^$UfFRosnLUZIB`oPHymkF9+_#K<4# zLvy1xbZMX_k4rOfqgF#}?X;yrm_TXg$KkB(17JHvd!o7DfGecyLNOp}<>U8&``&zx zrV|FeO-2xprwe%EFIJ^SWw00JSoGdJpJfBH4sY17uV8{nHDgK?3G+weMf z3mY&%>kx*-991(0N`nT}T-Zi;L$Y{X}iIU-klWKWTd8$dbzKDNoX zBHLWZl3B-}@6|E)BvqECtIW4Z;W!;-SX+DcnnLF;-G?KV(6-Y}wwJk|2C@5n$k6d@ zR_ag5d;^<^({+(hgpJzz&p~eC!ZQ+~m`NyZXIRfq|1R%xR;Bs=xbULMEL%CfoLP*A z%5P5f$+Yx~^)+p0fx261b_E{3^g-x1-iFmv^PK84PCpEgk3KOp6)dbO$d|cnj}KcX z3koTn=)95L)pOg3j}5|yc{eTLUQH3i#5ho%KHjO+dy`>LELvIVS3Ej*0E({m(cx~^ zie>jDP3GnkD{^;~{Tb4Gi z^6l>oEVJ_ye920jx9&W(dI<=X^5ul-^Z!Gbe(?G`u_8xf2)J7QIX`Neu-wzFOhZ~C zIG;w4mdW_fHVA#1_Z=g{D)Z@2Asdsuv$3CCWEn_oETz&^3Q708nm2d{ZBan5na2>s zmYz*;_^5$$-g5hb`NwxS%k|r$=8_rD9S!cS4oeU3@g6^q!>yM@rw zNmmmNz-$>}NKV3Rs~`snK4o*+Czz%XvohcbnuIzcT{h!C_b>snX=HIv4wYBc`>5Q? zH4mk-eN8oK7@hu@9E3$M9c?Mb#KAP4lKr&+r);FE8cXn=3XjMlTi z?dAtGXKq88K1y7*ryfy4@-kdYH)D68IAAJw@Av0A5Y)Qp&$)R?d*c%?tlsJa{{gw3 z;t=sSlTXt2(j38U;c=gUbkdjVV|%j)RYDDZCay0khuNQ(^PfVZLJB5Mu4?53IgtHA zJD7yKw!#3whqsY`k9W&h#tzNNN;Ufi^#>E!Kj&QG^@`~Lr7KNHVC4??JJKfj&?P=_ z%Kgx#_e&sE*2NZ(jFAr8Q%lEOMm`#e}q$EQPuDTyO(h0N|`u=rXWv z+D7V!?8kCvdWWF+-?b7wK_yuJ7)1U9;~6Y}HBCK_P3m?^#3QDOd=v<#mYXWOkx)HF z@*8_*Z6r4{2JC55v6v)%Ef5yMO=mxcnpQg?;q6yXxjrE{07R_{gTv)Pxea(Dr=pVW zC}K=PfKR2h)SS~?deVc@m<*cLX_1+n?-eYs%ZbJg5#n0|cX?I!PBn!2MxEw&A_n9h z46ntb5JHQA`~UGImf`=@LH0+EwW)vH@2A+j)P|CZ^~g;nE?6}a0@8pEnHN^izKK_3 zGsh=AA)XGNE^*`ML*Im%!%q~WN0V;e7YN(Wdu>2b?cct@LtQgB<(SV@`!`s_g zu6{ITVgIB7wOH(aoa$WJZS^el2}p8RW~tPu`OCb>wPtwAOr<=}zQfMfW1e?nMzJ5@IgX3>%#PX#$=-)BLB|;n`X`RvVPE9r(I?amr!|ZF2w|-QOB83o7%FYW^J5n+(m$Gl@8DQzzZIbVA>6e`$#E<{2GN zB=R<7b)<4?D+LzEjc^CUQ?R-o5$%y=AHlro!P%iv+}3YC2aV(EeX^g#`~`aLCZlyJ9lwMGH&_RgBp7xYVZyV~h3%sC-S6Z0TC?y=$8nx4nhD`9}Ml zp?>=A%RL6pJcF>_9=LssyX9%WD-j@6ZCBwTG*~HOq(qGOY;4pzO*eI6IxX$2tC1P2 z+CNTc!`fFX<_WMzXV<%-T?{;&KcLu2iV<82Tps5dPUJZ&0n}xn&HyjC2~YRJ1|Lib z*8KJAdcKZu@LJBhg>09QiD29oZo7LONf=3E=}|FWyS7Re(e^fv>~5r1KdN^$fFu_$ z$K6}iI;dFF7rq~D5E63}JQ!q5>&cUsK;AsdNvS96oE~e>N{P@p);AdR#qv@=zw&ju zbrYQOEDQd(LOfI>HfatFpPp3wxJ>l7af<)P=(a5>O2s_^C_}Yj1$V3 zZ$r5#v?DD$LZO6Z(Mq|c0E}qsAGJTg{`9c5#i9F+9b9ssy0e%8DJCXP4gGyy^CV&+b@hTV0crB zt?_(LJK)V%3`}k5Cqu?Iqx*g7_o6Tj@!we6SAcUMwi!U2v>>RW;TO~C#qVdAVHUX4_0 z>-REV4~~lE=Igi2??)nJu0PWb1WqtKe}!E{0ur&XHHitDbhx8xe6nSM8HzTukaCm} z|6a`pZ^6S(-oOS%(WO+;q;TniN+ci|5AMk=nlhzvFAczo(?}VKO08%f z=^=4-;J>Lm4Bj7)D4Yqgd za>sLOSVtp~?_XPEha(sf(v1%>{LK z5Gq9JX0fNwn^6jH>FFOyP^;-_Q@+{vMzcc zTs%su+5U;vig7ibOBgdq|E;{_btX?1LFx_R7?Tw%UV0nes&5P*72Dpke&W?t7im86 z!EUS*ZCQhm;WgD)7Pi`Gs(*@4le~x_iNFqZY?@8*jAC_%%+8HB%k*Md$RU_CRwp(J zp-+Vr+X$J9?2h*){?LU8EG#rDJ|&EF#&mewJd*tP%nB?f1cXWFO#2q zgk6MpavWn;QZwXa!eJ=H&2lPya$fSL%UD#^j<(syC6RHEU(&mx&YS;n4cj`)H}P3A zq;>vp)|H`8^`B}`n|kYm?v*jR1d>{Co$Zo?Fc%;FW&B?Ejt*&N6!FC&Ch08Bcf*Vf z5&KjaVvN8NVH_Bf1SRx!>o-azeWDX<9)usr1B5GIe-5c_FxztHY?{VlKf~)0wIFz zR41ht?0w=pad8;@76^Afos!$FRRA|6)w|x`rV9}fOq++=`K}N>Lx(COP$zx-}xd7UNHyTP>E z;XQGbYev1L0kmAtT3`BIX60({i1f)rdfl~s{jqjDrJ*q@mV{6X%i=sq)6v+F-m5lZ zb5q2bp$vJlS;Gcq@a$Wl5ApGZ$c`PvJXqO8LH>*lhjh9j;mEusoFseR(8ikO*3(n} z*y~ZaogfzSCn}voY)MG=T9{2yWQhrSNx zzabQTjzTah1cfjT_|8LFLUfp666cXO(Q;SU;R7aU9d^Et*i{#+14|SPxx7XGb(9Dt zJE_YgtkZKxYUKMIevHMXjSfJvISbj82bSOTqf;#2CO&wt8yOPGsIdvB&%xLbu;q+D zrp#G(MiOKVEjkq9O=_YDZP}y;!7ux7F;HD0>#Ry#+ zi(k}B`R<3DOKu^S>Ha<^4d_23EBXaV@SWjx0ts!A2%uh7**F=zpZUpUThF=+f zIij+n+%mmgt`gL=qq>0I)tbe{Khy!Q@%5RYZ(QW_iMl>F^J4kKiME9x379BI0LA6g zaiFKtAKmk70&h(Erc|Az>~JC$8Kxm zje?2}ZcAt92@pY&0+{#f4Bnvm#`LU@d|zX)XFW_~(+~EvPcg|MHMm(A^B5-&JK%-Y z)}*?%FCm|2I@IbnXC)+u#MS)2r_i&%ZV*Dwfsl14Zr@WpzU0|{S9Eij%#+bps}egd zxF*tnJ)1-{$(^{>KY|(dkWQ~4d`ztCzHrQJP>fq-A5QIi3Y+Y6RG}b}p0ASu9J8hn zp2Y!Zha_b&&;{w@;f#LH2XM@3=)K11wV|AW)rQ%4D4q=Lpwd5j^10GBlc!3S%~SpU zJQa(cX!ls|dGK&0HHPGf6+xhi1OC1xHPz$$49>Y~#a`+gNovQKiv|C&@wYR*!Hd5ypPbC? z>+T!H{`Y|n6~1SG$EIVlHoB^ye9)@7-of$itnA>`(6N2E#BQuEeq_LB__>V77-z zIs6qK3(+B}S-Kl}?6e6ngP!NdrLJVMWJ?8dj*4@}Gfk$fo!wMwKYG-&rHUJP^qAm0 zbCjQhC@`XdvE^rvvnO#$uaS7CRLGk@CTrRRaDX3%k_=dD)}>L%x!73Lrq{h=N%>~H z>}d)RUWy^TdQDgphcqNb4u2}JE7^_3gwDyF=TBx*!M5O~0h`CrV1r_#G77VSnT?T; zmIIe0_>!ZShM04CmwINtVCeTAnG+6>)M?aFJ;CF^vF*%y)D~oXU>kk-J0WG@_&h<* zsj-4&rhnE3;PvTweS&^N;hSdw9Dum#gZJVbt3rN;Kqj;jhsez%K zf8>0q)Re@I|>My2Hl z_J|wv+8I%`b}EG@+9;714P5xTB_FE_n*8*_^EQ}QHW_(zF$A2YKoS&t1A3a$0Jf%e zD(lABdpp~VA}-CF%xs*ekphIdHV0TQ7;RSU|GeR;__7_rhpzus5~NQf7?=a?+iem0 zqMN>8rwVnkw|kUx*_G;ge9T$ob(hni>Q1ODSQ7Iinj&z*J$Ms zYDjtELrca)Km}_(%OCuwbH(&l%V&DNWi3=LOc%G*1?2r$YC&56aRyQS{ zvspiD2=AbgXP(E%|M<2P#{KC{aZ?r9-kb<7P1+BtUCa64n_zV}77e-RBhDHE0ZX#o zZ5Qw28xh}O8#(89x87!HidptTUk!PC4e0~VBvyp6t)}q5&|rNCAdoR_xIt#`JeG|# z79*8m?h32|+Z(^4Yad3dpDazt)Z%8x@)Tl|xL=;Sp#u)WM?V2FrdcRWZSLzC7~Z`c zJV04y{@ch|KD%ovZ?ya8r+WNhY7QlW8$+g=+VnW$#Rt}6LZ*6S{&K?u|L6NKoI}|m z8&Z!i^T8Hh>-hvE)C}tUPC+MAYoxRD*yP7=F!6%!m4$|(b-H|;LNayteCxD7x4)WH zzyuC5Y%H(r=NTLU^@wh^QKi}1Zg(c0$MU*yTn(j+RZ&aF0FGjBW1%y{`K@nROZrm7 z=OsL)1aKl)sz`X0+9_Vi)0cU#Hx@l-Le0)%l8_?ayGxp&?C-Eb8Z4Ot!my6s^38XR zn=;c_V+e&FT^_@A(t}OyeP+(n@@F)&c##-pgQipEDbuLG_OJM$&`J@huRj>tze&8T zWuVo#F~WKb(fiD#VEpv>1MgmZGj{@`4AsI$*+4dI^L(EfXwjwH)U9i(kK2&@&c|t7 zoKoDq;fF#4%Nte;x+MaK`5h8zkhXw)rT_hRRdy@h4zlgl9L8R{9=?%)E!!oDElY4( z@x!LeldK?2$th!m9rZiSmlliG9R!O%cU1sx<(*+t;bVt$q`hwcTi^dHH>~DMUVTp) z)kY~_W^t^GFMS5ChQ)bSoQ9*<3WDOf z92Bp0;WSxVza7Ky+w7V5$qvyg^|PVzuEgJBfwE8EQpt-0c(cwqeLE!0m-qEnDck`b zpe=>BWH>Lx%9LZpf_10Xoa_a-0y5r4xSuM`q#J2E-{hLpq4gvc%-KQ5^^O$upVriX z4|N)0!gBXB?jr#o>&8@mQ4a_JrXM-?rzeHvNZ2-(NSt;(TANT`Wy@8T?{B%N3~%H8yArEA^5=X4^Cb0li-0RA*R zk;#Y@wc}VJ7LS zY(*~cVrvn5wpCjZW5VIozjY; z=$^pGc~(`^$$ZzNzNQ10+V;;!xH)~NyDKlZ0z+!05-AYJHLRFyRDhO0^9Q>;J?w9M zS>nXeLhlM)T(Pt;Z00VX9|PiH5VtE(!%R|C_tv62It;wXErKdk(_xX_Arp*1%u%vIY6t2D0 zb6qdTWnDb_yhjTZd(%o&E#b1sQ966J$G&WH9TJ>Oc-c9eH@mdpsr-?WiE|z0CY|dQ ziU@=GJJyTsh3$iBvh)A`0RNZ(s_;bf9YYq%r^vNl5O&IkzK2hCd!3eGSMi2$(cOL8o{5sB$mWfaSYfKO1Daf zeyg`L{WQDnREc|SYkG)Qm^=TQ2MI6fyODfc;rPPn>5GHc_Leq{XHG*e3+#Q*+dQkG zzd=s5TGixyNG?9&1w3+T2CNFPTscxb**e~~N%;ss0hU>w->c@P%+jRA#kl}|0s=Yl z6}w!qsF2cb3V7?E4yj_nH|94Yx6Q-bk{<5lA+3%c1gQ4h;`npLRgGhv^;KR3+;#ZE zHCyVFar1XX!^z1;S}ir4s#4bt=6YIF3T2A_BZ4&3*o(vV|6O}_CH`Qe7K~}YTPuC8mtrg_uiwAG9n`(SlkySpNt3+*gfOb;>C-gUSAQ0D zlL#Yo|22di=co2adrN&pW#`S1*nOjsFC};{fM@bwOLbZe2|m=eOK?IXdu6Bm%-jnh zM2EDP?6;mpZgN`~Mg z7fXckwPx-#A22>7}vqV}m&Cvf==8 zZ)q~=txuQoDT+N!u_)K@*y^bkCtjsyP{q0D)g{f5+{J%=-b4AniZ~2EKZM&2j&F}J zbl2@?iceWS6J@EQz+~)2crmC4Zw~>xJN>)yYT{n7d_mBuOp^-;EioK#@FKw%5MNeC zZwf5Z8WOmzy?|tER;(NqhBtlTO0;xtYs}|fm>^^l>!roJ6MJsy9NMPeh;(q<1cifj zN>xuT<=dCDlk%U$<=vCd(f+f|I^C0cOAf+DiWR$X6%(%g%+>9aMkBFi@q^Z}GBw`4 z?ETn8-r=cXS!^GGo6mf;vD*TT9HjwZMB|Z7%Uq_PyBcfcovV_ygvE)IYG);hF+ag- zzqM>6fJg$cB;L@==;)zA1<>d{+^L`)@*Oy-*6EW0X5JpWz;K|ERIudjVcNZI9~6J8qGbMb4<4Q$ z4EAO=fuv>BUoIs4jPbGEX|PG}Ovo$;#s3T{J@8-`09O2W+5GGFcP%)NZ5|3yget?w%y-kwhn z1Seo;#j%#JnO_Vl92)xdMDG5KgQ?m_l}8j7dY zpE&E#9Xc*;FDC@TaQ$*Fl~#C*nri|{W?rCYS#tTeA0}hOx#?5llOsE~0sYB9srcflOUxy30DUgGt6Db(noUacaT@?9TzKIs&9T)3+M5nWu{D=*Y zx{ZmN8-z#fT&Gl2i;2^sTx4urFHnG)4)#8<)Gry9^(Z1 zAQKlm-m{q@$ma=Ajg?bLwdl9@)*Jg~57CVnr$O`j#*6EaN`1`+7gOFC_@UiAcNx5>FA%hW(OY?s*|}jyIaeSb0nRZF_9KwnaVWwch`XZ;uZH zC1gAwDzVhV(z)Xjpw-vODw zF#I+{QluzD$*heznF!sCtiTt64gT!yBN)Z!))So?xJ z0cHm?O{IDmH2J*Oc5lH@K_x;FIQtU8YZ;Y#z-c}VVAiBen$B+)N}~RJ$VZarYdVd4 zn4;;5RO}_m!|T9Ou{>tONv)K)GD83`%FDNgU)S=mjTt6^Uf4#>3&wJ8^0oiW6HfQ{ zxP@!9I{)l8VwMa;cD&9JZ5A#C)fYkj42qX_+hjV1^)T?`;?*<8yb5&I&q}SaGQEyk zuH&eJT;hS6^$SU&^;pD`1TPxx<_fmB;ijSfk75ql+Xh3_`XQ-ie@Yn379@O=}@ z)xCIrZk_%|9{fr^`n#V;Ijx`nG3H@1ERQ~pPiXdUnaDzASk{96@Kycq2Jn4Q_D_1} z$L7P>JW8BcN^gU(XYSw^N;bI8snoqdk zQJr2v6AI=0=@#%~Lwn%8L#B?pfR{_@D{qaS+6fJADMATp+(G6ua0$>mS-^+3GBOJlL1C6T}Vt^e$ zP89j>{VV%RCxk$6Q(GdU=~f7h>3W9o(dTWDiA`45$tdU^Y^TSmZqvn$}nR3!SM4{H7}8wNNgSoghTu}_||UY z{;yj_QHYRtDU^WIx&BO^&Lx%}>v?Mz53eP5a3Zek9X=cj;hQ_7G{TA{iH)tO#!Ix! zTKrOyDzYg8gACW$z-kE?p&X9sy2x*^jA}xaQJVB6pXZ+GD45*yK5l=8C;hO;bI0-} z2G~!7)q)Ts?_yPcn#R7MjCZ?@sxHA8`cMllE5^BrU_s<svpg-~iX}2O6 zZxbVI+^59a{7psZS^4|%VTH@=S57RAsaGv&fu?+k*aKtb;+l4bzpndg#krn$!p9~? z=~tVyUoD;XajFztyw3&C_jt7R7a9YMq6^Vu+&nzC2ZGAp0MYg z0S~9Un?ybe;9f(41=?>ZNl|YRgyed2ubEaUt=Zb45dd&PpJx&9c?NjKRa1hvMu-Nx zKsS6*-2jirQrKI#cxOq_5|n9sm&E?)n0x-~xwTV1Vb0gLFlZ#4F1J_bp%{T;>4oBH z3=8e>`)SU$FV;ILYSi`9J&Tyv3vyDcVTL=7QQZHQu5DvwBSi$+An~cdnI0Az{=~&P z;1m#pElaY0PGVnUg3+Tv9OzCOPyC&zR*kVV)mJodjnp*R8tZvsS+d*+3`{cTK8MDy z9Q9WV^padbR4m(aXFuj0L&YQwQ}3?~$!0dy+{WIwL|LkX_x$-Gog~yJk9*Dak2wt8 z%3XITy4ajN^DVwQhb%( zx5B@j`M6v5!8}|10Bcf~(QcJBNm)Tk8ztHOQ}4Q{LzWV*VaBy|*pZ~*hISM)bLO}; z;q`6G^KbW%ngheWCq+Q7Y_aCd?1RO7Uobg4Zs~fH9GpIjIO5tb9=acdwz;REi{?b! zu9T3GKOddisK@d!gmmz#Wc6&f?}<;Rj}~KgcB{{Uvb=zSod?7Ya*TChJ{G{+wxDu5 zn7U$S`7Plo6A7J)_@R4kH~(W;mvh*K@`i%icT5T>PRGdu$lHpF1k^!NWh#=J#C-QA zf7MQ4Ch`+amj9FHW)zu$vH#Z-vHoovx-zDdo{a*EW;@FKG~Tw-VmHMBTlMXUqgT(j zdeiJjdW;{MFmoLnV5RBWT5pR4nBbFS)QB1PpM3!ts-d`1JHYUB*G~xowNud+ zrfFBtI>yxxD#L2-6BhsXIhXnVjtC!+QjuzMvmnbULSGkk@pB$dT!@k?<`9y4O(+8H zPWdXrvL%rN%p7~rz~O8XH;<#?7dEvQ3wIBYkugd6-vtr

7hSx!dS&s~|_Qu+Qkq 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 E1(J6e`2YX_ literal 0 HcmV?d00001 diff --git a/tools/terrain/sampleYaml.yaml b/tools/terrain/NREL.yaml similarity index 65% rename from tools/terrain/sampleYaml.yaml rename to tools/terrain/NREL.yaml index 60120dd8e3..5d8722a657 100644 --- a/tools/terrain/sampleYaml.yaml +++ b/tools/terrain/NREL.yaml @@ -6,25 +6,24 @@ caseInitial: "amr" domainType: "center" centerLat: 39.90613 centerLon: -105.216 -refHeight: 2184 -west: 15000 -east: 15000 -south: 15000 -north: 15000 -purgeCorners: 100 +west: 10000 +east: 10000 +south: 20000 +north: 20000 +refHeight: 2000 cellSize: 128 verticalAR: 4 -terrainSize: 90 timeMethod: "step" -numOfSteps: 10000 -plotOutput: 5000 -restartOutput: 2000 +numOfSteps: 5000 +plotOutput: 1000 +restartOutput: 1000 windX: 10.0 windY: 0.0 windZ: 0.0 refTemperature: 300.0 refRoughness: 0.1 refHeatflux: 0.0 -refLat: 90.0 -refPeriod: 125663.706143592 +refLat: 39.90613 +refPeriod: 86164.0900027328 +includeCoriolis: true turbineMarkType: "database" \ No newline at end of file diff --git a/tools/terrain/backendInterface.py b/tools/terrain/backendInterface.py index e941d29617..4a4a2f8ec3 100644 --- a/tools/terrain/backendInterface.py +++ b/tools/terrain/backendInterface.py @@ -35,7 +35,7 @@ def createCase(self): caseTerrain=Path(self.caseParent,self.caseName,"terrainTurbine") self.caseTerrain=caseTerrain.as_posix() caseTerrain.mkdir(parents=True,exist_ok=True) - self.caseDomainType=self.yamlFile['domainType'] + #self.caseDomainType=self.yamlFile['domainType'] # if(self.caseDomainType=="corners"): # pass self.caseNorth=self.yamlFile['north'] @@ -151,11 +151,14 @@ def createAMRGeometry(self,target,periodic=-1): minZ=np.amin(self.terrainX3) maxX=np.amax(self.terrainX1) maxY=np.amax(self.terrainX2) - terrainZMax=np.amax(self.terrainX3) - # Add 3 km for Rayleigh - maxZ=terrainZMax+2000+3000 + self.terrainZMax=np.amax(self.terrainX3) + # Add 1 km for ABL and 4 km for Rayleigh + self.ABLHeight=1000 + self.RDLHeight=2000 + self.maxZ=self.terrainZMax+self.ABLHeight+self.RDLHeight + self.maxZ=round(self.maxZ,-3) target.write("geometry.prob_lo \t\t\t = %g %g %g \n"%(minX,minY,minZ)) - target.write("geometry.prob_hi \t\t\t = %g %g %g \n"%(maxX,maxY,maxZ)) + target.write("geometry.prob_hi \t\t\t = %g %g %g \n"%(maxX,maxY,self.maxZ)) if(periodic==1): target.write("geometry.is_periodic \t\t\t = 1 1 0\n") else: @@ -170,16 +173,17 @@ def createAMRGrid(self,target): while (ny%8 !=0): ny=ny+1 # Keeping the vertical height to account for gravity waves - terrainZMax=np.amax(self.terrainX3) - # Add 3 km for Rayleigh - zDomainHeight=terrainZMax+2000+3000 - print("Terrain Maximum Height:",terrainZMax) - print("Domain Height:",zDomainHeight) + # terrainZMax=np.amax(self.terrainX3) + # # Add 4 km for Rayleigh + # zDomainHeight=terrainZMax+4000+4000 + # zDomainHeight=zDomainHeight-(zDomainHeight%1000) + # print("Terrain Maximum Height:",terrainZMax) + # print("Domain Height:",zDomainHeight) self.caseverticalAR=self.yamlFile['verticalAR'] - nz=self.caseverticalAR*int(zDomainHeight/self.caseCellSize) + nz=self.caseverticalAR*int(self.maxZ/self.caseCellSize) while (nz%8 !=0): nz=nz+1 - print("dx,dz",self.caseCellSize,zDomainHeight/nz) + print("dx,dz",self.caseCellSize,self.maxZ/nz) target.write("# Grid \n") target.write("amr.n_cell \t\t\t = %g %g %g\n"%(nx,ny,nz)) target.write("amr.max_level \t\t\t = 0\n") @@ -194,7 +198,7 @@ def createAMRTime(self,target): self.restartOutput=self.yamlFile['restartOutput'] target.write("time.stop_time \t\t\t = -1\n") target.write("time.max_step \t\t\t = %g\n"%(self.timeSteps)) - target.write("time.initial_dt \t\t\t = 0.1\n") + target.write("time.initial_dt \t\t\t = 1.0\n") target.write("time.fixed_dt \t\t\t = -1\n") target.write("time.cfl \t\t\t = 0.9\n") target.write('time.plot_interval \t\t\t = %g\n'%(self.plotOutput)) @@ -258,31 +262,13 @@ def createAMRABLData(self,target,iomode=-1,fluctuations=1): target.write("ABL.stats_output_format \t\t\t = netcdf\n") target.write("ABL.surface_roughness_z0 \t\t\t = %g\n"%(self.refRoughness)) # Write Heights - target.write("ABL.temperature_heights = 0 ") #750 850 1850 2850 3850 4850\n") - invLayer=750 - target.write(" %g %g "%(np.amax(self.terrainX3),np.amax(self.terrainX3)+invLayer)) - invLayerWidth=100 - target.write(" %g "%(np.amax(self.terrainX3)+invLayer+invLayerWidth)) - zstart=np.amax(self.terrainX3)+invLayer+invLayerWidth+1000 - while(zstart<10000): - target.write(" %g "%(zstart)) - zstart+=1000 - #target.write("ABL.temperature_values \t\t\t = 300 300 308 311 314 317 321\n") - target.write("\n") + inversionHeight=round(self.terrainZMax,-3)+1000 + inversionLayerThickness=round(self.terrainZMax,-3)+1000+100 + lapseRate=0.003 + target.write("ABL.temperature_heights = %g %g %g %g %g \n"%(0.0,round(self.terrainZMax,-3),inversionHeight,inversionLayerThickness,self.maxZ)) TRef=300 - target.write("ABL.temperature_values = %g "%(TRef)) - invLayer=750 - target.write(" %g %g "%(TRef,TRef)) - invStrength=8 - target.write(" %g "%(TRef+invStrength)) - zstart=np.amax(self.terrainX3)+invLayer+invLayerWidth+1000 - lapseRate=3.0 # Per km - TRef=TRef+invStrength+lapseRate - zstart=np.amax(self.terrainX3)+invLayer+invLayerWidth+1000 - while(zstart<10000): - target.write(" %g "%(TRef)) - zstart+=1000 - TRef+=3 + print(self.maxZ-inversionLayerThickness) + target.write("ABL.temperature_values = %g %g %g %g %g "%(TRef,TRef,TRef,TRef+5,TRef+5+lapseRate*(self.maxZ-inversionLayerThickness))) target.write("\n") target.write("ABL.wall_shear_stress_type \t\t\t = local\n") target.write("ABL.surface_temp_flux \t\t\t = %g\n"%(self.refHeatFlux)) @@ -315,22 +301,62 @@ def createAMRSourceTerm(self,target,terrain=-1,turbine=-1): target.write("# Source\n") refLat=self.yamlFile["refLat"] refPeriod=self.yamlFile["refPeriod"] - if(terrain==1 and turbine==1): - target.write("ICNS.source_terms \t\t\t = BoussinesqBuoyancy CoriolisForcing GeostrophicForcing RayleighDamping NonLinearSGSTerm DragForcing ActuatorForcing \n") - elif(terrain==1): - target.write("ICNS.source_terms \t\t\t = BoussinesqBuoyancy CoriolisForcing GeostrophicForcing RayleighDamping NonLinearSGSTerm DragForcing\n") + try: + self.includeCoriolis=self.yamlFile["includeCoriolis"] + except: + self.includeCoriolis=False + if(self.includeCoriolis): + try: + self.forcingHeight=self.yamlFile["forcingHeight"] + except: + if(terrain==1 and turbine==1): + target.write("ICNS.source_terms \t\t\t = BoussinesqBuoyancy CoriolisForcing GeostrophicForcing RayleighDamping NonLinearSGSTerm DragForcing ActuatorForcing \n") + elif(terrain==1): + target.write("ICNS.source_terms \t\t\t = BoussinesqBuoyancy CoriolisForcing GeostrophicForcing RayleighDamping NonLinearSGSTerm DragForcing\n") + else: + target.write("ICNS.source_terms \t\t\t = BoussinesqBuoyancy CoriolisForcing GeostrophicForcing RayleighDamping NonLinearSGSTerm\n") + target.write("GeostrophicForcing.geostrophic_wind \t\t\t = %g %g %g\n"%(self.caseWindspeedX,self.caseWindspeedY,self.caseWindspeedZ)) + else: + if(terrain==1 and turbine==1): + target.write("ICNS.source_terms \t\t\t = BoussinesqBuoyancy CoriolisForcing ABLForcing RayleighDamping NonLinearSGSTerm DragForcing ActuatorForcing \n") + elif(terrain==1): + target.write("ICNS.source_terms \t\t\t = BoussinesqBuoyancy CoriolisForcing ABLForcing RayleighDamping NonLinearSGSTerm DragForcing\n") + else: + target.write("ICNS.source_terms \t\t\t = BoussinesqBuoyancy CoriolisForcing ABLForcing RayleighDamping NonLinearSGSTerm\n") + target.write("ABLForcing.abl_forcing_height \t\t\t = %g \n"%(self.forcingHeight)) else: - target.write("ICNS.source_terms \t\t\t = BoussinesqBuoyancy CoriolisForcing GeostrophicForcing RayleighDamping NonLinearSGSTerm\n") + try: + self.forcingHeight=self.yamlFile["forcingHeight"] + except: + if(terrain==1 and turbine==1): + target.write("ICNS.source_terms \t\t\t = BoussinesqBuoyancy GeostrophicForcing RayleighDamping NonLinearSGSTerm DragForcing ActuatorForcing \n") + elif(terrain==1): + target.write("ICNS.source_terms \t\t\t = BoussinesqBuoyancy GeostrophicForcing RayleighDamping NonLinearSGSTerm DragForcing\n") + else: + target.write("ICNS.source_terms \t\t\t = BoussinesqBuoyancy GeostrophicForcing RayleighDamping NonLinearSGSTerm\n") + target.write("GeostrophicForcing.geostrophic_wind \t\t\t = %g %g %g\n"%(self.caseWindspeedX,self.caseWindspeedY,self.caseWindspeedZ)) + else: + if(terrain==1 and turbine==1): + target.write("ICNS.source_terms \t\t\t = BoussinesqBuoyancy ABLForcing RayleighDamping NonLinearSGSTerm DragForcing ActuatorForcing \n") + elif(terrain==1): + target.write("ICNS.source_terms \t\t\t = BoussinesqBuoyancy ABLForcing RayleighDamping NonLinearSGSTerm DragForcing\n") + else: + target.write("ICNS.source_terms \t\t\t = BoussinesqBuoyancy ABLForcing RayleighDamping NonLinearSGSTerm\n") + target.write("ABLForcing.abl_forcing_height \t\t\t = %g \n"%(self.forcingHeight)) + if(terrain==1 or turbine==1): + target.write("Temperature.source_terms = DragTempForcing\n") + target.write("RayleighDamping.force_coord_directions= 0 0 1\n") target.write("BoussinesqBuoyancy.reference_temperature \t\t\t = %g\n"%(self.refTemperature)) target.write("BoussinesqBuoyancy.thermal_expansion_coeff \t\t\t = %g\n"%(1.0/self.refTemperature)) - target.write("CoriolisForcing.east_vector \t\t\t = 1.0 0.0 0.0 \n") - target.write("CoriolisForcing.north_vector \t\t\t = 0.0 1.0 0.0 \n") - target.write("CoriolisForcing.latitude \t\t\t = %g \n"%(refLat)) - target.write("CoriolisForcing.rotational_time_period \t\t\t = %g \n"%(refPeriod)) - target.write("GeostrophicForcing.geostrophic_wind \t\t\t = %g %g %g\n"%(self.caseWindspeedX,self.caseWindspeedY,self.caseWindspeedZ)) + if(self.includeCoriolis): + target.write("CoriolisForcing.east_vector \t\t\t = 1.0 0.0 0.0 \n") + target.write("CoriolisForcing.north_vector \t\t\t = 0.0 1.0 0.0 \n") + target.write("CoriolisForcing.latitude \t\t\t = %g \n"%(refLat)) + target.write("CoriolisForcing.rotational_time_period \t\t\t = %g \n"%(refPeriod)) target.write("RayleighDamping.reference_velocity \t\t\t = %g %g %g\n"%(self.caseWindspeedX,self.caseWindspeedY,self.caseWindspeedZ)) - target.write("RayleighDamping.length_sloped_damping \t\t\t = 500\n") - target.write("RayleighDamping.length_complete_damping \t\t\t = 2500\n") + startRayleigh=self.maxZ-self.RDLHeight + target.write("RayleighDamping.length_sloped_damping \t\t\t = %g\n"%(500)) + target.write("RayleighDamping.length_complete_damping \t\t\t = %g\n"%(self.maxZ-startRayleigh-500)) target.write("RayleighDamping.time_scale \t\t\t = 20.0\n") def createAMRBC(self,target,inflowOutflow=-1): @@ -403,7 +429,10 @@ def createAMRPrecursorSampling(self,target): def metMastRefinement(self,target): # Read Met Mast - latList=self.yamlFile['metMastLat'] + try: + latList=self.yamlFile['metMastLat'] + except: + return lonList=self.yamlFile['metMastLon'] metMastHeight=self.yamlFile['metMastHeight'] print(latList,len(latList)) @@ -608,9 +637,11 @@ def writeRestart(self,target): def createTurbineFiles(self): print("Creating Turbines") - latmin,lonmin=self.srtm.to_latlon(self.terrainX1[0,0],self.terrainX2[0,0]) - latmax,lonmax=self.srtm.to_latlon(self.terrainX1[self.terrainX1.shape[0]-1,self.terrainX1.shape[1]-1], \ - self.terrainX2[self.terrainX1.shape[0]-1,self.terrainX1.shape[1]-1]) + latmin,lonmin=self.srtm.to_latlon(self.xref-abs(np.amin(self.terrainX1)),self.yref-abs(np.amin(self.terrainX2))) + latmax,lonmax=self.srtm.to_latlon(np.amax(self.terrainX1)+self.xref,np.amax(self.terrainX2)+self.yref) + print(self.xref,self.yref) + print(latmin,lonmin) + print(latmax,lonmax) self.turbineMarkType=self.yamlFile['turbineMarkType'] if(self.turbineMarkType=='database'): xmin=latmin+0.01 @@ -634,7 +665,7 @@ def createTurbineFiles(self): index=index+1 self.caseTurbineLat.append(lat[i]) self.caseTurbineLon.append(lon[i]) - #print(xmin,xmax,lat[i],ymin,ymax,lon[i]) + print(xmin,xmax,lat[i],ymin,ymax,lon[i]) target=Path(self.caseParent,self.caseName,"terrainTurbine","turbineLabels.info").open("w") target.write("Actuator.labels =") index=0 @@ -806,8 +837,8 @@ def plotTurbines(self): pl = pv.Plotter() mesh2=pv.PolyData(data) mesh2['elevation']=data[:,2] - surf = mesh2.delaunay_2d() - pl.add_mesh(surf) + #surf = mesh2.delaunay_2d() + #pl.add_mesh(surf) for i in range(0,len(self.turbineX1)): print("Plotting turbine",i+1) newDisk=pv.Disc(center=(self.turbineX1[i],self.turbineX2[i],self.turbineX3[i]+80),inner=8,outer=50,normal=(1.0, 0.0,0.0), r_res=1, c_res=24) diff --git a/tools/terrain/saveTurbines.py b/tools/terrain/saveTurbines.py deleted file mode 100644 index e05ed9b799..0000000000 --- a/tools/terrain/saveTurbines.py +++ /dev/null @@ -1,26 +0,0 @@ -import pyvista as pv -print("Plotting Turbines") -x1=self.terrainX1.flatten(order='F') -x2=self.terrainX2.flatten(order='F') -x3=self.terrainX3.flatten(order='F') -data=np.column_stack([x1,x2,x3]) -for i in range(0,len(self.turbineX1)): - print("Plotting turbine",i+1) - newDisk=pv.Disc(center=(self.turbineX1[i],self.turbineX2[i],self.turbineX3[i]+80),inner=8,outer=50,normal=(1.0, 0.0,0.0), r_res=1, c_res=24) - #pl.add_mesh(newDisk) - if(i==0): - globalBox=newDisk - else: - localBox=newDisk - tempbox=globalBox.merge([localBox]) - globalBox=tempbox -for i in range(0,len(self.turbineX3)): - self.turbineX3[i]+=80 -data=np.column_stack([self.turbineX1,self.turbineX2,self.turbineX3]) -mesh1=pv.PolyData(data) -pl.add_mesh(mesh1,render_points_as_spheres=True,point_size=10) -tempFile=Path(self.caseParent,self.caseName,"terrainTurbine","turbines.vtk") -pv.save_meshio(tempFile.as_posix(),globalBox) -pl.view_xy() -pl.show_axes() -pl.show() \ No newline at end of file From 2473677b68e9efa145a36b3e67c07c0f8784be86 Mon Sep 17 00:00:00 2001 From: hgopalan Date: Mon, 8 Jul 2024 17:26:37 -0600 Subject: [PATCH 41/77] Commit to address some nomenclature changes and moving python files --- .../icns/source_terms/DragForcing.H | 12 +- .../icns/source_terms/DragForcing.cpp | 101 +++---- .../source_terms/DragTempForcing.cpp | 8 +- amr-wind/physics/TerrainDrag.H | 12 +- amr-wind/physics/TerrainDrag.cpp | 51 ++-- amr-wind/turbulence/LES/Kosovic.cpp | 2 +- test/CMakeLists.txt | 4 +- test/test_files/nrel_terrain/README | 6 - test/test_files/nrel_terrain/nrelterrain.png | Bin 301384 -> 0 bytes test/test_files/terrainbox/README | 6 - tools/terrain/SRTM_to_STL_example.py | 267 +----------------- .../terrain}/computeError.py | 0 .../terrain}/createTerrain.py | 0 13 files changed, 98 insertions(+), 371 deletions(-) delete mode 100644 test/test_files/nrel_terrain/README delete mode 100644 test/test_files/nrel_terrain/nrelterrain.png delete mode 100644 test/test_files/terrainbox/README rename {test/test_files/terrainbox => tools/terrain}/computeError.py (100%) rename {test/test_files/terrainbox => tools/terrain}/createTerrain.py (100%) diff --git a/amr-wind/equation_systems/icns/source_terms/DragForcing.H b/amr-wind/equation_systems/icns/source_terms/DragForcing.H index ff74503bad..45cb178e79 100644 --- a/amr-wind/equation_systems/icns/source_terms/DragForcing.H +++ b/amr-wind/equation_systems/icns/source_terms/DragForcing.H @@ -33,13 +33,13 @@ private: const CFDSim& m_sim; const amrex::AmrCore& m_mesh; const Field& m_velocity; - amrex::Gpu::DeviceVector gpu_vel_ht; - amrex::Gpu::DeviceVector gpu_vel_vals; + amrex::Gpu::DeviceVector device_vel_ht; + amrex::Gpu::DeviceVector device_vel_vals; amrex::Real m_drag{100.0}; - amrex::Real m_spongeStrength{1.0}; - amrex::Real m_spongeDensity{1.0}; - amrex::Real m_spongeDistanceX{1000}; - amrex::Real m_spongeDistanceY{1000}; + amrex::Real m_sponge_strength{1.0}; + amrex::Real m_sponge_density{1.0}; + amrex::Real m_sponge_distanceX{1000}; + amrex::Real m_sponge_distanceY{1000}; }; } // namespace amr_wind::pde::icns diff --git a/amr-wind/equation_systems/icns/source_terms/DragForcing.cpp b/amr-wind/equation_systems/icns/source_terms/DragForcing.cpp index 67920dd501..ca376d144c 100644 --- a/amr-wind/equation_systems/icns/source_terms/DragForcing.cpp +++ b/amr-wind/equation_systems/icns/source_terms/DragForcing.cpp @@ -5,6 +5,7 @@ #include "AMReX_Random.H" #include "amr-wind/wind_energy/ABL.H" + namespace amr_wind::pde::icns { DragForcing::DragForcing(const CFDSim& sim) @@ -13,26 +14,26 @@ DragForcing::DragForcing(const CFDSim& sim) , m_velocity(sim.repo().get_field("velocity")) { amrex::ParmParse pp("DragForcing"); - pp.query("dragCoefficient", m_drag); - pp.query("spongeStrength", m_spongeStrength); - pp.query("spongeDensity", m_spongeDensity); - pp.query("spongeDistanceX", m_spongeDistanceX); - pp.query("spongeDistanceY", m_spongeDistanceY); + pp.query("drag_coefficient", m_drag); + pp.query("sponge_strength", m_sponge_strength); + pp.query("sponge_density", m_sponge_density); + pp.query("sponge_distanceX", m_sponge_distanceX); + pp.query("sponge_distanceY", m_sponge_distanceY); const auto& phy_mgr = m_sim.physics_manager(); if (phy_mgr.contains("ABL")) { const auto& abl = m_sim.physics_manager().get(); const VelPlaneAveraging& fa_velocity = abl.abl_statistics().vel_profile_coarse(); - gpu_vel_ht.resize(fa_velocity.line_centroids().size()); - gpu_vel_vals.resize(fa_velocity.line_average().size()); + device_vel_ht.resize(fa_velocity.line_centroids().size()); + device_vel_vals.resize(fa_velocity.line_average().size()); amrex::Gpu::copy( amrex::Gpu::hostToDevice, fa_velocity.line_centroids().begin(), - fa_velocity.line_centroids().end(), gpu_vel_ht.begin()); + fa_velocity.line_centroids().end(), device_vel_ht.begin()); amrex::Gpu::copy( amrex::Gpu::hostToDevice, fa_velocity.line_average().begin(), - fa_velocity.line_average().end(), gpu_vel_vals.begin()); + fa_velocity.line_average().end(), device_vel_vals.begin()); } else { - m_spongeStrength = 0.0; + m_sponge_strength = 0.0; } } @@ -47,14 +48,14 @@ void DragForcing::operator()( { const auto& vel = m_velocity.state(field_impl::dof_state(fstate))(lev).const_array(mfi); - bool is_terrain = this->m_sim.repo().field_exists("terrainBlank"); + const bool is_terrain = this->m_sim.repo().field_exists("terrainBlank"); if (!is_terrain) { amrex::Abort("Need terrain blanking variable to use this source term"); } - auto* const m_terrainBlank = &this->m_sim.repo().get_field("terrainBlank"); - const auto& blank = (*m_terrainBlank)(lev).const_array(mfi); - auto* const m_terrainDrag = &this->m_sim.repo().get_field("terrainDrag"); - const auto& drag = (*m_terrainDrag)(lev).const_array(mfi); + auto* const m_terrain_blank = &this->m_sim.repo().get_field("terrainBlank"); + const auto& blank = (*m_terrain_blank)(lev).const_array(mfi); + auto* const m_terrain_drag = &this->m_sim.repo().get_field("terrainDrag"); + const auto& drag = (*m_terrain_drag)(lev).const_array(mfi); auto* const m_terrainz0 = &this->m_sim.repo().get_field("terrainz0"); const auto& terrainz0 = (*m_terrainz0)(lev).const_array(mfi); const auto& geom_vec = m_mesh.Geom(); @@ -62,53 +63,53 @@ void DragForcing::operator()( const auto& dx = geom.CellSize(); const auto& prob_lo = geom.ProbLoArray(); const auto& prob_hi = geom.ProbHiArray(); - const amrex::Real gpu_drag = m_drag; - const amrex::Real gpu_spongeStrength = m_spongeStrength; - const amrex::Real gpu_spongeDensity = m_spongeDensity; - const amrex::Real gpu_startX = (m_spongeDistanceX > 0) - ? prob_hi[0] - m_spongeDistanceX - : prob_lo[0] - m_spongeDistanceX; - const amrex::Real gpu_startY = (m_spongeDistanceY > 0) - ? prob_hi[1] - m_spongeDistanceY - : prob_lo[1] - m_spongeDistanceY; - const amrex::Real gpu_spongeX = (m_spongeDistanceX > 0) ? 1 : 0; - const amrex::Real gpu_spongeY = (m_spongeDistanceY > 0) ? 1 : 0; + const amrex::Real device_drag = m_drag; + const amrex::Real device_sponge_strength = m_sponge_strength; + const amrex::Real device_sponge_density = m_sponge_density; + const amrex::Real device_startX = (m_sponge_distanceX > 0) + ? prob_hi[0] - m_sponge_distanceX + : prob_lo[0] - m_sponge_distanceX; + const amrex::Real device_startY = (m_sponge_distanceY > 0) + ? prob_hi[1] - m_sponge_distanceY + : prob_lo[1] - m_sponge_distanceY; + const unsigned device_spongeX = (m_sponge_distanceX > 0) ? 1 : 0; + const unsigned device_spongeY = (m_sponge_distanceY > 0) ? 1 : 0; // Copy Data - const auto* local_gpu_vel_ht = gpu_vel_ht.data(); - const auto* local_gpu_vel_vals = gpu_vel_vals.data(); - const unsigned vsize = gpu_vel_ht.size(); + const auto* local_device_vel_ht = device_vel_ht.data(); + const auto* local_device_vel_vals = device_vel_vals.data(); + const unsigned vsize = device_vel_ht.size(); amrex::ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept { const amrex::Real x1 = prob_lo[0] + (i + 0.5) * dx[0]; const amrex::Real x2 = prob_lo[1] + (j + 0.5) * dx[1]; const amrex::Real x3 = prob_lo[2] + (k + 0.5) * dx[2]; amrex::Real xdamping = 0; amrex::Real ydamping = 0; - amrex::Real xi = (gpu_spongeX == 1) - ? (x1 - gpu_startX) / (prob_hi[0] - gpu_startX) - : (gpu_startX - x1) / (gpu_startX - prob_lo[0]); + amrex::Real xi = (device_spongeX == 1) + ? (x1 - device_startX) / (prob_hi[0] - device_startX) + : (device_startX - x1) / (device_startX - prob_lo[0]); xi = std::max(xi, 0.0); - xdamping = gpu_spongeStrength * xi * xi; - amrex::Real yi = (gpu_spongeY == 1) - ? (x2 - gpu_startY) / (prob_hi[1] - gpu_startY) - : (gpu_startY - x2) / (gpu_startY - prob_lo[1]); + xdamping = device_sponge_strength * xi * xi; + amrex::Real yi = (device_spongeY == 1) + ? (x2 - device_startY) / (prob_hi[1] - device_startY) + : (device_startY - x2) / (device_startY - prob_lo[1]); yi = std::max(yi, 0.0); - ydamping = gpu_spongeStrength * yi * yi; - amrex::Real Cd = gpu_drag / dx[0]; - amrex::Real gpu_spongeVelX = 0.0; - amrex::Real gpu_spongeVelY = 0.0; - amrex::Real gpu_spongeVelZ = 0.0; + ydamping = device_sponge_strength * yi * yi; + const amrex::Real Cd = device_drag / dx[0]; + amrex::Real device_spongeVelX = 0.0; + amrex::Real device_spongeVelY = 0.0; + amrex::Real device_spongeVelZ = 0.0; amrex::Real residual = 1000; amrex::Real height_error = 0.0; for (unsigned ii = 0; ii < vsize; ++ii) { - height_error = std::abs(x3 - local_gpu_vel_ht[ii]); + height_error = std::abs(x3 - local_device_vel_ht[ii]); if (height_error < residual) { residual = height_error; const unsigned ix = 3 * ii; const unsigned iy = 3 * ii + 1; const unsigned iz = 3 * ii + 2; - gpu_spongeVelX = local_gpu_vel_vals[ix]; - gpu_spongeVelY = local_gpu_vel_vals[iy]; - gpu_spongeVelZ = local_gpu_vel_vals[iz]; + device_spongeVelX = local_device_vel_vals[ix]; + device_spongeVelY = local_device_vel_vals[iy]; + device_spongeVelZ = local_device_vel_vals[iz]; } } // Terrain Drag @@ -125,7 +126,7 @@ void DragForcing::operator()( const amrex::Real m2 = std::sqrt(ux2 * ux2 + uy2 * uy2); const amrex::Real kappa = 0.41; const amrex::Real z0 = std::max(terrainz0(i, j, k), 1e-4); - const amrex::Real ustar = std::min(gpu_spongeStrength, 1.0) * + const amrex::Real ustar = std::min(device_sponge_strength, 1.0) * std::abs(m2 - m1) * kappa / std::log((x3 + z0) / z0); Dxz = -ustar * ustar * ux1 / @@ -134,19 +135,19 @@ void DragForcing::operator()( (1e-5 + std::sqrt(ux1 * ux1 + uy1 * uy1)) / dx[2]; } // Adjusting Cd for momentum - amrex::Real CdM = std::min(Cd / (m + 1e-5), 1000.0); + const amrex::Real CdM = std::min(Cd / (m + 1e-5), 1000.0); src_term(i, j, k, 0) -= (CdM * m * ux1 * blank(i, j, k) + Dxz * drag(i, j, k) + (xdamping + ydamping) * - (ux1 - gpu_spongeDensity * gpu_spongeVelX)); + (ux1 - device_sponge_density * device_spongeVelX)); src_term(i, j, k, 1) -= (CdM * m * uy1 * blank(i, j, k) + Dyz * drag(i, j, k) + (xdamping + ydamping) * - (uy1 - gpu_spongeDensity * gpu_spongeVelY)); + (uy1 - device_sponge_density * device_spongeVelY)); src_term(i, j, k, 2) -= (CdM * m * uz1 * blank(i, j, k) + (xdamping + ydamping) * - (uz1 - gpu_spongeDensity * gpu_spongeVelZ)); + (uz1 - device_sponge_density * device_spongeVelZ)); }); } diff --git a/amr-wind/equation_systems/temperature/source_terms/DragTempForcing.cpp b/amr-wind/equation_systems/temperature/source_terms/DragTempForcing.cpp index 169a3269f4..4935841f6e 100644 --- a/amr-wind/equation_systems/temperature/source_terms/DragTempForcing.cpp +++ b/amr-wind/equation_systems/temperature/source_terms/DragTempForcing.cpp @@ -27,19 +27,19 @@ void DragTempForcing::operator()( const amrex::Array4& src_term) const { const auto temperature = m_temperature(lev).const_array(mfi); - bool is_terrain = this->m_sim.repo().field_exists("terrainBlank"); + const bool is_terrain = this->m_sim.repo().field_exists("terrainBlank"); if (!is_terrain) { amrex::Abort("Need terrain blanking variable to use this source term"); } - auto* const m_terrainBlank = &this->m_sim.repo().get_field("terrainBlank"); - const auto& blank = (*m_terrainBlank)(lev).const_array(mfi); + auto* const m_terrain_blank = &this->m_sim.repo().get_field("terrainBlank"); + const auto& blank = (*m_terrain_blank)(lev).const_array(mfi); const auto& geom_vec = m_mesh.Geom(); const auto& geom = geom_vec[lev]; const auto& dx = geom.CellSize(); const amrex::Real gpu_drag = m_drag; const amrex::Real gpu_TRef = m_internalRefT; amrex::ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept { - amrex::Real Cd = gpu_drag / dx[0]; + const amrex::Real Cd = gpu_drag / dx[0]; src_term(i, j, k, 0) -= (Cd * (temperature(i, j, k, 0) - gpu_TRef) * blank(i, j, k)); }); diff --git a/amr-wind/physics/TerrainDrag.H b/amr-wind/physics/TerrainDrag.H index 6f7c7d27db..351febe5c7 100644 --- a/amr-wind/physics/TerrainDrag.H +++ b/amr-wind/physics/TerrainDrag.H @@ -44,16 +44,20 @@ private: const amrex::AmrCore& m_mesh; Field& m_velocity; // Blanking Field for Terrain or Buildings - Field& m_terrainBlank; + Field& m_terrain_blank; // Terrain Drag Force Term - Field& m_terrainDrag; + Field& m_terrain_drag; // Reading the Terrain Coordinates from file - amrex::Vector m_xterrain, m_yterrain, m_zterrain; + amrex::Vector m_xterrain; + amrex::Vector m_yterrain; + amrex::Vector m_zterrain; // Roughness Field Field& m_terrainz0; // Reading the Roughness Coordinates from file - Not Fully there yet // Need updates to ABLWallFunction in future - amrex::Vector m_xrough, m_yrough, m_z0rough; + amrex::Vector m_xrough; + amrex::Vector m_yrough; + amrex::Vector m_z0rough; }; } // namespace amr_wind::terraindrag diff --git a/amr-wind/physics/TerrainDrag.cpp b/amr-wind/physics/TerrainDrag.cpp index de923d8d2d..2be61067f3 100644 --- a/amr-wind/physics/TerrainDrag.cpp +++ b/amr-wind/physics/TerrainDrag.cpp @@ -16,8 +16,8 @@ TerrainDrag::TerrainDrag(CFDSim& sim) , m_repo(sim.repo()) , m_mesh(sim.mesh()) , m_velocity(sim.repo().get_field("velocity")) - , m_terrainBlank(sim.repo().declare_field("terrainBlank", 1, 1, 1)) - , m_terrainDrag(sim.repo().declare_field("terrainDrag", 1, 1, 1)) + , m_terrain_blank(sim.repo().declare_field("terrainBlank", 1, 1, 1)) + , m_terrain_drag(sim.repo().declare_field("terrainDrag", 1, 1, 1)) , m_terrainz0(sim.repo().declare_field("terrainz0", 1, 1, 1)) { std::string terrainfile("terrain.amrwind"); @@ -56,41 +56,41 @@ void TerrainDrag::post_init_actions() const auto& dx = geom.CellSizeArray(); const auto& prob_lo = geom.ProbLoArray(); auto& velocity = m_velocity(level); - auto& blanking = m_terrainBlank(level); + auto& blanking = m_terrain_blank(level); auto& terrainz0 = m_terrainz0(level); - auto& drag = m_terrainDrag(level); + auto& drag = m_terrain_drag(level); // copy terrain data to gpu - amrex::Gpu::DeviceVector gpu_xterrain(m_xterrain.size()); - amrex::Gpu::DeviceVector gpu_yterrain(m_xterrain.size()); - amrex::Gpu::DeviceVector gpu_zterrain(m_xterrain.size()); + amrex::Gpu::DeviceVector device_xterrain(m_xterrain.size()); + amrex::Gpu::DeviceVector device_yterrain(m_xterrain.size()); + amrex::Gpu::DeviceVector device_zterrain(m_xterrain.size()); amrex::Gpu::copy( amrex::Gpu::hostToDevice, m_xterrain.begin(), m_xterrain.end(), - gpu_xterrain.begin()); + device_xterrain.begin()); amrex::Gpu::copy( amrex::Gpu::hostToDevice, m_yterrain.begin(), m_yterrain.end(), - gpu_yterrain.begin()); + device_yterrain.begin()); amrex::Gpu::copy( amrex::Gpu::hostToDevice, m_zterrain.begin(), m_zterrain.end(), - gpu_zterrain.begin()); - const auto* xterrain_ptr = gpu_xterrain.data(); - const auto* yterrain_ptr = gpu_yterrain.data(); - const auto* zterrain_ptr = gpu_zterrain.data(); + device_zterrain.begin()); + const auto* xterrain_ptr = device_xterrain.data(); + const auto* yterrain_ptr = device_yterrain.data(); + const auto* zterrain_ptr = device_zterrain.data(); // Copy Roughness to gpu - amrex::Gpu::DeviceVector gpu_xrough(m_xrough.size()); - amrex::Gpu::DeviceVector gpu_yrough(m_xrough.size()); - amrex::Gpu::DeviceVector gpu_z0rough(m_xrough.size()); + amrex::Gpu::DeviceVector device_xrough(m_xrough.size()); + amrex::Gpu::DeviceVector device_yrough(m_xrough.size()); + amrex::Gpu::DeviceVector device_z0rough(m_xrough.size()); amrex::Gpu::copy( amrex::Gpu::hostToDevice, m_xrough.begin(), m_xrough.end(), - gpu_xrough.begin()); + device_xrough.begin()); amrex::Gpu::copy( amrex::Gpu::hostToDevice, m_yrough.begin(), m_yrough.end(), - gpu_yrough.begin()); + device_yrough.begin()); amrex::Gpu::copy( amrex::Gpu::hostToDevice, m_z0rough.begin(), m_z0rough.end(), - gpu_z0rough.begin()); - const auto* xrough_ptr = gpu_xrough.data(); - const auto* yrough_ptr = gpu_yrough.data(); - const auto* z0rough_ptr = gpu_z0rough.data(); + device_z0rough.begin()); + const auto* xrough_ptr = device_xrough.data(); + const auto* yrough_ptr = device_yrough.data(); + const auto* z0rough_ptr = device_z0rough.data(); for (amrex::MFIter mfi(velocity); mfi.isValid(); ++mfi) { const auto& vbx = mfi.validbox(); auto levelBlanking = blanking.array(mfi); @@ -119,8 +119,7 @@ void TerrainDrag::post_init_actions() break; } } - int turnOn = (x3 <= terrainHt) ? 1 : 0; - levelBlanking(i, j, k, 0) = turnOn; + levelBlanking(i, j, k, 0) = static_cast(x3 <= terrainHt); residual = 10000; amrex::Real roughz0 = 0.1; for (unsigned ii = 0; ii < roughnessSize; ++ii) { @@ -172,8 +171,8 @@ void TerrainDrag::pre_init_actions() int TerrainDrag::returnBlankValue(int i, int j, int k) { int lev = 0; - amrex::MFIter mfi(m_terrainBlank(lev)); - const auto& levelBlanking = m_terrainBlank(lev).const_array(mfi); + amrex::MFIter mfi(m_terrain_blank(lev)); + const auto& levelBlanking = m_terrain_blank(lev).const_array(mfi); return int(levelBlanking(i, j, k)); } diff --git a/amr-wind/turbulence/LES/Kosovic.cpp b/amr-wind/turbulence/LES/Kosovic.cpp index 59e930f3a2..fd1dfd7017 100644 --- a/amr-wind/turbulence/LES/Kosovic.cpp +++ b/amr-wind/turbulence/LES/Kosovic.cpp @@ -18,7 +18,7 @@ Kosovic::Kosovic(CFDSim& sim) , m_vel(sim.repo().get_field("velocity")) , m_rho(sim.repo().get_field("density")) , m_Nij(sim.repo().declare_field("Nij", 9, 1, 1)) - , m_divNij(sim.repo().declare_field("divNij", 3, 1, 1)) + , m_divNij(sim.repo().declare_field("divNij", 3)) { amrex::ParmParse pp("Kosovic"); pp.query("Cb", m_Cb); diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index d3f1f2cfde..a45a68b17f 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -243,8 +243,7 @@ add_test_re(abl_godunov_rayleigh_damping) add_test_re(rankine) add_test_re(rankine-sym) add_test_re(terrainbox) -add_test_re(nrel_precursor) -add_test_re(nrel_terrain) + if(NOT AMR_WIND_ENABLE_CUDA) add_test_re(ctv_godunov_plm) @@ -302,6 +301,7 @@ add_test_red(abl_godunov_restart abl_godunov) add_test_red(abl_bndry_input_amr_native abl_bndry_output_native) add_test_red(abl_bndry_input_amr_native_mlbc abl_bndry_output_amr_native) add_test_red(abl_godunov_forcetimetable abl_godunov_timetable) +add_test_red(nrel_precursor nrel_terrain) if(AMR_WIND_ENABLE_NETCDF) add_test_red(abl_bndry_input abl_bndry_output) diff --git a/test/test_files/nrel_terrain/README b/test/test_files/nrel_terrain/README deleted file mode 100644 index 841d14c502..0000000000 --- a/test/test_files/nrel_terrain/README +++ /dev/null @@ -1,6 +0,0 @@ -This is the sample terrain case. You need to run "python3.XX backendinterface.py NREL.yaml" in the tools/terrain folder. -The output of the python execution will be a file "terrain.amrwind". This file needs to be copied to this folder before -execution to avoid an error message. - -The python tool backendinterface.py generates both precursor and terrain case folders. Modify the NREL.yaml file to cater -to your needs and generate the cases. The terrain cases are designed to run with the Kosovic turbulence model. \ No newline at end of file diff --git a/test/test_files/nrel_terrain/nrelterrain.png b/test/test_files/nrel_terrain/nrelterrain.png deleted file mode 100644 index 963283af0d9b30738562d57dd787ae4475586c99..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 301384 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

9|+4xb(sDQ5dp(I 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

DD%ZNAz6dGs(B8U-^e}9Vk|G{-wS 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

7hSx!dS&s~|_Qu+Qkq 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 E1(J6e`2YX_ diff --git a/test/test_files/terrainbox/README b/test/test_files/terrainbox/README deleted file mode 100644 index 27999b9031..0000000000 --- a/test/test_files/terrainbox/README +++ /dev/null @@ -1,6 +0,0 @@ -This is a simple test case to verify the terrain setup. A box is created and a freestream velocity -is specified. Diffusion is turned off. The flow field is sampled inside the terrain region. The sampled -velocity should be a very small value (this method drives the cell center value towards zero). - -The createTerrain.py file can be used to change the size of the box and resolution. computeError.py file -returns the mean value inside the box. diff --git a/tools/terrain/SRTM_to_STL_example.py b/tools/terrain/SRTM_to_STL_example.py index e64f654839..b60e54e9b0 100644 --- a/tools/terrain/SRTM_to_STL_example.py +++ b/tools/terrain/SRTM_to_STL_example.py @@ -9,41 +9,9 @@ def SRTM_Converter(outputDir,refLat,refLon,refHeight,left,right,bottom,top): import utm from stl import mesh # install with `pip install numpy-stl` from terrain import SRTM - # # Terrain-Resolved Domain Setup - # This notebook will generate a surface geometry file to be used by the microscale solver (e.g., SOWFA) to conform the solver domain to the terrain (e.g., with `moveDynamicMesh`). - # - # Notebook written by Eliot Quon, modified by Regis Thedin\ - # {eliot.quon,regis.thedin}@nrel.gov - - # ## 1. User input - # Output directory (absolute dir) - outdir = outputDir - # ### 1.1 Mesoscale parameters - # Get lower resolution WRF terrain data - getWRFdata = False - # WRF reference solution to blend from low-res (WRF) at inflow boundaries to full SRTM resolution - wrfout = '/home/rthedin/MMC/WFIP2Region/20161121_YSU/wrfout_d01_2016-11-22_00:00:00' - # ### 1.2 Microscale parameters - # - # First, set the resolution of the data the STL will be created from, and the output resolution. product = 'SRTM1' # SRTM1 | SRTM3 (30- and 90-m DEM) ds = 10. # output resolution - - # The following cell should be modified by the user, following the examples given. The cell contains information about the actual location to be saved. - # - # The `refloc` variable is the location corresponding to (0,0) in SOWFA. - # - # Set the fringe on each side of the domain. This fringe region will used to blend the high-resolution SRTM domain data with either i) low-reosolution WRF (mesoscale) digital elevation model (DEM), or ii) flat. - # - # If `getWRFdata` above is `True`, then blending to mesoscale will occur; otherwise, the domain will be blended to flat. If blending to flat, the user can specify an extra fringe region of completely flat domain (`fringe_flat`). Additionally, if blending to flat, the terrain surface data can be shifted vertically such that the flat region is at $z=0$ by setting `shiftFlatToZero` to `True`. - # - # With respect to the bounding box, it is nice to have the boundaries exactly where the mesh would go because of the blending. For instance, a 5x5 km domain needs to match all the levels of cells: 20, 40, 80, 160 m. Essentially, 5000/160 needs to be an integer number, the same way 5000/80 needs to be as well. However, we only really need to match the coarsest resolution because they are multiple. Finally, an extra fringe of width `ds` (the resolution set above) is added, half on each side. The desired bounding box should go into the `xmin`,`xmax`,`ymin`,`ymax` variables, ignoring the `ds` addition. This extra fringe is to ensure that the STL is slightly larger than the bounding box that will be set on the microscale solver (needed in OpenFOAM to avoid numerical issues). - - - # For WFIP2 region - # - blend to flat - #refloc = (45.638004, -120.642973, 495) # biglow PS12 met mast refloc=(refLat,refLon,refHeight) xmin,xmax = -left-ds/2,right+ds/2 ymin,ymax = -bottom-ds/2,top+ds/2 @@ -54,82 +22,19 @@ def SRTM_Converter(outputDir,refLat,refLon,refHeight,left,right,bottom,top): fringe_n = 3000 fringe_e = 3000 case = f'wfip_xm{abs(int(xmin))}to{int(xmax)}_ym{abs(int(ymin))}to{int(ymax)}_blendFlat3N3S3E3W_ff{fringe_flat}' - - # - blend to WRF - # refloc = (45.638004, -120.642973, 495) # biglow PS12 met mast - # xmin,xmax = -15000-ds/2, 15720+ds/2 - # ymin,ymax = -5000-ds/2, 15160+ds/2 - # fringe_flat=0 - # shiftFlatToZero=False - # fringe_w = 3000 - # fringe_s = 3000 - # fringe_n = 3000 - # fringe_e = 3000 - # case = f'wfip_xm{abs(int(xmin))}to{int(xmax)}_ym{abs(int(ymin))}to{int(ymax)}_blendWRF3N3S3E3W' - - - # ## 2. Create output surface - - # In[11]: - - x1 = np.arange(xmin, xmax+ds, ds) y1 = np.arange(ymin, ymax+ds, ds) xsurf,ysurf = np.meshgrid(x1, y1, indexing='ij') - - - # In[12]: - - print('The output bounding box is') print('xmin: ',xsurf[0,0], '\nxmax: ',xsurf[-1,-1]) print('ymin: ',ysurf[0,0], '\nymax: ',ysurf[-1,-1]) - - - # ## 3. Get the high-resolution terrain - - # In[13]: - - - # Terrain region to clip from the digital elevation model (DEM) srtm_bounds = west, south, east, north = (refloc[1]-0.5, refloc[0]-0.4, refloc[1]+0.62, refloc[0]+0.42) - - # this will be downloaded: srtm_output=f'{outdir}/{case}.tif' # need absolute path for GDAL - - - # In[14]: - - srtm = SRTM(srtm_bounds, fpath=srtm_output, product=product) - - - # In[15]: - - - #get_ipython().run_line_magic('time', 'srtm.download()') - # CPU times: user 3.53 ms, sys: 12.7 ms, total: 16.2 ms - # Wall time: 8.74 s - - - # In[16]: srtm.download() x,y,z = srtm.to_terrain() - #get_ipython().run_cell_magic('time', '', "# original SRTM terrain stored as 'z'\nx,y,z = srtm.to_terrain()\n") - - - # In[17]: - - - # get reference location to use as origin xref,yref,_,_ = utm.from_latlon(*refloc[:2], force_zone_number=srtm.zone_number) - - - # In[18]: - - vmin,vmax = 1500,2500 - fig,ax = plt.subplots(figsize=(12,8)) cm = ax.pcolormesh(x-xref, y-yref, z, cmap='terrain')#,vmin=vmin,vmax=vmax) cb = fig.colorbar(cm,ax=ax) @@ -139,31 +44,11 @@ def SRTM_Converter(outputDir,refLat,refLon,refHeight,left,right,bottom,top): ax.set_ylabel('northing [m]') ax.set_title(f'{product} DEM projection') ax.axis('scaled') - # bounding box for microscale region les = Rectangle((xmin,ymin), xmax-xmin, ymax-ymin, edgecolor='r', lw=3, facecolor='0.5', alpha=0.5) ax.add_patch(les) - #plt.show() - - # ### 3.1 Downscale to output grid - - # In[19]: - - interpfun = RectBivariateSpline(x[:,0]-xref, y[0,:]-yref, z) - - - # In[20]: - - - # resampled SRTM data stored in 'zsrtm' zsrtm = interpfun(x1,y1,grid=True) - - - - # In[21]: - - fig,ax = plt.subplots(figsize=(12,8)) cm = ax.pcolormesh(xsurf, ysurf, zsrtm, cmap='terrain')#,vmin=vmin,vmax=vmax) cb = fig.colorbar(cm,ax=ax) @@ -173,124 +58,21 @@ def SRTM_Converter(outputDir,refLat,refLon,refHeight,left,right,bottom,top): ax.set_ylabel('northing [m]') ax.set_title(f'{product} terrain height') ax.axis('scaled') - fig.savefig(f'{outdir}/elevation_srtm_{case}.png',dpi=150,bbox_inches='tight') - - - # ## 4. Get the low-resolution terrain from the mesoscale - # This part is only relevant if the user chose to blen the high-resolution SRTM terrain data with WRF - - # In[22]: - - - # Open the dataset - if getWRFdata is True: - if os.path.isfile(wrfout) is True: - wrf = xr.open_dataset(wrfout) - wrf['HGT'] - else: - print('WRF input does not exist') - sys.exit(1) - - - # In[23]: - - - if getWRFdata is True: - # wrf fields - hgt = wrf['HGT'][0,:,:] - xlat = wrf.coords['XLAT'][0,:,:] - xlon = wrf.coords['XLONG'][0,:,:] - - - # In[24]: - - - if getWRFdata is True: - get_ipython().run_line_magic('time', 'output_lat, output_lon = srtm.to_latlon(xsurf.ravel()+xref, ysurf.ravel()+yref)') - # CPU times: user 3.38 s, sys: 157 ms, total: 3.54 s - # Wall time: 3.54 s - - - # In[25]: - - - if getWRFdata is True: - # interpolate to wrf surface elevation based on lat/lon (stored as 'zwrf') - xi = np.stack((output_lat.ravel(),output_lon.ravel()),axis=-1) - points = np.stack((xlat.values.ravel(),xlon.values.ravel()),axis=-1) - values = hgt.values.ravel() - zi = griddata(points,values,xi) - zwrf = zi.reshape(xsurf.shape) - # CPU times: user 3.14 s, sys: 931 ms, total: 4.07 s - # Wall time: 2.57 s - - - # In[26]: - - - if getWRFdata is True: - fig,ax = plt.subplots(figsize=(12,8)) - cm = ax.pcolormesh(xsurf, ysurf, zwrf, cmap='terrain')#,vmin=vmin,vmax=vmax) - cb = fig.colorbar(cm,ax=ax) - cb.set_label('elevation [m]',fontsize='x-large') - ax.tick_params(labelsize='large') - ax.set_xlabel('easting [m]') - ax.set_ylabel('northing [m]') - ax.set_title('WRF terrain height') - ax.axis('scaled') - - fig.savefig(f'elevation_wrf_{os.path.basename(wrfout)}.png',dpi=150,bbox_inches='tight') - - - # ## 5. Blend surface definitions - - # In[27]: - - # check distance from west boundary blend_w = np.ones(xsurf.shape) if fringe_w > 0: blend_w = np.minimum(np.maximum((xsurf-xmin-fringe_flat)/fringe_w, 0), 1) - - - # In[28]: - - - # check distance from east boundary blend_e = np.ones(xsurf.shape) if fringe_e > 0: blend_e = np.minimum(np.maximum((xmax-xsurf-fringe_flat)/fringe_e, 0), 1) - - - # In[29]: - - - # check distance from south boundary blend_s = np.ones(xsurf.shape) if fringe_s > 0: blend_s = np.minimum(np.maximum((ysurf-ymin-fringe_flat)/fringe_s, 0), 1) - - - # In[30]: - - - # check distance from north boundary blend_n = np.ones(xsurf.shape) if fringe_n > 0: blend_n = np.minimum(np.maximum((ymax-ysurf-fringe_flat)/fringe_n, 0), 1) - - - # In[31]: - - - # combine blending functions blend = blend_w * blend_e * blend_s * blend_n - - - # In[32]: - - fig,ax = plt.subplots(figsize=(12,8)) cm = ax.pcolormesh(xsurf, ysurf, blend, cmap='magma') cb = fig.colorbar(cm,ax=ax) @@ -299,37 +81,10 @@ def SRTM_Converter(outputDir,refLat,refLon,refHeight,left,right,bottom,top): ax.set_ylabel('northing [m]') ax.set_title('blending function') ax.axis('scaled') - - - # In[33]: - - - # create flat surface to be blended - # SRTM data is unlikely to be around the z=0 mark, so get the average z0 = np.amin(zsrtm) #0 #np.mean(zsrtm) zflat = np.full(zsrtm.shape,z0) - - - # In[34]: - - - # surface to blend - if getWRFdata is True: - zlowres = zwrf - else: - zlowres = zflat - - - # In[35]: - - - # now, blend the high/low resolution elevations + zlowres = zflat zblend = blend*zsrtm + (1-blend)*zlowres - - - # In[36]: - - fig,ax = plt.subplots(figsize=(12,8)) cm = ax.pcolormesh(xsurf, ysurf, zblend, cmap='terrain')#,vmin=vmin,vmax=vmax) cb = fig.colorbar(cm,ax=ax) @@ -340,23 +95,10 @@ def SRTM_Converter(outputDir,refLat,refLon,refHeight,left,right,bottom,top): ax.set_title('blended terrain height') ax.axis('scaled') fig.savefig(f'{outdir}/elevation_blended_{case}.png',dpi=150,bbox_inches='tight') - - - # # 6. Shift terrain - # Shifts the terrain data so that the flat borders are at $z=0$ - - # In[37]: - - if shiftFlatToZero: zTerrainRef=zblend[0,0] zblend = zblend - zblend[0,0] case = case + '_flatz0' - - - # In[38]: - - if shiftFlatToZero: fig,ax = plt.subplots(figsize=(12,8)) cm = ax.pcolormesh(xsurf, ysurf, zblend, cmap='terrain')#,vmin=vmin,vmax=vmax) @@ -368,9 +110,6 @@ def SRTM_Converter(outputDir,refLat,refLon,refHeight,left,right,bottom,top): ax.set_title('shifted terrain height') ax.axis('scaled') fig.savefig(f'{outdir}/elevation_blended_{case}.png',dpi=150,bbox_inches='tight') - - - # ## 6. Write out terrain surface STL stlout = f'{outdir}/terrain.stl' # output 'zblend' surface - can skip blending step and just output 'zsrtm' Npts = np.prod(xsurf.shape) @@ -382,7 +121,6 @@ def SRTM_Converter(outputDir,refLat,refLon,refHeight,left,right,bottom,top): stlindices = np.reshape(np.arange(Npts), xsurf.shape) Nx,Ny = xsurf.shape Nfaces = (Nx-1)*(Ny-1)*2 - surf = mesh.Mesh(np.zeros(Nfaces, dtype=mesh.Mesh.dtype)) iface = 0 for i in range(Nx-1): @@ -395,12 +133,9 @@ def SRTM_Converter(outputDir,refLat,refLon,refHeight,left,right,bottom,top): surf.vectors[iface+1,2,:] = stlpoints[stlindices[i,j],:] iface += 2 assert (iface == Nfaces) - #get_ipython().run_cell_magic('time', '', 'Nx,Ny = xsurf.shape\nNfaces = (Nx-1)*(Ny-1)*2\n\nsurf = mesh.Mesh(np.zeros(Nfaces, dtype=mesh.Mesh.dtype))\n\n#\n# manually define triangular faces for this simple quad mesh\n#\n# for iface, f in enumerate(faces):\n# for dim in range(3):\n# surf.vectors[iface][dim] = vertices[f[dim],:]\niface = 0 \nfor i in range(Nx-1):\n for j in range(Ny-1):\n surf.vectors[iface,0,:] = stlpoints[stlindices[i,j],:]\n surf.vectors[iface,1,:] = stlpoints[stlindices[i+1,j],:]\n surf.vectors[iface,2,:] = stlpoints[stlindices[i+1,j+1],:]\n surf.vectors[iface+1,0,:] = stlpoints[stlindices[i+1,j+1],:]\n surf.vectors[iface+1,1,:] = stlpoints[stlindices[i,j+1],:]\n surf.vectors[iface+1,2,:] = stlpoints[stlindices[i,j],:]\n iface += 2\nassert (iface == Nfaces)\n# CPU times: user 27.5 s, sys: 182 ms, total: 27.7 s\n# Wall time: 27.7 s\n') - dpath = os.path.dirname(stlout) if (not dpath == '') and (not os.path.isdir(dpath)): os.makedirs(dpath) print('Created',dpath) - surf.save(stlout) # surf.save(stlout, mode=mesh.stl.ASCII) # if ASCII STL is needed print('Saved',stlout) diff --git a/test/test_files/terrainbox/computeError.py b/tools/terrain/computeError.py similarity index 100% rename from test/test_files/terrainbox/computeError.py rename to tools/terrain/computeError.py diff --git a/test/test_files/terrainbox/createTerrain.py b/tools/terrain/createTerrain.py similarity index 100% rename from test/test_files/terrainbox/createTerrain.py rename to tools/terrain/createTerrain.py From 4ecbf15b1e32cf0d2368fc991d7cdd445c70a242 Mon Sep 17 00:00:00 2001 From: hgopalan Date: Mon, 8 Jul 2024 17:33:34 -0600 Subject: [PATCH 42/77] Clang Formatting --- .../icns/source_terms/DragForcing.cpp | 23 ++++++++++--------- amr-wind/physics/TerrainDrag.cpp | 12 ++++++---- submods/amrex | 2 +- 3 files changed, 21 insertions(+), 16 deletions(-) diff --git a/amr-wind/equation_systems/icns/source_terms/DragForcing.cpp b/amr-wind/equation_systems/icns/source_terms/DragForcing.cpp index ca376d144c..801aa7c197 100644 --- a/amr-wind/equation_systems/icns/source_terms/DragForcing.cpp +++ b/amr-wind/equation_systems/icns/source_terms/DragForcing.cpp @@ -5,7 +5,6 @@ #include "AMReX_Random.H" #include "amr-wind/wind_energy/ABL.H" - namespace amr_wind::pde::icns { DragForcing::DragForcing(const CFDSim& sim) @@ -67,11 +66,11 @@ void DragForcing::operator()( const amrex::Real device_sponge_strength = m_sponge_strength; const amrex::Real device_sponge_density = m_sponge_density; const amrex::Real device_startX = (m_sponge_distanceX > 0) - ? prob_hi[0] - m_sponge_distanceX - : prob_lo[0] - m_sponge_distanceX; + ? prob_hi[0] - m_sponge_distanceX + : prob_lo[0] - m_sponge_distanceX; const amrex::Real device_startY = (m_sponge_distanceY > 0) - ? prob_hi[1] - m_sponge_distanceY - : prob_lo[1] - m_sponge_distanceY; + ? prob_hi[1] - m_sponge_distanceY + : prob_lo[1] - m_sponge_distanceY; const unsigned device_spongeX = (m_sponge_distanceX > 0) ? 1 : 0; const unsigned device_spongeY = (m_sponge_distanceY > 0) ? 1 : 0; // Copy Data @@ -84,14 +83,16 @@ void DragForcing::operator()( const amrex::Real x3 = prob_lo[2] + (k + 0.5) * dx[2]; amrex::Real xdamping = 0; amrex::Real ydamping = 0; - amrex::Real xi = (device_spongeX == 1) - ? (x1 - device_startX) / (prob_hi[0] - device_startX) - : (device_startX - x1) / (device_startX - prob_lo[0]); + amrex::Real xi = + (device_spongeX == 1) + ? (x1 - device_startX) / (prob_hi[0] - device_startX) + : (device_startX - x1) / (device_startX - prob_lo[0]); xi = std::max(xi, 0.0); xdamping = device_sponge_strength * xi * xi; - amrex::Real yi = (device_spongeY == 1) - ? (x2 - device_startY) / (prob_hi[1] - device_startY) - : (device_startY - x2) / (device_startY - prob_lo[1]); + amrex::Real yi = + (device_spongeY == 1) + ? (x2 - device_startY) / (prob_hi[1] - device_startY) + : (device_startY - x2) / (device_startY - prob_lo[1]); yi = std::max(yi, 0.0); ydamping = device_sponge_strength * yi * yi; const amrex::Real Cd = device_drag / dx[0]; diff --git a/amr-wind/physics/TerrainDrag.cpp b/amr-wind/physics/TerrainDrag.cpp index 2be61067f3..25be115fb6 100644 --- a/amr-wind/physics/TerrainDrag.cpp +++ b/amr-wind/physics/TerrainDrag.cpp @@ -60,9 +60,12 @@ void TerrainDrag::post_init_actions() auto& terrainz0 = m_terrainz0(level); auto& drag = m_terrain_drag(level); // copy terrain data to gpu - amrex::Gpu::DeviceVector device_xterrain(m_xterrain.size()); - amrex::Gpu::DeviceVector device_yterrain(m_xterrain.size()); - amrex::Gpu::DeviceVector device_zterrain(m_xterrain.size()); + amrex::Gpu::DeviceVector device_xterrain( + m_xterrain.size()); + amrex::Gpu::DeviceVector device_yterrain( + m_xterrain.size()); + amrex::Gpu::DeviceVector device_zterrain( + m_xterrain.size()); amrex::Gpu::copy( amrex::Gpu::hostToDevice, m_xterrain.begin(), m_xterrain.end(), device_xterrain.begin()); @@ -119,7 +122,8 @@ void TerrainDrag::post_init_actions() break; } } - levelBlanking(i, j, k, 0) = static_cast(x3 <= terrainHt); + levelBlanking(i, j, k, 0) = + static_cast(x3 <= terrainHt); residual = 10000; amrex::Real roughz0 = 0.1; for (unsigned ii = 0; ii < roughnessSize; ++ii) { diff --git a/submods/amrex b/submods/amrex index 1da91151ae..259db7cfb9 160000 --- a/submods/amrex +++ b/submods/amrex @@ -1 +1 @@ -Subproject commit 1da91151ae161c6d58afc182512075542e127b07 +Subproject commit 259db7cfb99e7d1d2ab4bec9b1587fdf624a138a From 02505aa4eca954775bff76324f5152ff18d14ce6 Mon Sep 17 00:00:00 2001 From: hgopalan Date: Mon, 8 Jul 2024 17:39:58 -0600 Subject: [PATCH 43/77] Fixing CMake Issue --- test/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index a45a68b17f..6e3e2d5ea5 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -301,7 +301,7 @@ add_test_red(abl_godunov_restart abl_godunov) add_test_red(abl_bndry_input_amr_native abl_bndry_output_native) add_test_red(abl_bndry_input_amr_native_mlbc abl_bndry_output_amr_native) add_test_red(abl_godunov_forcetimetable abl_godunov_timetable) -add_test_red(nrel_precursor nrel_terrain) +add_test_red(nrel_terrain nrel_precursor) if(AMR_WIND_ENABLE_NETCDF) add_test_red(abl_bndry_input abl_bndry_output) From f81b41a73c1a0805e9ce49afe8720fd6997afb4d Mon Sep 17 00:00:00 2001 From: hgopalan Date: Mon, 8 Jul 2024 17:47:37 -0600 Subject: [PATCH 44/77] Coupled testing --- test/CMakeLists.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 6e3e2d5ea5..2a5fe64900 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -301,12 +301,13 @@ add_test_red(abl_godunov_restart abl_godunov) add_test_red(abl_bndry_input_amr_native abl_bndry_output_native) add_test_red(abl_bndry_input_amr_native_mlbc abl_bndry_output_amr_native) add_test_red(abl_godunov_forcetimetable abl_godunov_timetable) -add_test_red(nrel_terrain nrel_precursor) + if(AMR_WIND_ENABLE_NETCDF) add_test_red(abl_bndry_input abl_bndry_output) add_test_red(abl_bndry_input_amr abl_bndry_output) add_test_red(abl_bndry_input_amr_inflow abl_bndry_output_amr_inflow) + add_test_red(nrel_terrain nrel_precursor) endif() #============================================================================= From 64c5d5c92cce4ec27ae4806e30c1248290d5e9f1 Mon Sep 17 00:00:00 2001 From: hgopalan Date: Tue, 9 Jul 2024 13:04:04 -0600 Subject: [PATCH 45/77] Modification forc converting blanking to int field --- .../icns/source_terms/DragForcing.cpp | 8 +++-- .../source_terms/DragTempForcing.cpp | 5 +-- amr-wind/physics/TerrainDrag.H | 4 +-- amr-wind/physics/TerrainDrag.cpp | 36 +++++++++---------- amr-wind/turbulence/LES/Kosovic.cpp | 13 +++---- .../nrel_precursor/nrel_precursor.inp | 1 + test/test_files/nrel_terrain/nrel_terrain.inp | 1 + test/test_files/terrainbox/terrainBox.inp | 2 +- 8 files changed, 38 insertions(+), 32 deletions(-) diff --git a/amr-wind/equation_systems/icns/source_terms/DragForcing.cpp b/amr-wind/equation_systems/icns/source_terms/DragForcing.cpp index 801aa7c197..72c7937fd8 100644 --- a/amr-wind/equation_systems/icns/source_terms/DragForcing.cpp +++ b/amr-wind/equation_systems/icns/source_terms/DragForcing.cpp @@ -47,13 +47,15 @@ void DragForcing::operator()( { const auto& vel = m_velocity.state(field_impl::dof_state(fstate))(lev).const_array(mfi); - const bool is_terrain = this->m_sim.repo().field_exists("terrainBlank"); + const bool is_terrain = this->m_sim.repo().int_field_exists("terrainBlank"); if (!is_terrain) { amrex::Abort("Need terrain blanking variable to use this source term"); } - auto* const m_terrain_blank = &this->m_sim.repo().get_field("terrainBlank"); + auto* const m_terrain_blank = + &this->m_sim.repo().get_int_field("terrainBlank"); const auto& blank = (*m_terrain_blank)(lev).const_array(mfi); - auto* const m_terrain_drag = &this->m_sim.repo().get_field("terrainDrag"); + auto* const m_terrain_drag = + &this->m_sim.repo().get_int_field("terrainDrag"); const auto& drag = (*m_terrain_drag)(lev).const_array(mfi); auto* const m_terrainz0 = &this->m_sim.repo().get_field("terrainz0"); const auto& terrainz0 = (*m_terrainz0)(lev).const_array(mfi); diff --git a/amr-wind/equation_systems/temperature/source_terms/DragTempForcing.cpp b/amr-wind/equation_systems/temperature/source_terms/DragTempForcing.cpp index 4935841f6e..8216b7ff2a 100644 --- a/amr-wind/equation_systems/temperature/source_terms/DragTempForcing.cpp +++ b/amr-wind/equation_systems/temperature/source_terms/DragTempForcing.cpp @@ -27,11 +27,12 @@ void DragTempForcing::operator()( const amrex::Array4& src_term) const { const auto temperature = m_temperature(lev).const_array(mfi); - const bool is_terrain = this->m_sim.repo().field_exists("terrainBlank"); + const bool is_terrain = this->m_sim.repo().int_field_exists("terrainBlank"); if (!is_terrain) { amrex::Abort("Need terrain blanking variable to use this source term"); } - auto* const m_terrain_blank = &this->m_sim.repo().get_field("terrainBlank"); + auto* const m_terrain_blank = + &this->m_sim.repo().get_int_field("terrainBlank"); const auto& blank = (*m_terrain_blank)(lev).const_array(mfi); const auto& geom_vec = m_mesh.Geom(); const auto& geom = geom_vec[lev]; diff --git a/amr-wind/physics/TerrainDrag.H b/amr-wind/physics/TerrainDrag.H index 351febe5c7..9f93b1e9d3 100644 --- a/amr-wind/physics/TerrainDrag.H +++ b/amr-wind/physics/TerrainDrag.H @@ -44,9 +44,9 @@ private: const amrex::AmrCore& m_mesh; Field& m_velocity; // Blanking Field for Terrain or Buildings - Field& m_terrain_blank; + IntField& m_terrain_blank; // Terrain Drag Force Term - Field& m_terrain_drag; + IntField& m_terrain_drag; // Reading the Terrain Coordinates from file amrex::Vector m_xterrain; amrex::Vector m_yterrain; diff --git a/amr-wind/physics/TerrainDrag.cpp b/amr-wind/physics/TerrainDrag.cpp index 25be115fb6..c909aaa39b 100644 --- a/amr-wind/physics/TerrainDrag.cpp +++ b/amr-wind/physics/TerrainDrag.cpp @@ -16,8 +16,8 @@ TerrainDrag::TerrainDrag(CFDSim& sim) , m_repo(sim.repo()) , m_mesh(sim.mesh()) , m_velocity(sim.repo().get_field("velocity")) - , m_terrain_blank(sim.repo().declare_field("terrainBlank", 1, 1, 1)) - , m_terrain_drag(sim.repo().declare_field("terrainDrag", 1, 1, 1)) + , m_terrain_blank(sim.repo().declare_int_field("terrainBlank", 1, 1, 1)) + , m_terrain_drag(sim.repo().declare_int_field("terrainDrag", 1, 1, 1)) , m_terrainz0(sim.repo().declare_field("terrainz0", 1, 1, 1)) { std::string terrainfile("terrain.amrwind"); @@ -41,8 +41,8 @@ TerrainDrag::TerrainDrag(CFDSim& sim) m_z0rough.push_back(value3); } file1.close(); - m_sim.io_manager().register_io_var("terrainDrag"); - m_sim.io_manager().register_io_var("terrainBlank"); + m_sim.io_manager().register_output_int_var("terrainDrag"); + m_sim.io_manager().register_output_int_var("terrainBlank"); m_sim.io_manager().register_io_var("terrainz0"); } @@ -104,16 +104,16 @@ void TerrainDrag::post_init_actions() amrex::ParallelFor( vbx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept { // compute the source term - const amrex::Real x1 = prob_lo[0] + (i + 0.5) * dx[0]; - const amrex::Real x2 = prob_lo[1] + (j + 0.5) * dx[1]; - const amrex::Real x3 = prob_lo[2] + (k + 0.5) * dx[2]; + const amrex::Real x = prob_lo[0] + (i + 0.5) * dx[0]; + const amrex::Real y = prob_lo[1] + (j + 0.5) * dx[1]; + const amrex::Real z = prob_lo[2] + (k + 0.5) * dx[2]; // Terrain Height amrex::Real residual = 10000; amrex::Real terrainHt = 0.0; for (unsigned ii = 0; ii < terrainSize; ++ii) { const amrex::Real radius = std::sqrt( - std::pow(x1 - xterrain_ptr[ii], 2) + - std::pow(x2 - yterrain_ptr[ii], 2)); + std::pow(x - xterrain_ptr[ii], 2) + + std::pow(y - yterrain_ptr[ii], 2)); if (radius < residual) { residual = radius; terrainHt = zterrain_ptr[ii]; @@ -123,13 +123,13 @@ void TerrainDrag::post_init_actions() } } levelBlanking(i, j, k, 0) = - static_cast(x3 <= terrainHt); + static_cast(z <= terrainHt); residual = 10000; amrex::Real roughz0 = 0.1; for (unsigned ii = 0; ii < roughnessSize; ++ii) { const amrex::Real radius = std::sqrt( - std::pow(x1 - xrough_ptr[ii], 2) + - std::pow(x2 - yrough_ptr[ii], 2)); + std::pow(x - xrough_ptr[ii], 2) + + std::pow(y - yrough_ptr[ii], 2)); if (radius < residual) { residual = radius; roughz0 = z0rough_ptr[ii]; @@ -145,20 +145,20 @@ void TerrainDrag::post_init_actions() // Terrain Height amrex::Real residual = 10000; amrex::Real terrainHt = 0.0; - const amrex::Real x1 = prob_lo[0] + (i + 0.5) * dx[0]; - const amrex::Real x2 = prob_lo[1] + (j + 0.5) * dx[1]; - const amrex::Real x3 = prob_lo[2] + (k + 0.5) * dx[2]; + const amrex::Real x = prob_lo[0] + (i + 0.5) * dx[0]; + const amrex::Real y = prob_lo[1] + (j + 0.5) * dx[1]; + const amrex::Real z = prob_lo[2] + (k + 0.5) * dx[2]; for (unsigned ii = 0; ii < terrainSize; ++ii) { const amrex::Real radius = std::sqrt( - std::pow(x1 - xterrain_ptr[ii], 2) + - std::pow(x2 - yterrain_ptr[ii], 2)); + std::pow(x - xterrain_ptr[ii], 2) + + std::pow(y - yterrain_ptr[ii], 2)); if (radius < residual) { residual = radius; terrainHt = zterrain_ptr[ii]; } } levelDrag(i, j, k, 0) = 0; - if (x3 > terrainHt && k > 0 && + if (z > terrainHt && k > 0 && levelBlanking(i, j, k - 1, 0) == 1) { levelDrag(i, j, k, 0) = 1; } diff --git a/amr-wind/turbulence/LES/Kosovic.cpp b/amr-wind/turbulence/LES/Kosovic.cpp index fd1dfd7017..24c1d66624 100644 --- a/amr-wind/turbulence/LES/Kosovic.cpp +++ b/amr-wind/turbulence/LES/Kosovic.cpp @@ -54,11 +54,10 @@ void Kosovic::update_turbulent_viscosity( const auto& den = m_rho.state(fstate); const auto& geom_vec = repo.mesh().Geom(); const amrex::Real Cs_sqr = this->m_Cs * this->m_Cs; - bool is_terrain = this->m_sim.repo().field_exists("terrainBlank"); - Field* m_terrainBlank = &mu_turb; - if (is_terrain) { - m_terrainBlank = &this->m_sim.repo().get_field("terrainBlank"); - } + const bool is_terrain = this->m_sim.repo().int_field_exists("terrainBlank"); + const auto* m_terrain_blank = + is_terrain ? &this->m_sim.repo().get_int_field("terrainBlank") + : nullptr; // Populate strainrate into the turbulent viscosity arrays to avoid creating // a temporary buffer fvm::strainrate(mu_turb, vel); @@ -86,7 +85,9 @@ void Kosovic::update_turbulent_viscosity( const auto& mu_arr = mu_turb(lev).array(mfi); const auto& rho_arr = den(lev).const_array(mfi); const auto& divNijLevel = (this->m_divNij)(lev).array(mfi); - const auto& blank_arr = (*m_terrainBlank)(lev).array(mfi); + const auto& blank_arr = + is_terrain ? (*m_terrain_blank)(lev).const_array(mfi) + : amrex::Array4(); amrex::ParallelFor( bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept { const amrex::Real rho = rho_arr(i, j, k); diff --git a/test/test_files/nrel_precursor/nrel_precursor.inp b/test/test_files/nrel_precursor/nrel_precursor.inp index 7e267338da..4d6dbf0afc 100644 --- a/test/test_files/nrel_precursor/nrel_precursor.inp +++ b/test/test_files/nrel_precursor/nrel_precursor.inp @@ -13,6 +13,7 @@ time.fixed_dt = -1 time.cfl = 0.9 time.plot_interval = 1000 time.checkpoint_interval = 1000 +io.int_outputs = terrainBlank TerrainDrag # incflo incflo.physics = ABL incflo.density = 1.225 diff --git a/test/test_files/nrel_terrain/nrel_terrain.inp b/test/test_files/nrel_terrain/nrel_terrain.inp index 8d3afaeb2a..9799515374 100644 --- a/test/test_files/nrel_terrain/nrel_terrain.inp +++ b/test/test_files/nrel_terrain/nrel_terrain.inp @@ -13,6 +13,7 @@ time.fixed_dt = -1 time.cfl = 0.9 time.plot_interval = 1000 time.checkpoint_interval = 1000 +io.int_outputs = terrainBlank TerrainDrag # incflo incflo.physics = ABL TerrainDrag incflo.density = 1.225 diff --git a/test/test_files/terrainbox/terrainBox.inp b/test/test_files/terrainbox/terrainBox.inp index 28d7467ff4..0deb4f650a 100644 --- a/test/test_files/terrainbox/terrainBox.inp +++ b/test/test_files/terrainbox/terrainBox.inp @@ -30,7 +30,7 @@ transport.viscosity = 1.0e-15 transport.laminar_prandtl = 0.7 transport.turbulent_prandtl = 0.3333 turbulence.model = Laminar - +io.int_outputs = terrainBlank TerrainDrag incflo.physics = FreeStream TerrainDrag ICNS.source_terms = DragForcing DragForcing.verificationMode = 1 From cd01d021b0a8278e8dcfbcc1a453be93a7c92f86 Mon Sep 17 00:00:00 2001 From: hgopalan Date: Tue, 9 Jul 2024 15:12:18 -0600 Subject: [PATCH 46/77] Updated for consistency and formatting --- .../icns/source_terms/DragForcing.H | 4 +- .../icns/source_terms/DragForcing.cpp | 82 +++++++++---------- .../source_terms/DragTempForcing.cpp | 14 ++-- amr-wind/physics/TerrainDrag.cpp | 4 +- amr-wind/turbulence/LES/Kosovic.cpp | 14 ++-- .../nrel_precursor/nrel_precursor.inp | 2 +- test/test_files/nrel_terrain/nrel_terrain.inp | 2 +- 7 files changed, 61 insertions(+), 61 deletions(-) diff --git a/amr-wind/equation_systems/icns/source_terms/DragForcing.H b/amr-wind/equation_systems/icns/source_terms/DragForcing.H index 45cb178e79..4524c956f5 100644 --- a/amr-wind/equation_systems/icns/source_terms/DragForcing.H +++ b/amr-wind/equation_systems/icns/source_terms/DragForcing.H @@ -33,8 +33,8 @@ private: const CFDSim& m_sim; const amrex::AmrCore& m_mesh; const Field& m_velocity; - amrex::Gpu::DeviceVector device_vel_ht; - amrex::Gpu::DeviceVector device_vel_vals; + amrex::Gpu::DeviceVector m_device_vel_ht; + amrex::Gpu::DeviceVector m_device_vel_vals; amrex::Real m_drag{100.0}; amrex::Real m_sponge_strength{1.0}; amrex::Real m_sponge_density{1.0}; diff --git a/amr-wind/equation_systems/icns/source_terms/DragForcing.cpp b/amr-wind/equation_systems/icns/source_terms/DragForcing.cpp index 72c7937fd8..399e3c4b67 100644 --- a/amr-wind/equation_systems/icns/source_terms/DragForcing.cpp +++ b/amr-wind/equation_systems/icns/source_terms/DragForcing.cpp @@ -23,14 +23,14 @@ DragForcing::DragForcing(const CFDSim& sim) const auto& abl = m_sim.physics_manager().get(); const VelPlaneAveraging& fa_velocity = abl.abl_statistics().vel_profile_coarse(); - device_vel_ht.resize(fa_velocity.line_centroids().size()); - device_vel_vals.resize(fa_velocity.line_average().size()); + m_device_vel_ht.resize(fa_velocity.line_centroids().size()); + m_device_vel_vals.resize(fa_velocity.line_average().size()); amrex::Gpu::copy( amrex::Gpu::hostToDevice, fa_velocity.line_centroids().begin(), - fa_velocity.line_centroids().end(), device_vel_ht.begin()); + fa_velocity.line_centroids().end(), m_device_vel_ht.begin()); amrex::Gpu::copy( amrex::Gpu::hostToDevice, fa_velocity.line_average().begin(), - fa_velocity.line_average().end(), device_vel_vals.begin()); + fa_velocity.line_average().end(), m_device_vel_vals.begin()); } else { m_sponge_strength = 0.0; } @@ -47,15 +47,15 @@ void DragForcing::operator()( { const auto& vel = m_velocity.state(field_impl::dof_state(fstate))(lev).const_array(mfi); - const bool is_terrain = this->m_sim.repo().int_field_exists("terrainBlank"); + const bool is_terrain = this->m_sim.repo().int_field_exists("terrain_blank"); if (!is_terrain) { amrex::Abort("Need terrain blanking variable to use this source term"); } auto* const m_terrain_blank = - &this->m_sim.repo().get_int_field("terrainBlank"); + &this->m_sim.repo().get_int_field("terrain_blank"); const auto& blank = (*m_terrain_blank)(lev).const_array(mfi); auto* const m_terrain_drag = - &this->m_sim.repo().get_int_field("terrainDrag"); + &this->m_sim.repo().get_int_field("terrain_drag"); const auto& drag = (*m_terrain_drag)(lev).const_array(mfi); auto* const m_terrainz0 = &this->m_sim.repo().get_field("terrainz0"); const auto& terrainz0 = (*m_terrainz0)(lev).const_array(mfi); @@ -64,55 +64,55 @@ void DragForcing::operator()( const auto& dx = geom.CellSize(); const auto& prob_lo = geom.ProbLoArray(); const auto& prob_hi = geom.ProbHiArray(); - const amrex::Real device_drag = m_drag; - const amrex::Real device_sponge_strength = m_sponge_strength; - const amrex::Real device_sponge_density = m_sponge_density; - const amrex::Real device_startX = (m_sponge_distanceX > 0) + const amrex::Real dragCoefficient = m_drag; + const amrex::Real sponge_strength = m_sponge_strength; + const amrex::Real sponge_density = m_sponge_density; + const amrex::Real startX = (m_sponge_distanceX > 0) ? prob_hi[0] - m_sponge_distanceX : prob_lo[0] - m_sponge_distanceX; - const amrex::Real device_startY = (m_sponge_distanceY > 0) + const amrex::Real startY = (m_sponge_distanceY > 0) ? prob_hi[1] - m_sponge_distanceY : prob_lo[1] - m_sponge_distanceY; - const unsigned device_spongeX = (m_sponge_distanceX > 0) ? 1 : 0; - const unsigned device_spongeY = (m_sponge_distanceY > 0) ? 1 : 0; + const unsigned spongeX = (m_sponge_distanceX > 0) ? 1 : 0; + const unsigned spongeY = (m_sponge_distanceY > 0) ? 1 : 0; // Copy Data - const auto* local_device_vel_ht = device_vel_ht.data(); - const auto* local_device_vel_vals = device_vel_vals.data(); - const unsigned vsize = device_vel_ht.size(); + const auto* device_vel_ht = m_device_vel_ht.data(); + const auto* device_vel_vals = m_device_vel_vals.data(); + const unsigned vsize = m_device_vel_ht.size(); amrex::ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept { - const amrex::Real x1 = prob_lo[0] + (i + 0.5) * dx[0]; - const amrex::Real x2 = prob_lo[1] + (j + 0.5) * dx[1]; - const amrex::Real x3 = prob_lo[2] + (k + 0.5) * dx[2]; + const amrex::Real x = prob_lo[0] + (i + 0.5) * dx[0]; + const amrex::Real y = prob_lo[1] + (j + 0.5) * dx[1]; + const amrex::Real z = prob_lo[2] + (k + 0.5) * dx[2]; amrex::Real xdamping = 0; amrex::Real ydamping = 0; amrex::Real xi = - (device_spongeX == 1) - ? (x1 - device_startX) / (prob_hi[0] - device_startX) - : (device_startX - x1) / (device_startX - prob_lo[0]); + (spongeX == 1) + ? (x- startX) / (prob_hi[0] - startX) + : (startX - x) / (startX - prob_lo[0]); xi = std::max(xi, 0.0); - xdamping = device_sponge_strength * xi * xi; + xdamping = sponge_strength * xi * xi; amrex::Real yi = - (device_spongeY == 1) - ? (x2 - device_startY) / (prob_hi[1] - device_startY) - : (device_startY - x2) / (device_startY - prob_lo[1]); + (spongeY == 1) + ? (y - startY) / (prob_hi[1] - startY) + : (startY - y) / (startY - prob_lo[1]); yi = std::max(yi, 0.0); - ydamping = device_sponge_strength * yi * yi; - const amrex::Real Cd = device_drag / dx[0]; - amrex::Real device_spongeVelX = 0.0; - amrex::Real device_spongeVelY = 0.0; - amrex::Real device_spongeVelZ = 0.0; + ydamping = sponge_strength * yi * yi; + const amrex::Real Cd = dragCoefficient/ dx[0]; + amrex::Real spongeVelX = 0.0; + amrex::Real spongeVelY = 0.0; + amrex::Real spongeVelZ = 0.0; amrex::Real residual = 1000; amrex::Real height_error = 0.0; for (unsigned ii = 0; ii < vsize; ++ii) { - height_error = std::abs(x3 - local_device_vel_ht[ii]); + height_error = std::abs(z - device_vel_ht[ii]); if (height_error < residual) { residual = height_error; const unsigned ix = 3 * ii; const unsigned iy = 3 * ii + 1; const unsigned iz = 3 * ii + 2; - device_spongeVelX = local_device_vel_vals[ix]; - device_spongeVelY = local_device_vel_vals[iy]; - device_spongeVelZ = local_device_vel_vals[iz]; + spongeVelX = device_vel_vals[ix]; + spongeVelY = device_vel_vals[iy]; + spongeVelZ = device_vel_vals[iz]; } } // Terrain Drag @@ -129,9 +129,9 @@ void DragForcing::operator()( const amrex::Real m2 = std::sqrt(ux2 * ux2 + uy2 * uy2); const amrex::Real kappa = 0.41; const amrex::Real z0 = std::max(terrainz0(i, j, k), 1e-4); - const amrex::Real ustar = std::min(device_sponge_strength, 1.0) * + const amrex::Real ustar = std::min(sponge_strength, 1.0) * std::abs(m2 - m1) * kappa / - std::log((x3 + z0) / z0); + std::log((z + z0) / z0); Dxz = -ustar * ustar * ux1 / (1e-5 + std::sqrt(ux1 * ux1 + uy1 * uy1)) / dx[2]; Dyz = -ustar * ustar * uy1 / @@ -142,15 +142,15 @@ void DragForcing::operator()( src_term(i, j, k, 0) -= (CdM * m * ux1 * blank(i, j, k) + Dxz * drag(i, j, k) + (xdamping + ydamping) * - (ux1 - device_sponge_density * device_spongeVelX)); + (ux1 - sponge_density * spongeVelX)); src_term(i, j, k, 1) -= (CdM * m * uy1 * blank(i, j, k) + Dyz * drag(i, j, k) + (xdamping + ydamping) * - (uy1 - device_sponge_density * device_spongeVelY)); + (uy1 - sponge_density * spongeVelY)); src_term(i, j, k, 2) -= (CdM * m * uz1 * blank(i, j, k) + (xdamping + ydamping) * - (uz1 - device_sponge_density * device_spongeVelZ)); + (uz1 - sponge_density * spongeVelZ)); }); } diff --git a/amr-wind/equation_systems/temperature/source_terms/DragTempForcing.cpp b/amr-wind/equation_systems/temperature/source_terms/DragTempForcing.cpp index 8216b7ff2a..729cad1fe1 100644 --- a/amr-wind/equation_systems/temperature/source_terms/DragTempForcing.cpp +++ b/amr-wind/equation_systems/temperature/source_terms/DragTempForcing.cpp @@ -13,7 +13,7 @@ DragTempForcing::DragTempForcing(const CFDSim& sim) , m_temperature(sim.repo().get_field("temperature")) { amrex::ParmParse pp("DragTempForcing"); - pp.query("dragCoefficient", m_drag); + pp.query("drag_coefficient", m_drag); pp.query("RefT", m_internalRefT); } @@ -27,22 +27,22 @@ void DragTempForcing::operator()( const amrex::Array4& src_term) const { const auto temperature = m_temperature(lev).const_array(mfi); - const bool is_terrain = this->m_sim.repo().int_field_exists("terrainBlank"); + const bool is_terrain = this->m_sim.repo().int_field_exists("terrain_blank"); if (!is_terrain) { amrex::Abort("Need terrain blanking variable to use this source term"); } auto* const m_terrain_blank = - &this->m_sim.repo().get_int_field("terrainBlank"); + &this->m_sim.repo().get_int_field("terrain_blank"); const auto& blank = (*m_terrain_blank)(lev).const_array(mfi); const auto& geom_vec = m_mesh.Geom(); const auto& geom = geom_vec[lev]; const auto& dx = geom.CellSize(); - const amrex::Real gpu_drag = m_drag; - const amrex::Real gpu_TRef = m_internalRefT; + const amrex::Real drag = m_drag; + const amrex::Real TRef = m_internalRefT; amrex::ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept { - const amrex::Real Cd = gpu_drag / dx[0]; + const amrex::Real Cd = drag / dx[0]; src_term(i, j, k, 0) -= - (Cd * (temperature(i, j, k, 0) - gpu_TRef) * blank(i, j, k)); + (Cd * (temperature(i, j, k, 0) - TRef) * blank(i, j, k)); }); } diff --git a/amr-wind/physics/TerrainDrag.cpp b/amr-wind/physics/TerrainDrag.cpp index c909aaa39b..1f31e9506e 100644 --- a/amr-wind/physics/TerrainDrag.cpp +++ b/amr-wind/physics/TerrainDrag.cpp @@ -16,8 +16,8 @@ TerrainDrag::TerrainDrag(CFDSim& sim) , m_repo(sim.repo()) , m_mesh(sim.mesh()) , m_velocity(sim.repo().get_field("velocity")) - , m_terrain_blank(sim.repo().declare_int_field("terrainBlank", 1, 1, 1)) - , m_terrain_drag(sim.repo().declare_int_field("terrainDrag", 1, 1, 1)) + , m_terrain_blank(sim.repo().declare_int_field("terrain_blank", 1, 1, 1)) + , m_terrain_drag(sim.repo().declare_int_field("terrain_drag", 1, 1, 1)) , m_terrainz0(sim.repo().declare_field("terrainz0", 1, 1, 1)) { std::string terrainfile("terrain.amrwind"); diff --git a/amr-wind/turbulence/LES/Kosovic.cpp b/amr-wind/turbulence/LES/Kosovic.cpp index 24c1d66624..551376b44f 100644 --- a/amr-wind/turbulence/LES/Kosovic.cpp +++ b/amr-wind/turbulence/LES/Kosovic.cpp @@ -54,9 +54,9 @@ void Kosovic::update_turbulent_viscosity( const auto& den = m_rho.state(fstate); const auto& geom_vec = repo.mesh().Geom(); const amrex::Real Cs_sqr = this->m_Cs * this->m_Cs; - const bool is_terrain = this->m_sim.repo().int_field_exists("terrainBlank"); + const bool is_terrain = this->m_sim.repo().int_field_exists("terrain_blank"); const auto* m_terrain_blank = - is_terrain ? &this->m_sim.repo().get_int_field("terrainBlank") + is_terrain ? &this->m_sim.repo().get_int_field("terrain_blank") : nullptr; // Populate strainrate into the turbulent viscosity arrays to avoid creating // a temporary buffer @@ -91,14 +91,14 @@ void Kosovic::update_turbulent_viscosity( amrex::ParallelFor( bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept { const amrex::Real rho = rho_arr(i, j, k); - const amrex::Real x3 = problo[2] + (k + 0.5) * dz; - const amrex::Real fmu = std::exp(-x3 / locSwitchLoc); + const amrex::Real z = problo[2] + (k + 0.5) * dz; + const amrex::Real fmu = std::exp(-z / locSwitchLoc); const amrex::Real phiM = - (locMOL < 0) ? std::pow(1 - 16 * x3 / locMOL, -0.25) - : 1 + 5 * x3 / locMOL; + (locMOL < 0) ? std::pow(1 - 16 * z/ locMOL, -0.25) + : 1 + 5 * z / locMOL; const amrex::Real ransL = std::pow(0.41 * (k + 1) * dz / phiM, 2); - amrex::Real turnOff = std::exp(-x3 / locLESTurnOff); + amrex::Real turnOff = std::exp(-z/ locLESTurnOff); amrex::Real viscosityScale = locSurfaceFactor * (std::pow(1 - fmu, locSurfaceRANSExp) * diff --git a/test/test_files/nrel_precursor/nrel_precursor.inp b/test/test_files/nrel_precursor/nrel_precursor.inp index 4d6dbf0afc..4a05abb19b 100644 --- a/test/test_files/nrel_precursor/nrel_precursor.inp +++ b/test/test_files/nrel_precursor/nrel_precursor.inp @@ -13,7 +13,7 @@ time.fixed_dt = -1 time.cfl = 0.9 time.plot_interval = 1000 time.checkpoint_interval = 1000 -io.int_outputs = terrainBlank TerrainDrag +io.int_outputs = terrain_blank terrain_drag # incflo incflo.physics = ABL incflo.density = 1.225 diff --git a/test/test_files/nrel_terrain/nrel_terrain.inp b/test/test_files/nrel_terrain/nrel_terrain.inp index 9799515374..8040b35774 100644 --- a/test/test_files/nrel_terrain/nrel_terrain.inp +++ b/test/test_files/nrel_terrain/nrel_terrain.inp @@ -13,7 +13,7 @@ time.fixed_dt = -1 time.cfl = 0.9 time.plot_interval = 1000 time.checkpoint_interval = 1000 -io.int_outputs = terrainBlank TerrainDrag +io.int_outputs = terrain_blank terrain_drag # incflo incflo.physics = ABL TerrainDrag incflo.density = 1.225 From 18ee5047dd640d649792e8b5346a3cff8efc7b53 Mon Sep 17 00:00:00 2001 From: hgopalan Date: Tue, 9 Jul 2024 15:15:26 -0600 Subject: [PATCH 47/77] Clang formatting --- amr-wind/turbulence/LES/Kosovic.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/amr-wind/turbulence/LES/Kosovic.cpp b/amr-wind/turbulence/LES/Kosovic.cpp index 551376b44f..558bdafd88 100644 --- a/amr-wind/turbulence/LES/Kosovic.cpp +++ b/amr-wind/turbulence/LES/Kosovic.cpp @@ -54,7 +54,8 @@ void Kosovic::update_turbulent_viscosity( const auto& den = m_rho.state(fstate); const auto& geom_vec = repo.mesh().Geom(); const amrex::Real Cs_sqr = this->m_Cs * this->m_Cs; - const bool is_terrain = this->m_sim.repo().int_field_exists("terrain_blank"); + const bool is_terrain = + this->m_sim.repo().int_field_exists("terrain_blank"); const auto* m_terrain_blank = is_terrain ? &this->m_sim.repo().get_int_field("terrain_blank") : nullptr; @@ -94,11 +95,11 @@ void Kosovic::update_turbulent_viscosity( const amrex::Real z = problo[2] + (k + 0.5) * dz; const amrex::Real fmu = std::exp(-z / locSwitchLoc); const amrex::Real phiM = - (locMOL < 0) ? std::pow(1 - 16 * z/ locMOL, -0.25) + (locMOL < 0) ? std::pow(1 - 16 * z / locMOL, -0.25) : 1 + 5 * z / locMOL; const amrex::Real ransL = std::pow(0.41 * (k + 1) * dz / phiM, 2); - amrex::Real turnOff = std::exp(-z/ locLESTurnOff); + amrex::Real turnOff = std::exp(-z / locLESTurnOff); amrex::Real viscosityScale = locSurfaceFactor * (std::pow(1 - fmu, locSurfaceRANSExp) * From 13557f0064cfcc49c84d770d1fa965d24bb6aba4 Mon Sep 17 00:00:00 2001 From: hgopalan Date: Tue, 9 Jul 2024 15:23:38 -0600 Subject: [PATCH 48/77] Formatting --- .../icns/source_terms/DragForcing.cpp | 34 ++++++++----------- .../source_terms/DragTempForcing.cpp | 3 +- 2 files changed, 16 insertions(+), 21 deletions(-) diff --git a/amr-wind/equation_systems/icns/source_terms/DragForcing.cpp b/amr-wind/equation_systems/icns/source_terms/DragForcing.cpp index 399e3c4b67..0632e34c69 100644 --- a/amr-wind/equation_systems/icns/source_terms/DragForcing.cpp +++ b/amr-wind/equation_systems/icns/source_terms/DragForcing.cpp @@ -47,7 +47,8 @@ void DragForcing::operator()( { const auto& vel = m_velocity.state(field_impl::dof_state(fstate))(lev).const_array(mfi); - const bool is_terrain = this->m_sim.repo().int_field_exists("terrain_blank"); + const bool is_terrain = + this->m_sim.repo().int_field_exists("terrain_blank"); if (!is_terrain) { amrex::Abort("Need terrain blanking variable to use this source term"); } @@ -68,11 +69,11 @@ void DragForcing::operator()( const amrex::Real sponge_strength = m_sponge_strength; const amrex::Real sponge_density = m_sponge_density; const amrex::Real startX = (m_sponge_distanceX > 0) - ? prob_hi[0] - m_sponge_distanceX - : prob_lo[0] - m_sponge_distanceX; + ? prob_hi[0] - m_sponge_distanceX + : prob_lo[0] - m_sponge_distanceX; const amrex::Real startY = (m_sponge_distanceY > 0) - ? prob_hi[1] - m_sponge_distanceY - : prob_lo[1] - m_sponge_distanceY; + ? prob_hi[1] - m_sponge_distanceY + : prob_lo[1] - m_sponge_distanceY; const unsigned spongeX = (m_sponge_distanceX > 0) ? 1 : 0; const unsigned spongeY = (m_sponge_distanceY > 0) ? 1 : 0; // Copy Data @@ -85,19 +86,15 @@ void DragForcing::operator()( const amrex::Real z = prob_lo[2] + (k + 0.5) * dx[2]; amrex::Real xdamping = 0; amrex::Real ydamping = 0; - amrex::Real xi = - (spongeX == 1) - ? (x- startX) / (prob_hi[0] - startX) - : (startX - x) / (startX - prob_lo[0]); + amrex::Real xi = (spongeX == 1) ? (x - startX) / (prob_hi[0] - startX) + : (startX - x) / (startX - prob_lo[0]); xi = std::max(xi, 0.0); xdamping = sponge_strength * xi * xi; - amrex::Real yi = - (spongeY == 1) - ? (y - startY) / (prob_hi[1] - startY) - : (startY - y) / (startY - prob_lo[1]); + amrex::Real yi = (spongeY == 1) ? (y - startY) / (prob_hi[1] - startY) + : (startY - y) / (startY - prob_lo[1]); yi = std::max(yi, 0.0); ydamping = sponge_strength * yi * yi; - const amrex::Real Cd = dragCoefficient/ dx[0]; + const amrex::Real Cd = dragCoefficient / dx[0]; amrex::Real spongeVelX = 0.0; amrex::Real spongeVelY = 0.0; amrex::Real spongeVelZ = 0.0; @@ -141,16 +138,13 @@ void DragForcing::operator()( const amrex::Real CdM = std::min(Cd / (m + 1e-5), 1000.0); src_term(i, j, k, 0) -= (CdM * m * ux1 * blank(i, j, k) + Dxz * drag(i, j, k) + - (xdamping + ydamping) * - (ux1 - sponge_density * spongeVelX)); + (xdamping + ydamping) * (ux1 - sponge_density * spongeVelX)); src_term(i, j, k, 1) -= (CdM * m * uy1 * blank(i, j, k) + Dyz * drag(i, j, k) + - (xdamping + ydamping) * - (uy1 - sponge_density * spongeVelY)); + (xdamping + ydamping) * (uy1 - sponge_density * spongeVelY)); src_term(i, j, k, 2) -= (CdM * m * uz1 * blank(i, j, k) + - (xdamping + ydamping) * - (uz1 - sponge_density * spongeVelZ)); + (xdamping + ydamping) * (uz1 - sponge_density * spongeVelZ)); }); } diff --git a/amr-wind/equation_systems/temperature/source_terms/DragTempForcing.cpp b/amr-wind/equation_systems/temperature/source_terms/DragTempForcing.cpp index 729cad1fe1..cac738fbca 100644 --- a/amr-wind/equation_systems/temperature/source_terms/DragTempForcing.cpp +++ b/amr-wind/equation_systems/temperature/source_terms/DragTempForcing.cpp @@ -27,7 +27,8 @@ void DragTempForcing::operator()( const amrex::Array4& src_term) const { const auto temperature = m_temperature(lev).const_array(mfi); - const bool is_terrain = this->m_sim.repo().int_field_exists("terrain_blank"); + const bool is_terrain = + this->m_sim.repo().int_field_exists("terrain_blank"); if (!is_terrain) { amrex::Abort("Need terrain blanking variable to use this source term"); } From 64c285bdf14f714512923f0018bf3d0d4ce95b60 Mon Sep 17 00:00:00 2001 From: Harish Date: Tue, 16 Jul 2024 11:38:10 -0600 Subject: [PATCH 49/77] Rename terrainBox.inp to terrainbox.inp --- test/test_files/terrainbox/{terrainBox.inp => terrainbox.inp} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename test/test_files/terrainbox/{terrainBox.inp => terrainbox.inp} (100%) diff --git a/test/test_files/terrainbox/terrainBox.inp b/test/test_files/terrainbox/terrainbox.inp similarity index 100% rename from test/test_files/terrainbox/terrainBox.inp rename to test/test_files/terrainbox/terrainbox.inp From e8e50eb6db467e627983a44bd00f7a2805a258d0 Mon Sep 17 00:00:00 2001 From: hgopalan Date: Tue, 16 Jul 2024 11:42:02 -0600 Subject: [PATCH 50/77] Fixing terrain_box --- test/CMakeLists.txt | 2 +- .../{terrainbox/terrainbox.inp => terrain_box/terrain_box.inp} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename test/test_files/{terrainbox/terrainbox.inp => terrain_box/terrain_box.inp} (100%) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index c2aff53dc8..0216cb029a 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -245,7 +245,7 @@ add_test_re(burggraf_flow) add_test_re(abl_godunov_rayleigh_damping) add_test_re(rankine) add_test_re(rankine-sym) -add_test_re(terrainbox) +add_test_re(terrain_box) if(NOT AMR_WIND_ENABLE_CUDA) diff --git a/test/test_files/terrainbox/terrainbox.inp b/test/test_files/terrain_box/terrain_box.inp similarity index 100% rename from test/test_files/terrainbox/terrainbox.inp rename to test/test_files/terrain_box/terrain_box.inp From e005a1dd1c8f372a708e9d7cb2c7224bf8378d0b Mon Sep 17 00:00:00 2001 From: hgopalan Date: Wed, 17 Jul 2024 11:14:25 -0600 Subject: [PATCH 51/77] Removed terrain tools from utilities. Modified forcing terms to avoid GPU errors. Added a test case to show that IB does not affect the MOST BC. --- .../icns/source_terms/DragForcing.cpp | 5 +- .../source_terms/DragTempForcing.cpp | 5 +- test/CMakeLists.txt | 1 + .../abl_kosovic_neutral_ib.inp | 109 + .../abl_kosovic_neutral_ib/terrain.amrwind | 4225 +++++++++++++++++ tools/terrain/NREL.yaml | 29 - tools/terrain/SRTM_to_STL_example.py | 149 - tools/terrain/backendInterface.py | 867 ---- tools/terrain/computeError.py | 13 - tools/terrain/createTerrain.py | 15 - tools/terrain/stl2XYZ.py | 62 - tools/terrain/terrain.py | 884 ---- 12 files changed, 4339 insertions(+), 2025 deletions(-) create mode 100644 test/test_files/abl_kosovic_neutral_ib/abl_kosovic_neutral_ib.inp create mode 100644 test/test_files/abl_kosovic_neutral_ib/terrain.amrwind delete mode 100644 tools/terrain/NREL.yaml delete mode 100644 tools/terrain/SRTM_to_STL_example.py delete mode 100644 tools/terrain/backendInterface.py delete mode 100644 tools/terrain/computeError.py delete mode 100644 tools/terrain/createTerrain.py delete mode 100644 tools/terrain/stl2XYZ.py delete mode 100644 tools/terrain/terrain.py diff --git a/amr-wind/equation_systems/icns/source_terms/DragForcing.cpp b/amr-wind/equation_systems/icns/source_terms/DragForcing.cpp index 0632e34c69..47d0c3182f 100644 --- a/amr-wind/equation_systems/icns/source_terms/DragForcing.cpp +++ b/amr-wind/equation_systems/icns/source_terms/DragForcing.cpp @@ -60,9 +60,8 @@ void DragForcing::operator()( const auto& drag = (*m_terrain_drag)(lev).const_array(mfi); auto* const m_terrainz0 = &this->m_sim.repo().get_field("terrainz0"); const auto& terrainz0 = (*m_terrainz0)(lev).const_array(mfi); - const auto& geom_vec = m_mesh.Geom(); - const auto& geom = geom_vec[lev]; - const auto& dx = geom.CellSize(); + const auto& geom = m_mesh.Geom(lev); + const auto& dx = geom.CellSizeArray(); const auto& prob_lo = geom.ProbLoArray(); const auto& prob_hi = geom.ProbHiArray(); const amrex::Real dragCoefficient = m_drag; diff --git a/amr-wind/equation_systems/temperature/source_terms/DragTempForcing.cpp b/amr-wind/equation_systems/temperature/source_terms/DragTempForcing.cpp index cac738fbca..8e6678e7a9 100644 --- a/amr-wind/equation_systems/temperature/source_terms/DragTempForcing.cpp +++ b/amr-wind/equation_systems/temperature/source_terms/DragTempForcing.cpp @@ -35,9 +35,8 @@ void DragTempForcing::operator()( auto* const m_terrain_blank = &this->m_sim.repo().get_int_field("terrain_blank"); const auto& blank = (*m_terrain_blank)(lev).const_array(mfi); - const auto& geom_vec = m_mesh.Geom(); - const auto& geom = geom_vec[lev]; - const auto& dx = geom.CellSize(); + const auto& geom = m_mesh.Geom(lev); + const auto& dx = geom.CellSizeArray(); const amrex::Real drag = m_drag; const amrex::Real TRef = m_internalRefT; amrex::ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept { diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 0216cb029a..044214c33c 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -262,6 +262,7 @@ if(AMR_WIND_ENABLE_NETCDF) add_test_re(abl_meso_input_dpa) add_test_re(abl_meso_input_ipa) add_test_re(abl_kosovic_neutral) + add_test_re(abl_kosovic_neutral_ib) endif() if(AMR_WIND_ENABLE_MASA) diff --git a/test/test_files/abl_kosovic_neutral_ib/abl_kosovic_neutral_ib.inp b/test/test_files/abl_kosovic_neutral_ib/abl_kosovic_neutral_ib.inp new file mode 100644 index 0000000000..e2790111a2 --- /dev/null +++ b/test/test_files/abl_kosovic_neutral_ib/abl_kosovic_neutral_ib.inp @@ -0,0 +1,109 @@ +# Geometry +geometry.prob_lo = 0.0 0.0 0.0 +geometry.prob_hi = 4096 4096 1024 +geometry.is_periodic = 1 1 0 +# Grid +amr.n_cell = 128 128 32 +amr.max_level = 0 +# Simulation control parameters +time.stop_time = 10 +time.max_step = 10 +time.initial_dt = 0.1 +time.cfl = 0.9 +time.init_shrink = 0.1 +time.regrid_interval = -1 +time.plot_interval = 7200 +time.checkpoint_interval = 28800 +#io +#io.restart_file = "chk33529" +# incflo +incflo.physics = ABL TerrainDrag +incflo.density = 1.225 +incflo.gravity = 0. 0. -9.81 # Gravitational force (3D) +incflo.velocity = 10.0 0.0 0.0 +incflo.verbose = 0 +incflo.initial_iterations = 8 +incflo.do_initial_proj = true +incflo.constant_density = true +incflo.use_godunov = true +incflo.godunov_type = "weno_z" +incflo.diffusion_type = 2 +# transport equation parameters +transport.model = ConstTransport +transport.viscosity = 0.0 +transport.laminar_prandtl = 0.7 +transport.turbulent_prandtl = 0.333 +# turbulence equation parameters +turbulence.model = Kosovic +Kosovic.surfaceRANS = false +Kosovic.surfaceRANSExp = 2 +Kosovic.writeTerms = false +Kosovic.refMOL = -1e30 +# Atmospheric boundary layer +ABL.Uperiods = 12.0 +ABL.Vperiods = 12.0 +ABL.cutoff_height = 50.0 +ABL.deltaU = 1.0 +ABL.deltaV = 1.0 +ABL.kappa = .41 +ABL.normal_direction = 2 +ABL.perturb_ref_height = 50.0 +ABL.perturb_velocity = true +ABL.perturb_temperature = false +ABL.reference_temperature = 300. +ABL.stats_output_format = netcdf +ABL.surface_roughness_z0 = 0.1 +ABL.temperature_heights = 0 800 900 1800 2700 +ABL.temperature_values = 300 300 308 311 314 +ABL.wall_shear_stress_type = local +ABL.surface_temp_flux = 0.0 +# Source +ICNS.source_terms = BoussinesqBuoyancy CoriolisForcing GeostrophicForcing RayleighDamping NonLinearSGSTerm DragForcing +Temperature.source_terms = DragTempForcing +RayleighDamping.force_coord_directions= 0 0 1 +DragForcing.sponge_strength=0 +BoussinesqBuoyancy.reference_temperature = 300.0 +BoussinesqBuoyancy.thermal_expansion_coeff = 0.003333 +#CoriolisForcing.east_vector = 1.0 0.0 0.0 +#CoriolisForcing.latitude = 45.0 +#CoriolisForcing.north_vector = 0.0 1.0 0.0 +#CoriolisForcing.rotational_time_period = 86400.0 +CoriolisForcing.east_vector = 1.0 0.0 0.0 +CoriolisForcing.north_vector = 0.0 1.0 0.0 +CoriolisForcing.latitude = 90.0 +CoriolisForcing.rotational_time_period = 125663.706143592 +GeostrophicForcing.geostrophic_wind = 10 0.0 0.0 +RayleighDamping.reference_velocity = 10 0.0 0.0 +RayleighDamping.length_sloped_damping = 150 +RayleighDamping.length_complete_damping = 50 +RayleighDamping.time_scale = 9.0 +# BC +zhi.type = "slip_wall" +zhi.temperature_type = "fixed_gradient" +zhi.temperature = 0.003 +zlo.type = "wall_model" +# MLMG +mac_proj.num_pre_smooth = 8 +mac_proj.num_post_smooth = 8 +mac_proj.mg_rtol = 1.0e-4 +mac_proj.mg_atol = 1.0e-8 +mac_proj.maxiter = 360 +diffusion.mg_rtol = 1e-6 +diffusion.mg_atol = 1e-8 +temperature_diffusion.mg_rtol = 1e-6 +temperature_diffusion.mg_rtol = 1e-8 +nodal_proj.num_pre_smooth = 8 +nodal_proj.num_post_smooth = 8 +nodal_proj.mg_rtol = 1.0e-4 +nodal_proj.mg_atol = 1.0e-8 +nodal_proj.maxiter = 360 +# Postprocessing +incflo.post_processing = averaging +averaging.type = TimeAveraging +averaging.labels = means stress +averaging.averaging_window = 14400 +averaging.averaging_start_time = 86400 +averaging.means.fields = velocity +averaging.means.averaging_type = ReAveraging +averaging.stress.fields = velocity +averaging.stress.averaging_type = ReynoldsStress diff --git a/test/test_files/abl_kosovic_neutral_ib/terrain.amrwind b/test/test_files/abl_kosovic_neutral_ib/terrain.amrwind new file mode 100644 index 0000000000..8ffee5533b --- /dev/null +++ b/test/test_files/abl_kosovic_neutral_ib/terrain.amrwind @@ -0,0 +1,4225 @@ +1024 1024 0 +1040 1024 0 +1056 1024 0 +1072 1024 0 +1088 1024 0 +1104 1024 0 +1120 1024 0 +1136 1024 0 +1152 1024 0 +1168 1024 0 +1184 1024 0 +1200 1024 0 +1216 1024 0 +1232 1024 0 +1248 1024 0 +1264 1024 0 +1280 1024 0 +1296 1024 0 +1312 1024 0 +1328 1024 0 +1344 1024 0 +1360 1024 0 +1376 1024 0 +1392 1024 0 +1408 1024 0 +1424 1024 0 +1440 1024 0 +1456 1024 0 +1472 1024 0 +1488 1024 0 +1504 1024 0 +1520 1024 0 +1536 1024 0 +1552 1024 0 +1568 1024 0 +1584 1024 0 +1600 1024 0 +1616 1024 0 +1632 1024 0 +1648 1024 0 +1664 1024 0 +1680 1024 0 +1696 1024 0 +1712 1024 0 +1728 1024 0 +1744 1024 0 +1760 1024 0 +1776 1024 0 +1792 1024 0 +1808 1024 0 +1824 1024 0 +1840 1024 0 +1856 1024 0 +1872 1024 0 +1888 1024 0 +1904 1024 0 +1920 1024 0 +1936 1024 0 +1952 1024 0 +1968 1024 0 +1984 1024 0 +2000 1024 0 +2016 1024 0 +2032 1024 0 +2048 1024 0 +1024 1040 0 +1040 1040 0 +1056 1040 0 +1072 1040 0 +1088 1040 0 +1104 1040 0 +1120 1040 0 +1136 1040 0 +1152 1040 0 +1168 1040 0 +1184 1040 0 +1200 1040 0 +1216 1040 0 +1232 1040 0 +1248 1040 0 +1264 1040 0 +1280 1040 0 +1296 1040 0 +1312 1040 0 +1328 1040 0 +1344 1040 0 +1360 1040 0 +1376 1040 0 +1392 1040 0 +1408 1040 0 +1424 1040 0 +1440 1040 0 +1456 1040 0 +1472 1040 0 +1488 1040 0 +1504 1040 0 +1520 1040 0 +1536 1040 0 +1552 1040 0 +1568 1040 0 +1584 1040 0 +1600 1040 0 +1616 1040 0 +1632 1040 0 +1648 1040 0 +1664 1040 0 +1680 1040 0 +1696 1040 0 +1712 1040 0 +1728 1040 0 +1744 1040 0 +1760 1040 0 +1776 1040 0 +1792 1040 0 +1808 1040 0 +1824 1040 0 +1840 1040 0 +1856 1040 0 +1872 1040 0 +1888 1040 0 +1904 1040 0 +1920 1040 0 +1936 1040 0 +1952 1040 0 +1968 1040 0 +1984 1040 0 +2000 1040 0 +2016 1040 0 +2032 1040 0 +2048 1040 0 +1024 1056 0 +1040 1056 0 +1056 1056 0 +1072 1056 0 +1088 1056 0 +1104 1056 0 +1120 1056 0 +1136 1056 0 +1152 1056 0 +1168 1056 0 +1184 1056 0 +1200 1056 0 +1216 1056 0 +1232 1056 0 +1248 1056 0 +1264 1056 0 +1280 1056 0 +1296 1056 0 +1312 1056 0 +1328 1056 0 +1344 1056 0 +1360 1056 0 +1376 1056 0 +1392 1056 0 +1408 1056 0 +1424 1056 0 +1440 1056 0 +1456 1056 0 +1472 1056 0 +1488 1056 0 +1504 1056 0 +1520 1056 0 +1536 1056 0 +1552 1056 0 +1568 1056 0 +1584 1056 0 +1600 1056 0 +1616 1056 0 +1632 1056 0 +1648 1056 0 +1664 1056 0 +1680 1056 0 +1696 1056 0 +1712 1056 0 +1728 1056 0 +1744 1056 0 +1760 1056 0 +1776 1056 0 +1792 1056 0 +1808 1056 0 +1824 1056 0 +1840 1056 0 +1856 1056 0 +1872 1056 0 +1888 1056 0 +1904 1056 0 +1920 1056 0 +1936 1056 0 +1952 1056 0 +1968 1056 0 +1984 1056 0 +2000 1056 0 +2016 1056 0 +2032 1056 0 +2048 1056 0 +1024 1072 0 +1040 1072 0 +1056 1072 0 +1072 1072 0 +1088 1072 0 +1104 1072 0 +1120 1072 0 +1136 1072 0 +1152 1072 0 +1168 1072 0 +1184 1072 0 +1200 1072 0 +1216 1072 0 +1232 1072 0 +1248 1072 0 +1264 1072 0 +1280 1072 0 +1296 1072 0 +1312 1072 0 +1328 1072 0 +1344 1072 0 +1360 1072 0 +1376 1072 0 +1392 1072 0 +1408 1072 0 +1424 1072 0 +1440 1072 0 +1456 1072 0 +1472 1072 0 +1488 1072 0 +1504 1072 0 +1520 1072 0 +1536 1072 0 +1552 1072 0 +1568 1072 0 +1584 1072 0 +1600 1072 0 +1616 1072 0 +1632 1072 0 +1648 1072 0 +1664 1072 0 +1680 1072 0 +1696 1072 0 +1712 1072 0 +1728 1072 0 +1744 1072 0 +1760 1072 0 +1776 1072 0 +1792 1072 0 +1808 1072 0 +1824 1072 0 +1840 1072 0 +1856 1072 0 +1872 1072 0 +1888 1072 0 +1904 1072 0 +1920 1072 0 +1936 1072 0 +1952 1072 0 +1968 1072 0 +1984 1072 0 +2000 1072 0 +2016 1072 0 +2032 1072 0 +2048 1072 0 +1024 1088 0 +1040 1088 0 +1056 1088 0 +1072 1088 0 +1088 1088 0 +1104 1088 0 +1120 1088 0 +1136 1088 0 +1152 1088 0 +1168 1088 0 +1184 1088 0 +1200 1088 0 +1216 1088 0 +1232 1088 0 +1248 1088 0 +1264 1088 0 +1280 1088 0 +1296 1088 0 +1312 1088 0 +1328 1088 0 +1344 1088 0 +1360 1088 0 +1376 1088 0 +1392 1088 0 +1408 1088 0 +1424 1088 0 +1440 1088 0 +1456 1088 0 +1472 1088 0 +1488 1088 0 +1504 1088 0 +1520 1088 0 +1536 1088 0 +1552 1088 0 +1568 1088 0 +1584 1088 0 +1600 1088 0 +1616 1088 0 +1632 1088 0 +1648 1088 0 +1664 1088 0 +1680 1088 0 +1696 1088 0 +1712 1088 0 +1728 1088 0 +1744 1088 0 +1760 1088 0 +1776 1088 0 +1792 1088 0 +1808 1088 0 +1824 1088 0 +1840 1088 0 +1856 1088 0 +1872 1088 0 +1888 1088 0 +1904 1088 0 +1920 1088 0 +1936 1088 0 +1952 1088 0 +1968 1088 0 +1984 1088 0 +2000 1088 0 +2016 1088 0 +2032 1088 0 +2048 1088 0 +1024 1104 0 +1040 1104 0 +1056 1104 0 +1072 1104 0 +1088 1104 0 +1104 1104 0 +1120 1104 0 +1136 1104 0 +1152 1104 0 +1168 1104 0 +1184 1104 0 +1200 1104 0 +1216 1104 0 +1232 1104 0 +1248 1104 0 +1264 1104 0 +1280 1104 0 +1296 1104 0 +1312 1104 0 +1328 1104 0 +1344 1104 0 +1360 1104 0 +1376 1104 0 +1392 1104 0 +1408 1104 0 +1424 1104 0 +1440 1104 0 +1456 1104 0 +1472 1104 0 +1488 1104 0 +1504 1104 0 +1520 1104 0 +1536 1104 0 +1552 1104 0 +1568 1104 0 +1584 1104 0 +1600 1104 0 +1616 1104 0 +1632 1104 0 +1648 1104 0 +1664 1104 0 +1680 1104 0 +1696 1104 0 +1712 1104 0 +1728 1104 0 +1744 1104 0 +1760 1104 0 +1776 1104 0 +1792 1104 0 +1808 1104 0 +1824 1104 0 +1840 1104 0 +1856 1104 0 +1872 1104 0 +1888 1104 0 +1904 1104 0 +1920 1104 0 +1936 1104 0 +1952 1104 0 +1968 1104 0 +1984 1104 0 +2000 1104 0 +2016 1104 0 +2032 1104 0 +2048 1104 0 +1024 1120 0 +1040 1120 0 +1056 1120 0 +1072 1120 0 +1088 1120 0 +1104 1120 0 +1120 1120 0 +1136 1120 0 +1152 1120 0 +1168 1120 0 +1184 1120 0 +1200 1120 0 +1216 1120 0 +1232 1120 0 +1248 1120 0 +1264 1120 0 +1280 1120 0 +1296 1120 0 +1312 1120 0 +1328 1120 0 +1344 1120 0 +1360 1120 0 +1376 1120 0 +1392 1120 0 +1408 1120 0 +1424 1120 0 +1440 1120 0 +1456 1120 0 +1472 1120 0 +1488 1120 0 +1504 1120 0 +1520 1120 0 +1536 1120 0 +1552 1120 0 +1568 1120 0 +1584 1120 0 +1600 1120 0 +1616 1120 0 +1632 1120 0 +1648 1120 0 +1664 1120 0 +1680 1120 0 +1696 1120 0 +1712 1120 0 +1728 1120 0 +1744 1120 0 +1760 1120 0 +1776 1120 0 +1792 1120 0 +1808 1120 0 +1824 1120 0 +1840 1120 0 +1856 1120 0 +1872 1120 0 +1888 1120 0 +1904 1120 0 +1920 1120 0 +1936 1120 0 +1952 1120 0 +1968 1120 0 +1984 1120 0 +2000 1120 0 +2016 1120 0 +2032 1120 0 +2048 1120 0 +1024 1136 0 +1040 1136 0 +1056 1136 0 +1072 1136 0 +1088 1136 0 +1104 1136 0 +1120 1136 0 +1136 1136 0 +1152 1136 0 +1168 1136 0 +1184 1136 0 +1200 1136 0 +1216 1136 0 +1232 1136 0 +1248 1136 0 +1264 1136 0 +1280 1136 0 +1296 1136 0 +1312 1136 0 +1328 1136 0 +1344 1136 0 +1360 1136 0 +1376 1136 0 +1392 1136 0 +1408 1136 0 +1424 1136 0 +1440 1136 0 +1456 1136 0 +1472 1136 0 +1488 1136 0 +1504 1136 0 +1520 1136 0 +1536 1136 0 +1552 1136 0 +1568 1136 0 +1584 1136 0 +1600 1136 0 +1616 1136 0 +1632 1136 0 +1648 1136 0 +1664 1136 0 +1680 1136 0 +1696 1136 0 +1712 1136 0 +1728 1136 0 +1744 1136 0 +1760 1136 0 +1776 1136 0 +1792 1136 0 +1808 1136 0 +1824 1136 0 +1840 1136 0 +1856 1136 0 +1872 1136 0 +1888 1136 0 +1904 1136 0 +1920 1136 0 +1936 1136 0 +1952 1136 0 +1968 1136 0 +1984 1136 0 +2000 1136 0 +2016 1136 0 +2032 1136 0 +2048 1136 0 +1024 1152 0 +1040 1152 0 +1056 1152 0 +1072 1152 0 +1088 1152 0 +1104 1152 0 +1120 1152 0 +1136 1152 0 +1152 1152 0 +1168 1152 0 +1184 1152 0 +1200 1152 0 +1216 1152 0 +1232 1152 0 +1248 1152 0 +1264 1152 0 +1280 1152 0 +1296 1152 0 +1312 1152 0 +1328 1152 0 +1344 1152 0 +1360 1152 0 +1376 1152 0 +1392 1152 0 +1408 1152 0 +1424 1152 0 +1440 1152 0 +1456 1152 0 +1472 1152 0 +1488 1152 0 +1504 1152 0 +1520 1152 0 +1536 1152 0 +1552 1152 0 +1568 1152 0 +1584 1152 0 +1600 1152 0 +1616 1152 0 +1632 1152 0 +1648 1152 0 +1664 1152 0 +1680 1152 0 +1696 1152 0 +1712 1152 0 +1728 1152 0 +1744 1152 0 +1760 1152 0 +1776 1152 0 +1792 1152 0 +1808 1152 0 +1824 1152 0 +1840 1152 0 +1856 1152 0 +1872 1152 0 +1888 1152 0 +1904 1152 0 +1920 1152 0 +1936 1152 0 +1952 1152 0 +1968 1152 0 +1984 1152 0 +2000 1152 0 +2016 1152 0 +2032 1152 0 +2048 1152 0 +1024 1168 0 +1040 1168 0 +1056 1168 0 +1072 1168 0 +1088 1168 0 +1104 1168 0 +1120 1168 0 +1136 1168 0 +1152 1168 0 +1168 1168 0 +1184 1168 0 +1200 1168 0 +1216 1168 0 +1232 1168 0 +1248 1168 0 +1264 1168 0 +1280 1168 0 +1296 1168 0 +1312 1168 0 +1328 1168 0 +1344 1168 0 +1360 1168 0 +1376 1168 0 +1392 1168 0 +1408 1168 0 +1424 1168 0 +1440 1168 0 +1456 1168 0 +1472 1168 0 +1488 1168 0 +1504 1168 0 +1520 1168 0 +1536 1168 0 +1552 1168 0 +1568 1168 0 +1584 1168 0 +1600 1168 0 +1616 1168 0 +1632 1168 0 +1648 1168 0 +1664 1168 0 +1680 1168 0 +1696 1168 0 +1712 1168 0 +1728 1168 0 +1744 1168 0 +1760 1168 0 +1776 1168 0 +1792 1168 0 +1808 1168 0 +1824 1168 0 +1840 1168 0 +1856 1168 0 +1872 1168 0 +1888 1168 0 +1904 1168 0 +1920 1168 0 +1936 1168 0 +1952 1168 0 +1968 1168 0 +1984 1168 0 +2000 1168 0 +2016 1168 0 +2032 1168 0 +2048 1168 0 +1024 1184 0 +1040 1184 0 +1056 1184 0 +1072 1184 0 +1088 1184 0 +1104 1184 0 +1120 1184 0 +1136 1184 0 +1152 1184 0 +1168 1184 0 +1184 1184 0 +1200 1184 0 +1216 1184 0 +1232 1184 0 +1248 1184 0 +1264 1184 0 +1280 1184 0 +1296 1184 0 +1312 1184 0 +1328 1184 0 +1344 1184 0 +1360 1184 0 +1376 1184 0 +1392 1184 0 +1408 1184 0 +1424 1184 0 +1440 1184 0 +1456 1184 0 +1472 1184 0 +1488 1184 0 +1504 1184 0 +1520 1184 0 +1536 1184 0 +1552 1184 0 +1568 1184 0 +1584 1184 0 +1600 1184 0 +1616 1184 0 +1632 1184 0 +1648 1184 0 +1664 1184 0 +1680 1184 0 +1696 1184 0 +1712 1184 0 +1728 1184 0 +1744 1184 0 +1760 1184 0 +1776 1184 0 +1792 1184 0 +1808 1184 0 +1824 1184 0 +1840 1184 0 +1856 1184 0 +1872 1184 0 +1888 1184 0 +1904 1184 0 +1920 1184 0 +1936 1184 0 +1952 1184 0 +1968 1184 0 +1984 1184 0 +2000 1184 0 +2016 1184 0 +2032 1184 0 +2048 1184 0 +1024 1200 0 +1040 1200 0 +1056 1200 0 +1072 1200 0 +1088 1200 0 +1104 1200 0 +1120 1200 0 +1136 1200 0 +1152 1200 0 +1168 1200 0 +1184 1200 0 +1200 1200 0 +1216 1200 0 +1232 1200 0 +1248 1200 0 +1264 1200 0 +1280 1200 0 +1296 1200 0 +1312 1200 0 +1328 1200 0 +1344 1200 0 +1360 1200 0 +1376 1200 0 +1392 1200 0 +1408 1200 0 +1424 1200 0 +1440 1200 0 +1456 1200 0 +1472 1200 0 +1488 1200 0 +1504 1200 0 +1520 1200 0 +1536 1200 0 +1552 1200 0 +1568 1200 0 +1584 1200 0 +1600 1200 0 +1616 1200 0 +1632 1200 0 +1648 1200 0 +1664 1200 0 +1680 1200 0 +1696 1200 0 +1712 1200 0 +1728 1200 0 +1744 1200 0 +1760 1200 0 +1776 1200 0 +1792 1200 0 +1808 1200 0 +1824 1200 0 +1840 1200 0 +1856 1200 0 +1872 1200 0 +1888 1200 0 +1904 1200 0 +1920 1200 0 +1936 1200 0 +1952 1200 0 +1968 1200 0 +1984 1200 0 +2000 1200 0 +2016 1200 0 +2032 1200 0 +2048 1200 0 +1024 1216 0 +1040 1216 0 +1056 1216 0 +1072 1216 0 +1088 1216 0 +1104 1216 0 +1120 1216 0 +1136 1216 0 +1152 1216 0 +1168 1216 0 +1184 1216 0 +1200 1216 0 +1216 1216 0 +1232 1216 0 +1248 1216 0 +1264 1216 0 +1280 1216 0 +1296 1216 0 +1312 1216 0 +1328 1216 0 +1344 1216 0 +1360 1216 0 +1376 1216 0 +1392 1216 0 +1408 1216 0 +1424 1216 0 +1440 1216 0 +1456 1216 0 +1472 1216 0 +1488 1216 0 +1504 1216 0 +1520 1216 0 +1536 1216 0 +1552 1216 0 +1568 1216 0 +1584 1216 0 +1600 1216 0 +1616 1216 0 +1632 1216 0 +1648 1216 0 +1664 1216 0 +1680 1216 0 +1696 1216 0 +1712 1216 0 +1728 1216 0 +1744 1216 0 +1760 1216 0 +1776 1216 0 +1792 1216 0 +1808 1216 0 +1824 1216 0 +1840 1216 0 +1856 1216 0 +1872 1216 0 +1888 1216 0 +1904 1216 0 +1920 1216 0 +1936 1216 0 +1952 1216 0 +1968 1216 0 +1984 1216 0 +2000 1216 0 +2016 1216 0 +2032 1216 0 +2048 1216 0 +1024 1232 0 +1040 1232 0 +1056 1232 0 +1072 1232 0 +1088 1232 0 +1104 1232 0 +1120 1232 0 +1136 1232 0 +1152 1232 0 +1168 1232 0 +1184 1232 0 +1200 1232 0 +1216 1232 0 +1232 1232 0 +1248 1232 0 +1264 1232 0 +1280 1232 0 +1296 1232 0 +1312 1232 0 +1328 1232 0 +1344 1232 0 +1360 1232 0 +1376 1232 0 +1392 1232 0 +1408 1232 0 +1424 1232 0 +1440 1232 0 +1456 1232 0 +1472 1232 0 +1488 1232 0 +1504 1232 0 +1520 1232 0 +1536 1232 0 +1552 1232 0 +1568 1232 0 +1584 1232 0 +1600 1232 0 +1616 1232 0 +1632 1232 0 +1648 1232 0 +1664 1232 0 +1680 1232 0 +1696 1232 0 +1712 1232 0 +1728 1232 0 +1744 1232 0 +1760 1232 0 +1776 1232 0 +1792 1232 0 +1808 1232 0 +1824 1232 0 +1840 1232 0 +1856 1232 0 +1872 1232 0 +1888 1232 0 +1904 1232 0 +1920 1232 0 +1936 1232 0 +1952 1232 0 +1968 1232 0 +1984 1232 0 +2000 1232 0 +2016 1232 0 +2032 1232 0 +2048 1232 0 +1024 1248 0 +1040 1248 0 +1056 1248 0 +1072 1248 0 +1088 1248 0 +1104 1248 0 +1120 1248 0 +1136 1248 0 +1152 1248 0 +1168 1248 0 +1184 1248 0 +1200 1248 0 +1216 1248 0 +1232 1248 0 +1248 1248 0 +1264 1248 0 +1280 1248 0 +1296 1248 0 +1312 1248 0 +1328 1248 0 +1344 1248 0 +1360 1248 0 +1376 1248 0 +1392 1248 0 +1408 1248 0 +1424 1248 0 +1440 1248 0 +1456 1248 0 +1472 1248 0 +1488 1248 0 +1504 1248 0 +1520 1248 0 +1536 1248 0 +1552 1248 0 +1568 1248 0 +1584 1248 0 +1600 1248 0 +1616 1248 0 +1632 1248 0 +1648 1248 0 +1664 1248 0 +1680 1248 0 +1696 1248 0 +1712 1248 0 +1728 1248 0 +1744 1248 0 +1760 1248 0 +1776 1248 0 +1792 1248 0 +1808 1248 0 +1824 1248 0 +1840 1248 0 +1856 1248 0 +1872 1248 0 +1888 1248 0 +1904 1248 0 +1920 1248 0 +1936 1248 0 +1952 1248 0 +1968 1248 0 +1984 1248 0 +2000 1248 0 +2016 1248 0 +2032 1248 0 +2048 1248 0 +1024 1264 0 +1040 1264 0 +1056 1264 0 +1072 1264 0 +1088 1264 0 +1104 1264 0 +1120 1264 0 +1136 1264 0 +1152 1264 0 +1168 1264 0 +1184 1264 0 +1200 1264 0 +1216 1264 0 +1232 1264 0 +1248 1264 0 +1264 1264 0 +1280 1264 0 +1296 1264 0 +1312 1264 0 +1328 1264 0 +1344 1264 0 +1360 1264 0 +1376 1264 0 +1392 1264 0 +1408 1264 0 +1424 1264 0 +1440 1264 0 +1456 1264 0 +1472 1264 0 +1488 1264 0 +1504 1264 0 +1520 1264 0 +1536 1264 0 +1552 1264 0 +1568 1264 0 +1584 1264 0 +1600 1264 0 +1616 1264 0 +1632 1264 0 +1648 1264 0 +1664 1264 0 +1680 1264 0 +1696 1264 0 +1712 1264 0 +1728 1264 0 +1744 1264 0 +1760 1264 0 +1776 1264 0 +1792 1264 0 +1808 1264 0 +1824 1264 0 +1840 1264 0 +1856 1264 0 +1872 1264 0 +1888 1264 0 +1904 1264 0 +1920 1264 0 +1936 1264 0 +1952 1264 0 +1968 1264 0 +1984 1264 0 +2000 1264 0 +2016 1264 0 +2032 1264 0 +2048 1264 0 +1024 1280 0 +1040 1280 0 +1056 1280 0 +1072 1280 0 +1088 1280 0 +1104 1280 0 +1120 1280 0 +1136 1280 0 +1152 1280 0 +1168 1280 0 +1184 1280 0 +1200 1280 0 +1216 1280 0 +1232 1280 0 +1248 1280 0 +1264 1280 0 +1280 1280 0 +1296 1280 0 +1312 1280 0 +1328 1280 0 +1344 1280 0 +1360 1280 0 +1376 1280 0 +1392 1280 0 +1408 1280 0 +1424 1280 0 +1440 1280 0 +1456 1280 0 +1472 1280 0 +1488 1280 0 +1504 1280 0 +1520 1280 0 +1536 1280 0 +1552 1280 0 +1568 1280 0 +1584 1280 0 +1600 1280 0 +1616 1280 0 +1632 1280 0 +1648 1280 0 +1664 1280 0 +1680 1280 0 +1696 1280 0 +1712 1280 0 +1728 1280 0 +1744 1280 0 +1760 1280 0 +1776 1280 0 +1792 1280 0 +1808 1280 0 +1824 1280 0 +1840 1280 0 +1856 1280 0 +1872 1280 0 +1888 1280 0 +1904 1280 0 +1920 1280 0 +1936 1280 0 +1952 1280 0 +1968 1280 0 +1984 1280 0 +2000 1280 0 +2016 1280 0 +2032 1280 0 +2048 1280 0 +1024 1296 0 +1040 1296 0 +1056 1296 0 +1072 1296 0 +1088 1296 0 +1104 1296 0 +1120 1296 0 +1136 1296 0 +1152 1296 0 +1168 1296 0 +1184 1296 0 +1200 1296 0 +1216 1296 0 +1232 1296 0 +1248 1296 0 +1264 1296 0 +1280 1296 0 +1296 1296 0 +1312 1296 0 +1328 1296 0 +1344 1296 0 +1360 1296 0 +1376 1296 0 +1392 1296 0 +1408 1296 0 +1424 1296 0 +1440 1296 0 +1456 1296 0 +1472 1296 0 +1488 1296 0 +1504 1296 0 +1520 1296 0 +1536 1296 0 +1552 1296 0 +1568 1296 0 +1584 1296 0 +1600 1296 0 +1616 1296 0 +1632 1296 0 +1648 1296 0 +1664 1296 0 +1680 1296 0 +1696 1296 0 +1712 1296 0 +1728 1296 0 +1744 1296 0 +1760 1296 0 +1776 1296 0 +1792 1296 0 +1808 1296 0 +1824 1296 0 +1840 1296 0 +1856 1296 0 +1872 1296 0 +1888 1296 0 +1904 1296 0 +1920 1296 0 +1936 1296 0 +1952 1296 0 +1968 1296 0 +1984 1296 0 +2000 1296 0 +2016 1296 0 +2032 1296 0 +2048 1296 0 +1024 1312 0 +1040 1312 0 +1056 1312 0 +1072 1312 0 +1088 1312 0 +1104 1312 0 +1120 1312 0 +1136 1312 0 +1152 1312 0 +1168 1312 0 +1184 1312 0 +1200 1312 0 +1216 1312 0 +1232 1312 0 +1248 1312 0 +1264 1312 0 +1280 1312 0 +1296 1312 0 +1312 1312 0 +1328 1312 0 +1344 1312 0 +1360 1312 0 +1376 1312 0 +1392 1312 0 +1408 1312 0 +1424 1312 0 +1440 1312 0 +1456 1312 0 +1472 1312 0 +1488 1312 0 +1504 1312 0 +1520 1312 0 +1536 1312 0 +1552 1312 0 +1568 1312 0 +1584 1312 0 +1600 1312 0 +1616 1312 0 +1632 1312 0 +1648 1312 0 +1664 1312 0 +1680 1312 0 +1696 1312 0 +1712 1312 0 +1728 1312 0 +1744 1312 0 +1760 1312 0 +1776 1312 0 +1792 1312 0 +1808 1312 0 +1824 1312 0 +1840 1312 0 +1856 1312 0 +1872 1312 0 +1888 1312 0 +1904 1312 0 +1920 1312 0 +1936 1312 0 +1952 1312 0 +1968 1312 0 +1984 1312 0 +2000 1312 0 +2016 1312 0 +2032 1312 0 +2048 1312 0 +1024 1328 0 +1040 1328 0 +1056 1328 0 +1072 1328 0 +1088 1328 0 +1104 1328 0 +1120 1328 0 +1136 1328 0 +1152 1328 0 +1168 1328 0 +1184 1328 0 +1200 1328 0 +1216 1328 0 +1232 1328 0 +1248 1328 0 +1264 1328 0 +1280 1328 0 +1296 1328 0 +1312 1328 0 +1328 1328 0 +1344 1328 0 +1360 1328 0 +1376 1328 0 +1392 1328 0 +1408 1328 0 +1424 1328 0 +1440 1328 0 +1456 1328 0 +1472 1328 0 +1488 1328 0 +1504 1328 0 +1520 1328 0 +1536 1328 0 +1552 1328 0 +1568 1328 0 +1584 1328 0 +1600 1328 0 +1616 1328 0 +1632 1328 0 +1648 1328 0 +1664 1328 0 +1680 1328 0 +1696 1328 0 +1712 1328 0 +1728 1328 0 +1744 1328 0 +1760 1328 0 +1776 1328 0 +1792 1328 0 +1808 1328 0 +1824 1328 0 +1840 1328 0 +1856 1328 0 +1872 1328 0 +1888 1328 0 +1904 1328 0 +1920 1328 0 +1936 1328 0 +1952 1328 0 +1968 1328 0 +1984 1328 0 +2000 1328 0 +2016 1328 0 +2032 1328 0 +2048 1328 0 +1024 1344 0 +1040 1344 0 +1056 1344 0 +1072 1344 0 +1088 1344 0 +1104 1344 0 +1120 1344 0 +1136 1344 0 +1152 1344 0 +1168 1344 0 +1184 1344 0 +1200 1344 0 +1216 1344 0 +1232 1344 0 +1248 1344 0 +1264 1344 0 +1280 1344 0 +1296 1344 0 +1312 1344 0 +1328 1344 0 +1344 1344 0 +1360 1344 0 +1376 1344 0 +1392 1344 0 +1408 1344 0 +1424 1344 0 +1440 1344 0 +1456 1344 0 +1472 1344 0 +1488 1344 0 +1504 1344 0 +1520 1344 0 +1536 1344 0 +1552 1344 0 +1568 1344 0 +1584 1344 0 +1600 1344 0 +1616 1344 0 +1632 1344 0 +1648 1344 0 +1664 1344 0 +1680 1344 0 +1696 1344 0 +1712 1344 0 +1728 1344 0 +1744 1344 0 +1760 1344 0 +1776 1344 0 +1792 1344 0 +1808 1344 0 +1824 1344 0 +1840 1344 0 +1856 1344 0 +1872 1344 0 +1888 1344 0 +1904 1344 0 +1920 1344 0 +1936 1344 0 +1952 1344 0 +1968 1344 0 +1984 1344 0 +2000 1344 0 +2016 1344 0 +2032 1344 0 +2048 1344 0 +1024 1360 0 +1040 1360 0 +1056 1360 0 +1072 1360 0 +1088 1360 0 +1104 1360 0 +1120 1360 0 +1136 1360 0 +1152 1360 0 +1168 1360 0 +1184 1360 0 +1200 1360 0 +1216 1360 0 +1232 1360 0 +1248 1360 0 +1264 1360 0 +1280 1360 0 +1296 1360 0 +1312 1360 0 +1328 1360 0 +1344 1360 0 +1360 1360 0 +1376 1360 0 +1392 1360 0 +1408 1360 0 +1424 1360 0 +1440 1360 0 +1456 1360 0 +1472 1360 0 +1488 1360 0 +1504 1360 0 +1520 1360 0 +1536 1360 0 +1552 1360 0 +1568 1360 0 +1584 1360 0 +1600 1360 0 +1616 1360 0 +1632 1360 0 +1648 1360 0 +1664 1360 0 +1680 1360 0 +1696 1360 0 +1712 1360 0 +1728 1360 0 +1744 1360 0 +1760 1360 0 +1776 1360 0 +1792 1360 0 +1808 1360 0 +1824 1360 0 +1840 1360 0 +1856 1360 0 +1872 1360 0 +1888 1360 0 +1904 1360 0 +1920 1360 0 +1936 1360 0 +1952 1360 0 +1968 1360 0 +1984 1360 0 +2000 1360 0 +2016 1360 0 +2032 1360 0 +2048 1360 0 +1024 1376 0 +1040 1376 0 +1056 1376 0 +1072 1376 0 +1088 1376 0 +1104 1376 0 +1120 1376 0 +1136 1376 0 +1152 1376 0 +1168 1376 0 +1184 1376 0 +1200 1376 0 +1216 1376 0 +1232 1376 0 +1248 1376 0 +1264 1376 0 +1280 1376 0 +1296 1376 0 +1312 1376 0 +1328 1376 0 +1344 1376 0 +1360 1376 0 +1376 1376 0 +1392 1376 0 +1408 1376 0 +1424 1376 0 +1440 1376 0 +1456 1376 0 +1472 1376 0 +1488 1376 0 +1504 1376 0 +1520 1376 0 +1536 1376 0 +1552 1376 0 +1568 1376 0 +1584 1376 0 +1600 1376 0 +1616 1376 0 +1632 1376 0 +1648 1376 0 +1664 1376 0 +1680 1376 0 +1696 1376 0 +1712 1376 0 +1728 1376 0 +1744 1376 0 +1760 1376 0 +1776 1376 0 +1792 1376 0 +1808 1376 0 +1824 1376 0 +1840 1376 0 +1856 1376 0 +1872 1376 0 +1888 1376 0 +1904 1376 0 +1920 1376 0 +1936 1376 0 +1952 1376 0 +1968 1376 0 +1984 1376 0 +2000 1376 0 +2016 1376 0 +2032 1376 0 +2048 1376 0 +1024 1392 0 +1040 1392 0 +1056 1392 0 +1072 1392 0 +1088 1392 0 +1104 1392 0 +1120 1392 0 +1136 1392 0 +1152 1392 0 +1168 1392 0 +1184 1392 0 +1200 1392 0 +1216 1392 0 +1232 1392 0 +1248 1392 0 +1264 1392 0 +1280 1392 0 +1296 1392 0 +1312 1392 0 +1328 1392 0 +1344 1392 0 +1360 1392 0 +1376 1392 0 +1392 1392 0 +1408 1392 0 +1424 1392 0 +1440 1392 0 +1456 1392 0 +1472 1392 0 +1488 1392 0 +1504 1392 0 +1520 1392 0 +1536 1392 0 +1552 1392 0 +1568 1392 0 +1584 1392 0 +1600 1392 0 +1616 1392 0 +1632 1392 0 +1648 1392 0 +1664 1392 0 +1680 1392 0 +1696 1392 0 +1712 1392 0 +1728 1392 0 +1744 1392 0 +1760 1392 0 +1776 1392 0 +1792 1392 0 +1808 1392 0 +1824 1392 0 +1840 1392 0 +1856 1392 0 +1872 1392 0 +1888 1392 0 +1904 1392 0 +1920 1392 0 +1936 1392 0 +1952 1392 0 +1968 1392 0 +1984 1392 0 +2000 1392 0 +2016 1392 0 +2032 1392 0 +2048 1392 0 +1024 1408 0 +1040 1408 0 +1056 1408 0 +1072 1408 0 +1088 1408 0 +1104 1408 0 +1120 1408 0 +1136 1408 0 +1152 1408 0 +1168 1408 0 +1184 1408 0 +1200 1408 0 +1216 1408 0 +1232 1408 0 +1248 1408 0 +1264 1408 0 +1280 1408 0 +1296 1408 0 +1312 1408 0 +1328 1408 0 +1344 1408 0 +1360 1408 0 +1376 1408 0 +1392 1408 0 +1408 1408 0 +1424 1408 0 +1440 1408 0 +1456 1408 0 +1472 1408 0 +1488 1408 0 +1504 1408 0 +1520 1408 0 +1536 1408 0 +1552 1408 0 +1568 1408 0 +1584 1408 0 +1600 1408 0 +1616 1408 0 +1632 1408 0 +1648 1408 0 +1664 1408 0 +1680 1408 0 +1696 1408 0 +1712 1408 0 +1728 1408 0 +1744 1408 0 +1760 1408 0 +1776 1408 0 +1792 1408 0 +1808 1408 0 +1824 1408 0 +1840 1408 0 +1856 1408 0 +1872 1408 0 +1888 1408 0 +1904 1408 0 +1920 1408 0 +1936 1408 0 +1952 1408 0 +1968 1408 0 +1984 1408 0 +2000 1408 0 +2016 1408 0 +2032 1408 0 +2048 1408 0 +1024 1424 0 +1040 1424 0 +1056 1424 0 +1072 1424 0 +1088 1424 0 +1104 1424 0 +1120 1424 0 +1136 1424 0 +1152 1424 0 +1168 1424 0 +1184 1424 0 +1200 1424 0 +1216 1424 0 +1232 1424 0 +1248 1424 0 +1264 1424 0 +1280 1424 0 +1296 1424 0 +1312 1424 0 +1328 1424 0 +1344 1424 0 +1360 1424 0 +1376 1424 0 +1392 1424 0 +1408 1424 0 +1424 1424 0 +1440 1424 0 +1456 1424 0 +1472 1424 0 +1488 1424 0 +1504 1424 0 +1520 1424 0 +1536 1424 0 +1552 1424 0 +1568 1424 0 +1584 1424 0 +1600 1424 0 +1616 1424 0 +1632 1424 0 +1648 1424 0 +1664 1424 0 +1680 1424 0 +1696 1424 0 +1712 1424 0 +1728 1424 0 +1744 1424 0 +1760 1424 0 +1776 1424 0 +1792 1424 0 +1808 1424 0 +1824 1424 0 +1840 1424 0 +1856 1424 0 +1872 1424 0 +1888 1424 0 +1904 1424 0 +1920 1424 0 +1936 1424 0 +1952 1424 0 +1968 1424 0 +1984 1424 0 +2000 1424 0 +2016 1424 0 +2032 1424 0 +2048 1424 0 +1024 1440 0 +1040 1440 0 +1056 1440 0 +1072 1440 0 +1088 1440 0 +1104 1440 0 +1120 1440 0 +1136 1440 0 +1152 1440 0 +1168 1440 0 +1184 1440 0 +1200 1440 0 +1216 1440 0 +1232 1440 0 +1248 1440 0 +1264 1440 0 +1280 1440 0 +1296 1440 0 +1312 1440 0 +1328 1440 0 +1344 1440 0 +1360 1440 0 +1376 1440 0 +1392 1440 0 +1408 1440 0 +1424 1440 0 +1440 1440 0 +1456 1440 0 +1472 1440 0 +1488 1440 0 +1504 1440 0 +1520 1440 0 +1536 1440 0 +1552 1440 0 +1568 1440 0 +1584 1440 0 +1600 1440 0 +1616 1440 0 +1632 1440 0 +1648 1440 0 +1664 1440 0 +1680 1440 0 +1696 1440 0 +1712 1440 0 +1728 1440 0 +1744 1440 0 +1760 1440 0 +1776 1440 0 +1792 1440 0 +1808 1440 0 +1824 1440 0 +1840 1440 0 +1856 1440 0 +1872 1440 0 +1888 1440 0 +1904 1440 0 +1920 1440 0 +1936 1440 0 +1952 1440 0 +1968 1440 0 +1984 1440 0 +2000 1440 0 +2016 1440 0 +2032 1440 0 +2048 1440 0 +1024 1456 0 +1040 1456 0 +1056 1456 0 +1072 1456 0 +1088 1456 0 +1104 1456 0 +1120 1456 0 +1136 1456 0 +1152 1456 0 +1168 1456 0 +1184 1456 0 +1200 1456 0 +1216 1456 0 +1232 1456 0 +1248 1456 0 +1264 1456 0 +1280 1456 0 +1296 1456 0 +1312 1456 0 +1328 1456 0 +1344 1456 0 +1360 1456 0 +1376 1456 0 +1392 1456 0 +1408 1456 0 +1424 1456 0 +1440 1456 0 +1456 1456 0 +1472 1456 0 +1488 1456 0 +1504 1456 0 +1520 1456 0 +1536 1456 0 +1552 1456 0 +1568 1456 0 +1584 1456 0 +1600 1456 0 +1616 1456 0 +1632 1456 0 +1648 1456 0 +1664 1456 0 +1680 1456 0 +1696 1456 0 +1712 1456 0 +1728 1456 0 +1744 1456 0 +1760 1456 0 +1776 1456 0 +1792 1456 0 +1808 1456 0 +1824 1456 0 +1840 1456 0 +1856 1456 0 +1872 1456 0 +1888 1456 0 +1904 1456 0 +1920 1456 0 +1936 1456 0 +1952 1456 0 +1968 1456 0 +1984 1456 0 +2000 1456 0 +2016 1456 0 +2032 1456 0 +2048 1456 0 +1024 1472 0 +1040 1472 0 +1056 1472 0 +1072 1472 0 +1088 1472 0 +1104 1472 0 +1120 1472 0 +1136 1472 0 +1152 1472 0 +1168 1472 0 +1184 1472 0 +1200 1472 0 +1216 1472 0 +1232 1472 0 +1248 1472 0 +1264 1472 0 +1280 1472 0 +1296 1472 0 +1312 1472 0 +1328 1472 0 +1344 1472 0 +1360 1472 0 +1376 1472 0 +1392 1472 0 +1408 1472 0 +1424 1472 0 +1440 1472 0 +1456 1472 0 +1472 1472 0 +1488 1472 0 +1504 1472 0 +1520 1472 0 +1536 1472 0 +1552 1472 0 +1568 1472 0 +1584 1472 0 +1600 1472 0 +1616 1472 0 +1632 1472 0 +1648 1472 0 +1664 1472 0 +1680 1472 0 +1696 1472 0 +1712 1472 0 +1728 1472 0 +1744 1472 0 +1760 1472 0 +1776 1472 0 +1792 1472 0 +1808 1472 0 +1824 1472 0 +1840 1472 0 +1856 1472 0 +1872 1472 0 +1888 1472 0 +1904 1472 0 +1920 1472 0 +1936 1472 0 +1952 1472 0 +1968 1472 0 +1984 1472 0 +2000 1472 0 +2016 1472 0 +2032 1472 0 +2048 1472 0 +1024 1488 0 +1040 1488 0 +1056 1488 0 +1072 1488 0 +1088 1488 0 +1104 1488 0 +1120 1488 0 +1136 1488 0 +1152 1488 0 +1168 1488 0 +1184 1488 0 +1200 1488 0 +1216 1488 0 +1232 1488 0 +1248 1488 0 +1264 1488 0 +1280 1488 0 +1296 1488 0 +1312 1488 0 +1328 1488 0 +1344 1488 0 +1360 1488 0 +1376 1488 0 +1392 1488 0 +1408 1488 0 +1424 1488 0 +1440 1488 0 +1456 1488 0 +1472 1488 0 +1488 1488 0 +1504 1488 0 +1520 1488 0 +1536 1488 0 +1552 1488 0 +1568 1488 0 +1584 1488 0 +1600 1488 0 +1616 1488 0 +1632 1488 0 +1648 1488 0 +1664 1488 0 +1680 1488 0 +1696 1488 0 +1712 1488 0 +1728 1488 0 +1744 1488 0 +1760 1488 0 +1776 1488 0 +1792 1488 0 +1808 1488 0 +1824 1488 0 +1840 1488 0 +1856 1488 0 +1872 1488 0 +1888 1488 0 +1904 1488 0 +1920 1488 0 +1936 1488 0 +1952 1488 0 +1968 1488 0 +1984 1488 0 +2000 1488 0 +2016 1488 0 +2032 1488 0 +2048 1488 0 +1024 1504 0 +1040 1504 0 +1056 1504 0 +1072 1504 0 +1088 1504 0 +1104 1504 0 +1120 1504 0 +1136 1504 0 +1152 1504 0 +1168 1504 0 +1184 1504 0 +1200 1504 0 +1216 1504 0 +1232 1504 0 +1248 1504 0 +1264 1504 0 +1280 1504 0 +1296 1504 0 +1312 1504 0 +1328 1504 0 +1344 1504 0 +1360 1504 0 +1376 1504 0 +1392 1504 0 +1408 1504 0 +1424 1504 0 +1440 1504 0 +1456 1504 0 +1472 1504 0 +1488 1504 0 +1504 1504 0 +1520 1504 0 +1536 1504 0 +1552 1504 0 +1568 1504 0 +1584 1504 0 +1600 1504 0 +1616 1504 0 +1632 1504 0 +1648 1504 0 +1664 1504 0 +1680 1504 0 +1696 1504 0 +1712 1504 0 +1728 1504 0 +1744 1504 0 +1760 1504 0 +1776 1504 0 +1792 1504 0 +1808 1504 0 +1824 1504 0 +1840 1504 0 +1856 1504 0 +1872 1504 0 +1888 1504 0 +1904 1504 0 +1920 1504 0 +1936 1504 0 +1952 1504 0 +1968 1504 0 +1984 1504 0 +2000 1504 0 +2016 1504 0 +2032 1504 0 +2048 1504 0 +1024 1520 0 +1040 1520 0 +1056 1520 0 +1072 1520 0 +1088 1520 0 +1104 1520 0 +1120 1520 0 +1136 1520 0 +1152 1520 0 +1168 1520 0 +1184 1520 0 +1200 1520 0 +1216 1520 0 +1232 1520 0 +1248 1520 0 +1264 1520 0 +1280 1520 0 +1296 1520 0 +1312 1520 0 +1328 1520 0 +1344 1520 0 +1360 1520 0 +1376 1520 0 +1392 1520 0 +1408 1520 0 +1424 1520 0 +1440 1520 0 +1456 1520 0 +1472 1520 0 +1488 1520 0 +1504 1520 0 +1520 1520 0 +1536 1520 0 +1552 1520 0 +1568 1520 0 +1584 1520 0 +1600 1520 0 +1616 1520 0 +1632 1520 0 +1648 1520 0 +1664 1520 0 +1680 1520 0 +1696 1520 0 +1712 1520 0 +1728 1520 0 +1744 1520 0 +1760 1520 0 +1776 1520 0 +1792 1520 0 +1808 1520 0 +1824 1520 0 +1840 1520 0 +1856 1520 0 +1872 1520 0 +1888 1520 0 +1904 1520 0 +1920 1520 0 +1936 1520 0 +1952 1520 0 +1968 1520 0 +1984 1520 0 +2000 1520 0 +2016 1520 0 +2032 1520 0 +2048 1520 0 +1024 1536 0 +1040 1536 0 +1056 1536 0 +1072 1536 0 +1088 1536 0 +1104 1536 0 +1120 1536 0 +1136 1536 0 +1152 1536 0 +1168 1536 0 +1184 1536 0 +1200 1536 0 +1216 1536 0 +1232 1536 0 +1248 1536 0 +1264 1536 0 +1280 1536 0 +1296 1536 0 +1312 1536 0 +1328 1536 0 +1344 1536 0 +1360 1536 0 +1376 1536 0 +1392 1536 0 +1408 1536 0 +1424 1536 0 +1440 1536 0 +1456 1536 0 +1472 1536 0 +1488 1536 0 +1504 1536 0 +1520 1536 0 +1536 1536 0 +1552 1536 0 +1568 1536 0 +1584 1536 0 +1600 1536 0 +1616 1536 0 +1632 1536 0 +1648 1536 0 +1664 1536 0 +1680 1536 0 +1696 1536 0 +1712 1536 0 +1728 1536 0 +1744 1536 0 +1760 1536 0 +1776 1536 0 +1792 1536 0 +1808 1536 0 +1824 1536 0 +1840 1536 0 +1856 1536 0 +1872 1536 0 +1888 1536 0 +1904 1536 0 +1920 1536 0 +1936 1536 0 +1952 1536 0 +1968 1536 0 +1984 1536 0 +2000 1536 0 +2016 1536 0 +2032 1536 0 +2048 1536 0 +1024 1552 0 +1040 1552 0 +1056 1552 0 +1072 1552 0 +1088 1552 0 +1104 1552 0 +1120 1552 0 +1136 1552 0 +1152 1552 0 +1168 1552 0 +1184 1552 0 +1200 1552 0 +1216 1552 0 +1232 1552 0 +1248 1552 0 +1264 1552 0 +1280 1552 0 +1296 1552 0 +1312 1552 0 +1328 1552 0 +1344 1552 0 +1360 1552 0 +1376 1552 0 +1392 1552 0 +1408 1552 0 +1424 1552 0 +1440 1552 0 +1456 1552 0 +1472 1552 0 +1488 1552 0 +1504 1552 0 +1520 1552 0 +1536 1552 0 +1552 1552 0 +1568 1552 0 +1584 1552 0 +1600 1552 0 +1616 1552 0 +1632 1552 0 +1648 1552 0 +1664 1552 0 +1680 1552 0 +1696 1552 0 +1712 1552 0 +1728 1552 0 +1744 1552 0 +1760 1552 0 +1776 1552 0 +1792 1552 0 +1808 1552 0 +1824 1552 0 +1840 1552 0 +1856 1552 0 +1872 1552 0 +1888 1552 0 +1904 1552 0 +1920 1552 0 +1936 1552 0 +1952 1552 0 +1968 1552 0 +1984 1552 0 +2000 1552 0 +2016 1552 0 +2032 1552 0 +2048 1552 0 +1024 1568 0 +1040 1568 0 +1056 1568 0 +1072 1568 0 +1088 1568 0 +1104 1568 0 +1120 1568 0 +1136 1568 0 +1152 1568 0 +1168 1568 0 +1184 1568 0 +1200 1568 0 +1216 1568 0 +1232 1568 0 +1248 1568 0 +1264 1568 0 +1280 1568 0 +1296 1568 0 +1312 1568 0 +1328 1568 0 +1344 1568 0 +1360 1568 0 +1376 1568 0 +1392 1568 0 +1408 1568 0 +1424 1568 0 +1440 1568 0 +1456 1568 0 +1472 1568 0 +1488 1568 0 +1504 1568 0 +1520 1568 0 +1536 1568 0 +1552 1568 0 +1568 1568 0 +1584 1568 0 +1600 1568 0 +1616 1568 0 +1632 1568 0 +1648 1568 0 +1664 1568 0 +1680 1568 0 +1696 1568 0 +1712 1568 0 +1728 1568 0 +1744 1568 0 +1760 1568 0 +1776 1568 0 +1792 1568 0 +1808 1568 0 +1824 1568 0 +1840 1568 0 +1856 1568 0 +1872 1568 0 +1888 1568 0 +1904 1568 0 +1920 1568 0 +1936 1568 0 +1952 1568 0 +1968 1568 0 +1984 1568 0 +2000 1568 0 +2016 1568 0 +2032 1568 0 +2048 1568 0 +1024 1584 0 +1040 1584 0 +1056 1584 0 +1072 1584 0 +1088 1584 0 +1104 1584 0 +1120 1584 0 +1136 1584 0 +1152 1584 0 +1168 1584 0 +1184 1584 0 +1200 1584 0 +1216 1584 0 +1232 1584 0 +1248 1584 0 +1264 1584 0 +1280 1584 0 +1296 1584 0 +1312 1584 0 +1328 1584 0 +1344 1584 0 +1360 1584 0 +1376 1584 0 +1392 1584 0 +1408 1584 0 +1424 1584 0 +1440 1584 0 +1456 1584 0 +1472 1584 0 +1488 1584 0 +1504 1584 0 +1520 1584 0 +1536 1584 0 +1552 1584 0 +1568 1584 0 +1584 1584 0 +1600 1584 0 +1616 1584 0 +1632 1584 0 +1648 1584 0 +1664 1584 0 +1680 1584 0 +1696 1584 0 +1712 1584 0 +1728 1584 0 +1744 1584 0 +1760 1584 0 +1776 1584 0 +1792 1584 0 +1808 1584 0 +1824 1584 0 +1840 1584 0 +1856 1584 0 +1872 1584 0 +1888 1584 0 +1904 1584 0 +1920 1584 0 +1936 1584 0 +1952 1584 0 +1968 1584 0 +1984 1584 0 +2000 1584 0 +2016 1584 0 +2032 1584 0 +2048 1584 0 +1024 1600 0 +1040 1600 0 +1056 1600 0 +1072 1600 0 +1088 1600 0 +1104 1600 0 +1120 1600 0 +1136 1600 0 +1152 1600 0 +1168 1600 0 +1184 1600 0 +1200 1600 0 +1216 1600 0 +1232 1600 0 +1248 1600 0 +1264 1600 0 +1280 1600 0 +1296 1600 0 +1312 1600 0 +1328 1600 0 +1344 1600 0 +1360 1600 0 +1376 1600 0 +1392 1600 0 +1408 1600 0 +1424 1600 0 +1440 1600 0 +1456 1600 0 +1472 1600 0 +1488 1600 0 +1504 1600 0 +1520 1600 0 +1536 1600 0 +1552 1600 0 +1568 1600 0 +1584 1600 0 +1600 1600 0 +1616 1600 0 +1632 1600 0 +1648 1600 0 +1664 1600 0 +1680 1600 0 +1696 1600 0 +1712 1600 0 +1728 1600 0 +1744 1600 0 +1760 1600 0 +1776 1600 0 +1792 1600 0 +1808 1600 0 +1824 1600 0 +1840 1600 0 +1856 1600 0 +1872 1600 0 +1888 1600 0 +1904 1600 0 +1920 1600 0 +1936 1600 0 +1952 1600 0 +1968 1600 0 +1984 1600 0 +2000 1600 0 +2016 1600 0 +2032 1600 0 +2048 1600 0 +1024 1616 0 +1040 1616 0 +1056 1616 0 +1072 1616 0 +1088 1616 0 +1104 1616 0 +1120 1616 0 +1136 1616 0 +1152 1616 0 +1168 1616 0 +1184 1616 0 +1200 1616 0 +1216 1616 0 +1232 1616 0 +1248 1616 0 +1264 1616 0 +1280 1616 0 +1296 1616 0 +1312 1616 0 +1328 1616 0 +1344 1616 0 +1360 1616 0 +1376 1616 0 +1392 1616 0 +1408 1616 0 +1424 1616 0 +1440 1616 0 +1456 1616 0 +1472 1616 0 +1488 1616 0 +1504 1616 0 +1520 1616 0 +1536 1616 0 +1552 1616 0 +1568 1616 0 +1584 1616 0 +1600 1616 0 +1616 1616 0 +1632 1616 0 +1648 1616 0 +1664 1616 0 +1680 1616 0 +1696 1616 0 +1712 1616 0 +1728 1616 0 +1744 1616 0 +1760 1616 0 +1776 1616 0 +1792 1616 0 +1808 1616 0 +1824 1616 0 +1840 1616 0 +1856 1616 0 +1872 1616 0 +1888 1616 0 +1904 1616 0 +1920 1616 0 +1936 1616 0 +1952 1616 0 +1968 1616 0 +1984 1616 0 +2000 1616 0 +2016 1616 0 +2032 1616 0 +2048 1616 0 +1024 1632 0 +1040 1632 0 +1056 1632 0 +1072 1632 0 +1088 1632 0 +1104 1632 0 +1120 1632 0 +1136 1632 0 +1152 1632 0 +1168 1632 0 +1184 1632 0 +1200 1632 0 +1216 1632 0 +1232 1632 0 +1248 1632 0 +1264 1632 0 +1280 1632 0 +1296 1632 0 +1312 1632 0 +1328 1632 0 +1344 1632 0 +1360 1632 0 +1376 1632 0 +1392 1632 0 +1408 1632 0 +1424 1632 0 +1440 1632 0 +1456 1632 0 +1472 1632 0 +1488 1632 0 +1504 1632 0 +1520 1632 0 +1536 1632 0 +1552 1632 0 +1568 1632 0 +1584 1632 0 +1600 1632 0 +1616 1632 0 +1632 1632 0 +1648 1632 0 +1664 1632 0 +1680 1632 0 +1696 1632 0 +1712 1632 0 +1728 1632 0 +1744 1632 0 +1760 1632 0 +1776 1632 0 +1792 1632 0 +1808 1632 0 +1824 1632 0 +1840 1632 0 +1856 1632 0 +1872 1632 0 +1888 1632 0 +1904 1632 0 +1920 1632 0 +1936 1632 0 +1952 1632 0 +1968 1632 0 +1984 1632 0 +2000 1632 0 +2016 1632 0 +2032 1632 0 +2048 1632 0 +1024 1648 0 +1040 1648 0 +1056 1648 0 +1072 1648 0 +1088 1648 0 +1104 1648 0 +1120 1648 0 +1136 1648 0 +1152 1648 0 +1168 1648 0 +1184 1648 0 +1200 1648 0 +1216 1648 0 +1232 1648 0 +1248 1648 0 +1264 1648 0 +1280 1648 0 +1296 1648 0 +1312 1648 0 +1328 1648 0 +1344 1648 0 +1360 1648 0 +1376 1648 0 +1392 1648 0 +1408 1648 0 +1424 1648 0 +1440 1648 0 +1456 1648 0 +1472 1648 0 +1488 1648 0 +1504 1648 0 +1520 1648 0 +1536 1648 0 +1552 1648 0 +1568 1648 0 +1584 1648 0 +1600 1648 0 +1616 1648 0 +1632 1648 0 +1648 1648 0 +1664 1648 0 +1680 1648 0 +1696 1648 0 +1712 1648 0 +1728 1648 0 +1744 1648 0 +1760 1648 0 +1776 1648 0 +1792 1648 0 +1808 1648 0 +1824 1648 0 +1840 1648 0 +1856 1648 0 +1872 1648 0 +1888 1648 0 +1904 1648 0 +1920 1648 0 +1936 1648 0 +1952 1648 0 +1968 1648 0 +1984 1648 0 +2000 1648 0 +2016 1648 0 +2032 1648 0 +2048 1648 0 +1024 1664 0 +1040 1664 0 +1056 1664 0 +1072 1664 0 +1088 1664 0 +1104 1664 0 +1120 1664 0 +1136 1664 0 +1152 1664 0 +1168 1664 0 +1184 1664 0 +1200 1664 0 +1216 1664 0 +1232 1664 0 +1248 1664 0 +1264 1664 0 +1280 1664 0 +1296 1664 0 +1312 1664 0 +1328 1664 0 +1344 1664 0 +1360 1664 0 +1376 1664 0 +1392 1664 0 +1408 1664 0 +1424 1664 0 +1440 1664 0 +1456 1664 0 +1472 1664 0 +1488 1664 0 +1504 1664 0 +1520 1664 0 +1536 1664 0 +1552 1664 0 +1568 1664 0 +1584 1664 0 +1600 1664 0 +1616 1664 0 +1632 1664 0 +1648 1664 0 +1664 1664 0 +1680 1664 0 +1696 1664 0 +1712 1664 0 +1728 1664 0 +1744 1664 0 +1760 1664 0 +1776 1664 0 +1792 1664 0 +1808 1664 0 +1824 1664 0 +1840 1664 0 +1856 1664 0 +1872 1664 0 +1888 1664 0 +1904 1664 0 +1920 1664 0 +1936 1664 0 +1952 1664 0 +1968 1664 0 +1984 1664 0 +2000 1664 0 +2016 1664 0 +2032 1664 0 +2048 1664 0 +1024 1680 0 +1040 1680 0 +1056 1680 0 +1072 1680 0 +1088 1680 0 +1104 1680 0 +1120 1680 0 +1136 1680 0 +1152 1680 0 +1168 1680 0 +1184 1680 0 +1200 1680 0 +1216 1680 0 +1232 1680 0 +1248 1680 0 +1264 1680 0 +1280 1680 0 +1296 1680 0 +1312 1680 0 +1328 1680 0 +1344 1680 0 +1360 1680 0 +1376 1680 0 +1392 1680 0 +1408 1680 0 +1424 1680 0 +1440 1680 0 +1456 1680 0 +1472 1680 0 +1488 1680 0 +1504 1680 0 +1520 1680 0 +1536 1680 0 +1552 1680 0 +1568 1680 0 +1584 1680 0 +1600 1680 0 +1616 1680 0 +1632 1680 0 +1648 1680 0 +1664 1680 0 +1680 1680 0 +1696 1680 0 +1712 1680 0 +1728 1680 0 +1744 1680 0 +1760 1680 0 +1776 1680 0 +1792 1680 0 +1808 1680 0 +1824 1680 0 +1840 1680 0 +1856 1680 0 +1872 1680 0 +1888 1680 0 +1904 1680 0 +1920 1680 0 +1936 1680 0 +1952 1680 0 +1968 1680 0 +1984 1680 0 +2000 1680 0 +2016 1680 0 +2032 1680 0 +2048 1680 0 +1024 1696 0 +1040 1696 0 +1056 1696 0 +1072 1696 0 +1088 1696 0 +1104 1696 0 +1120 1696 0 +1136 1696 0 +1152 1696 0 +1168 1696 0 +1184 1696 0 +1200 1696 0 +1216 1696 0 +1232 1696 0 +1248 1696 0 +1264 1696 0 +1280 1696 0 +1296 1696 0 +1312 1696 0 +1328 1696 0 +1344 1696 0 +1360 1696 0 +1376 1696 0 +1392 1696 0 +1408 1696 0 +1424 1696 0 +1440 1696 0 +1456 1696 0 +1472 1696 0 +1488 1696 0 +1504 1696 0 +1520 1696 0 +1536 1696 0 +1552 1696 0 +1568 1696 0 +1584 1696 0 +1600 1696 0 +1616 1696 0 +1632 1696 0 +1648 1696 0 +1664 1696 0 +1680 1696 0 +1696 1696 0 +1712 1696 0 +1728 1696 0 +1744 1696 0 +1760 1696 0 +1776 1696 0 +1792 1696 0 +1808 1696 0 +1824 1696 0 +1840 1696 0 +1856 1696 0 +1872 1696 0 +1888 1696 0 +1904 1696 0 +1920 1696 0 +1936 1696 0 +1952 1696 0 +1968 1696 0 +1984 1696 0 +2000 1696 0 +2016 1696 0 +2032 1696 0 +2048 1696 0 +1024 1712 0 +1040 1712 0 +1056 1712 0 +1072 1712 0 +1088 1712 0 +1104 1712 0 +1120 1712 0 +1136 1712 0 +1152 1712 0 +1168 1712 0 +1184 1712 0 +1200 1712 0 +1216 1712 0 +1232 1712 0 +1248 1712 0 +1264 1712 0 +1280 1712 0 +1296 1712 0 +1312 1712 0 +1328 1712 0 +1344 1712 0 +1360 1712 0 +1376 1712 0 +1392 1712 0 +1408 1712 0 +1424 1712 0 +1440 1712 0 +1456 1712 0 +1472 1712 0 +1488 1712 0 +1504 1712 0 +1520 1712 0 +1536 1712 0 +1552 1712 0 +1568 1712 0 +1584 1712 0 +1600 1712 0 +1616 1712 0 +1632 1712 0 +1648 1712 0 +1664 1712 0 +1680 1712 0 +1696 1712 0 +1712 1712 0 +1728 1712 0 +1744 1712 0 +1760 1712 0 +1776 1712 0 +1792 1712 0 +1808 1712 0 +1824 1712 0 +1840 1712 0 +1856 1712 0 +1872 1712 0 +1888 1712 0 +1904 1712 0 +1920 1712 0 +1936 1712 0 +1952 1712 0 +1968 1712 0 +1984 1712 0 +2000 1712 0 +2016 1712 0 +2032 1712 0 +2048 1712 0 +1024 1728 0 +1040 1728 0 +1056 1728 0 +1072 1728 0 +1088 1728 0 +1104 1728 0 +1120 1728 0 +1136 1728 0 +1152 1728 0 +1168 1728 0 +1184 1728 0 +1200 1728 0 +1216 1728 0 +1232 1728 0 +1248 1728 0 +1264 1728 0 +1280 1728 0 +1296 1728 0 +1312 1728 0 +1328 1728 0 +1344 1728 0 +1360 1728 0 +1376 1728 0 +1392 1728 0 +1408 1728 0 +1424 1728 0 +1440 1728 0 +1456 1728 0 +1472 1728 0 +1488 1728 0 +1504 1728 0 +1520 1728 0 +1536 1728 0 +1552 1728 0 +1568 1728 0 +1584 1728 0 +1600 1728 0 +1616 1728 0 +1632 1728 0 +1648 1728 0 +1664 1728 0 +1680 1728 0 +1696 1728 0 +1712 1728 0 +1728 1728 0 +1744 1728 0 +1760 1728 0 +1776 1728 0 +1792 1728 0 +1808 1728 0 +1824 1728 0 +1840 1728 0 +1856 1728 0 +1872 1728 0 +1888 1728 0 +1904 1728 0 +1920 1728 0 +1936 1728 0 +1952 1728 0 +1968 1728 0 +1984 1728 0 +2000 1728 0 +2016 1728 0 +2032 1728 0 +2048 1728 0 +1024 1744 0 +1040 1744 0 +1056 1744 0 +1072 1744 0 +1088 1744 0 +1104 1744 0 +1120 1744 0 +1136 1744 0 +1152 1744 0 +1168 1744 0 +1184 1744 0 +1200 1744 0 +1216 1744 0 +1232 1744 0 +1248 1744 0 +1264 1744 0 +1280 1744 0 +1296 1744 0 +1312 1744 0 +1328 1744 0 +1344 1744 0 +1360 1744 0 +1376 1744 0 +1392 1744 0 +1408 1744 0 +1424 1744 0 +1440 1744 0 +1456 1744 0 +1472 1744 0 +1488 1744 0 +1504 1744 0 +1520 1744 0 +1536 1744 0 +1552 1744 0 +1568 1744 0 +1584 1744 0 +1600 1744 0 +1616 1744 0 +1632 1744 0 +1648 1744 0 +1664 1744 0 +1680 1744 0 +1696 1744 0 +1712 1744 0 +1728 1744 0 +1744 1744 0 +1760 1744 0 +1776 1744 0 +1792 1744 0 +1808 1744 0 +1824 1744 0 +1840 1744 0 +1856 1744 0 +1872 1744 0 +1888 1744 0 +1904 1744 0 +1920 1744 0 +1936 1744 0 +1952 1744 0 +1968 1744 0 +1984 1744 0 +2000 1744 0 +2016 1744 0 +2032 1744 0 +2048 1744 0 +1024 1760 0 +1040 1760 0 +1056 1760 0 +1072 1760 0 +1088 1760 0 +1104 1760 0 +1120 1760 0 +1136 1760 0 +1152 1760 0 +1168 1760 0 +1184 1760 0 +1200 1760 0 +1216 1760 0 +1232 1760 0 +1248 1760 0 +1264 1760 0 +1280 1760 0 +1296 1760 0 +1312 1760 0 +1328 1760 0 +1344 1760 0 +1360 1760 0 +1376 1760 0 +1392 1760 0 +1408 1760 0 +1424 1760 0 +1440 1760 0 +1456 1760 0 +1472 1760 0 +1488 1760 0 +1504 1760 0 +1520 1760 0 +1536 1760 0 +1552 1760 0 +1568 1760 0 +1584 1760 0 +1600 1760 0 +1616 1760 0 +1632 1760 0 +1648 1760 0 +1664 1760 0 +1680 1760 0 +1696 1760 0 +1712 1760 0 +1728 1760 0 +1744 1760 0 +1760 1760 0 +1776 1760 0 +1792 1760 0 +1808 1760 0 +1824 1760 0 +1840 1760 0 +1856 1760 0 +1872 1760 0 +1888 1760 0 +1904 1760 0 +1920 1760 0 +1936 1760 0 +1952 1760 0 +1968 1760 0 +1984 1760 0 +2000 1760 0 +2016 1760 0 +2032 1760 0 +2048 1760 0 +1024 1776 0 +1040 1776 0 +1056 1776 0 +1072 1776 0 +1088 1776 0 +1104 1776 0 +1120 1776 0 +1136 1776 0 +1152 1776 0 +1168 1776 0 +1184 1776 0 +1200 1776 0 +1216 1776 0 +1232 1776 0 +1248 1776 0 +1264 1776 0 +1280 1776 0 +1296 1776 0 +1312 1776 0 +1328 1776 0 +1344 1776 0 +1360 1776 0 +1376 1776 0 +1392 1776 0 +1408 1776 0 +1424 1776 0 +1440 1776 0 +1456 1776 0 +1472 1776 0 +1488 1776 0 +1504 1776 0 +1520 1776 0 +1536 1776 0 +1552 1776 0 +1568 1776 0 +1584 1776 0 +1600 1776 0 +1616 1776 0 +1632 1776 0 +1648 1776 0 +1664 1776 0 +1680 1776 0 +1696 1776 0 +1712 1776 0 +1728 1776 0 +1744 1776 0 +1760 1776 0 +1776 1776 0 +1792 1776 0 +1808 1776 0 +1824 1776 0 +1840 1776 0 +1856 1776 0 +1872 1776 0 +1888 1776 0 +1904 1776 0 +1920 1776 0 +1936 1776 0 +1952 1776 0 +1968 1776 0 +1984 1776 0 +2000 1776 0 +2016 1776 0 +2032 1776 0 +2048 1776 0 +1024 1792 0 +1040 1792 0 +1056 1792 0 +1072 1792 0 +1088 1792 0 +1104 1792 0 +1120 1792 0 +1136 1792 0 +1152 1792 0 +1168 1792 0 +1184 1792 0 +1200 1792 0 +1216 1792 0 +1232 1792 0 +1248 1792 0 +1264 1792 0 +1280 1792 0 +1296 1792 0 +1312 1792 0 +1328 1792 0 +1344 1792 0 +1360 1792 0 +1376 1792 0 +1392 1792 0 +1408 1792 0 +1424 1792 0 +1440 1792 0 +1456 1792 0 +1472 1792 0 +1488 1792 0 +1504 1792 0 +1520 1792 0 +1536 1792 0 +1552 1792 0 +1568 1792 0 +1584 1792 0 +1600 1792 0 +1616 1792 0 +1632 1792 0 +1648 1792 0 +1664 1792 0 +1680 1792 0 +1696 1792 0 +1712 1792 0 +1728 1792 0 +1744 1792 0 +1760 1792 0 +1776 1792 0 +1792 1792 0 +1808 1792 0 +1824 1792 0 +1840 1792 0 +1856 1792 0 +1872 1792 0 +1888 1792 0 +1904 1792 0 +1920 1792 0 +1936 1792 0 +1952 1792 0 +1968 1792 0 +1984 1792 0 +2000 1792 0 +2016 1792 0 +2032 1792 0 +2048 1792 0 +1024 1808 0 +1040 1808 0 +1056 1808 0 +1072 1808 0 +1088 1808 0 +1104 1808 0 +1120 1808 0 +1136 1808 0 +1152 1808 0 +1168 1808 0 +1184 1808 0 +1200 1808 0 +1216 1808 0 +1232 1808 0 +1248 1808 0 +1264 1808 0 +1280 1808 0 +1296 1808 0 +1312 1808 0 +1328 1808 0 +1344 1808 0 +1360 1808 0 +1376 1808 0 +1392 1808 0 +1408 1808 0 +1424 1808 0 +1440 1808 0 +1456 1808 0 +1472 1808 0 +1488 1808 0 +1504 1808 0 +1520 1808 0 +1536 1808 0 +1552 1808 0 +1568 1808 0 +1584 1808 0 +1600 1808 0 +1616 1808 0 +1632 1808 0 +1648 1808 0 +1664 1808 0 +1680 1808 0 +1696 1808 0 +1712 1808 0 +1728 1808 0 +1744 1808 0 +1760 1808 0 +1776 1808 0 +1792 1808 0 +1808 1808 0 +1824 1808 0 +1840 1808 0 +1856 1808 0 +1872 1808 0 +1888 1808 0 +1904 1808 0 +1920 1808 0 +1936 1808 0 +1952 1808 0 +1968 1808 0 +1984 1808 0 +2000 1808 0 +2016 1808 0 +2032 1808 0 +2048 1808 0 +1024 1824 0 +1040 1824 0 +1056 1824 0 +1072 1824 0 +1088 1824 0 +1104 1824 0 +1120 1824 0 +1136 1824 0 +1152 1824 0 +1168 1824 0 +1184 1824 0 +1200 1824 0 +1216 1824 0 +1232 1824 0 +1248 1824 0 +1264 1824 0 +1280 1824 0 +1296 1824 0 +1312 1824 0 +1328 1824 0 +1344 1824 0 +1360 1824 0 +1376 1824 0 +1392 1824 0 +1408 1824 0 +1424 1824 0 +1440 1824 0 +1456 1824 0 +1472 1824 0 +1488 1824 0 +1504 1824 0 +1520 1824 0 +1536 1824 0 +1552 1824 0 +1568 1824 0 +1584 1824 0 +1600 1824 0 +1616 1824 0 +1632 1824 0 +1648 1824 0 +1664 1824 0 +1680 1824 0 +1696 1824 0 +1712 1824 0 +1728 1824 0 +1744 1824 0 +1760 1824 0 +1776 1824 0 +1792 1824 0 +1808 1824 0 +1824 1824 0 +1840 1824 0 +1856 1824 0 +1872 1824 0 +1888 1824 0 +1904 1824 0 +1920 1824 0 +1936 1824 0 +1952 1824 0 +1968 1824 0 +1984 1824 0 +2000 1824 0 +2016 1824 0 +2032 1824 0 +2048 1824 0 +1024 1840 0 +1040 1840 0 +1056 1840 0 +1072 1840 0 +1088 1840 0 +1104 1840 0 +1120 1840 0 +1136 1840 0 +1152 1840 0 +1168 1840 0 +1184 1840 0 +1200 1840 0 +1216 1840 0 +1232 1840 0 +1248 1840 0 +1264 1840 0 +1280 1840 0 +1296 1840 0 +1312 1840 0 +1328 1840 0 +1344 1840 0 +1360 1840 0 +1376 1840 0 +1392 1840 0 +1408 1840 0 +1424 1840 0 +1440 1840 0 +1456 1840 0 +1472 1840 0 +1488 1840 0 +1504 1840 0 +1520 1840 0 +1536 1840 0 +1552 1840 0 +1568 1840 0 +1584 1840 0 +1600 1840 0 +1616 1840 0 +1632 1840 0 +1648 1840 0 +1664 1840 0 +1680 1840 0 +1696 1840 0 +1712 1840 0 +1728 1840 0 +1744 1840 0 +1760 1840 0 +1776 1840 0 +1792 1840 0 +1808 1840 0 +1824 1840 0 +1840 1840 0 +1856 1840 0 +1872 1840 0 +1888 1840 0 +1904 1840 0 +1920 1840 0 +1936 1840 0 +1952 1840 0 +1968 1840 0 +1984 1840 0 +2000 1840 0 +2016 1840 0 +2032 1840 0 +2048 1840 0 +1024 1856 0 +1040 1856 0 +1056 1856 0 +1072 1856 0 +1088 1856 0 +1104 1856 0 +1120 1856 0 +1136 1856 0 +1152 1856 0 +1168 1856 0 +1184 1856 0 +1200 1856 0 +1216 1856 0 +1232 1856 0 +1248 1856 0 +1264 1856 0 +1280 1856 0 +1296 1856 0 +1312 1856 0 +1328 1856 0 +1344 1856 0 +1360 1856 0 +1376 1856 0 +1392 1856 0 +1408 1856 0 +1424 1856 0 +1440 1856 0 +1456 1856 0 +1472 1856 0 +1488 1856 0 +1504 1856 0 +1520 1856 0 +1536 1856 0 +1552 1856 0 +1568 1856 0 +1584 1856 0 +1600 1856 0 +1616 1856 0 +1632 1856 0 +1648 1856 0 +1664 1856 0 +1680 1856 0 +1696 1856 0 +1712 1856 0 +1728 1856 0 +1744 1856 0 +1760 1856 0 +1776 1856 0 +1792 1856 0 +1808 1856 0 +1824 1856 0 +1840 1856 0 +1856 1856 0 +1872 1856 0 +1888 1856 0 +1904 1856 0 +1920 1856 0 +1936 1856 0 +1952 1856 0 +1968 1856 0 +1984 1856 0 +2000 1856 0 +2016 1856 0 +2032 1856 0 +2048 1856 0 +1024 1872 0 +1040 1872 0 +1056 1872 0 +1072 1872 0 +1088 1872 0 +1104 1872 0 +1120 1872 0 +1136 1872 0 +1152 1872 0 +1168 1872 0 +1184 1872 0 +1200 1872 0 +1216 1872 0 +1232 1872 0 +1248 1872 0 +1264 1872 0 +1280 1872 0 +1296 1872 0 +1312 1872 0 +1328 1872 0 +1344 1872 0 +1360 1872 0 +1376 1872 0 +1392 1872 0 +1408 1872 0 +1424 1872 0 +1440 1872 0 +1456 1872 0 +1472 1872 0 +1488 1872 0 +1504 1872 0 +1520 1872 0 +1536 1872 0 +1552 1872 0 +1568 1872 0 +1584 1872 0 +1600 1872 0 +1616 1872 0 +1632 1872 0 +1648 1872 0 +1664 1872 0 +1680 1872 0 +1696 1872 0 +1712 1872 0 +1728 1872 0 +1744 1872 0 +1760 1872 0 +1776 1872 0 +1792 1872 0 +1808 1872 0 +1824 1872 0 +1840 1872 0 +1856 1872 0 +1872 1872 0 +1888 1872 0 +1904 1872 0 +1920 1872 0 +1936 1872 0 +1952 1872 0 +1968 1872 0 +1984 1872 0 +2000 1872 0 +2016 1872 0 +2032 1872 0 +2048 1872 0 +1024 1888 0 +1040 1888 0 +1056 1888 0 +1072 1888 0 +1088 1888 0 +1104 1888 0 +1120 1888 0 +1136 1888 0 +1152 1888 0 +1168 1888 0 +1184 1888 0 +1200 1888 0 +1216 1888 0 +1232 1888 0 +1248 1888 0 +1264 1888 0 +1280 1888 0 +1296 1888 0 +1312 1888 0 +1328 1888 0 +1344 1888 0 +1360 1888 0 +1376 1888 0 +1392 1888 0 +1408 1888 0 +1424 1888 0 +1440 1888 0 +1456 1888 0 +1472 1888 0 +1488 1888 0 +1504 1888 0 +1520 1888 0 +1536 1888 0 +1552 1888 0 +1568 1888 0 +1584 1888 0 +1600 1888 0 +1616 1888 0 +1632 1888 0 +1648 1888 0 +1664 1888 0 +1680 1888 0 +1696 1888 0 +1712 1888 0 +1728 1888 0 +1744 1888 0 +1760 1888 0 +1776 1888 0 +1792 1888 0 +1808 1888 0 +1824 1888 0 +1840 1888 0 +1856 1888 0 +1872 1888 0 +1888 1888 0 +1904 1888 0 +1920 1888 0 +1936 1888 0 +1952 1888 0 +1968 1888 0 +1984 1888 0 +2000 1888 0 +2016 1888 0 +2032 1888 0 +2048 1888 0 +1024 1904 0 +1040 1904 0 +1056 1904 0 +1072 1904 0 +1088 1904 0 +1104 1904 0 +1120 1904 0 +1136 1904 0 +1152 1904 0 +1168 1904 0 +1184 1904 0 +1200 1904 0 +1216 1904 0 +1232 1904 0 +1248 1904 0 +1264 1904 0 +1280 1904 0 +1296 1904 0 +1312 1904 0 +1328 1904 0 +1344 1904 0 +1360 1904 0 +1376 1904 0 +1392 1904 0 +1408 1904 0 +1424 1904 0 +1440 1904 0 +1456 1904 0 +1472 1904 0 +1488 1904 0 +1504 1904 0 +1520 1904 0 +1536 1904 0 +1552 1904 0 +1568 1904 0 +1584 1904 0 +1600 1904 0 +1616 1904 0 +1632 1904 0 +1648 1904 0 +1664 1904 0 +1680 1904 0 +1696 1904 0 +1712 1904 0 +1728 1904 0 +1744 1904 0 +1760 1904 0 +1776 1904 0 +1792 1904 0 +1808 1904 0 +1824 1904 0 +1840 1904 0 +1856 1904 0 +1872 1904 0 +1888 1904 0 +1904 1904 0 +1920 1904 0 +1936 1904 0 +1952 1904 0 +1968 1904 0 +1984 1904 0 +2000 1904 0 +2016 1904 0 +2032 1904 0 +2048 1904 0 +1024 1920 0 +1040 1920 0 +1056 1920 0 +1072 1920 0 +1088 1920 0 +1104 1920 0 +1120 1920 0 +1136 1920 0 +1152 1920 0 +1168 1920 0 +1184 1920 0 +1200 1920 0 +1216 1920 0 +1232 1920 0 +1248 1920 0 +1264 1920 0 +1280 1920 0 +1296 1920 0 +1312 1920 0 +1328 1920 0 +1344 1920 0 +1360 1920 0 +1376 1920 0 +1392 1920 0 +1408 1920 0 +1424 1920 0 +1440 1920 0 +1456 1920 0 +1472 1920 0 +1488 1920 0 +1504 1920 0 +1520 1920 0 +1536 1920 0 +1552 1920 0 +1568 1920 0 +1584 1920 0 +1600 1920 0 +1616 1920 0 +1632 1920 0 +1648 1920 0 +1664 1920 0 +1680 1920 0 +1696 1920 0 +1712 1920 0 +1728 1920 0 +1744 1920 0 +1760 1920 0 +1776 1920 0 +1792 1920 0 +1808 1920 0 +1824 1920 0 +1840 1920 0 +1856 1920 0 +1872 1920 0 +1888 1920 0 +1904 1920 0 +1920 1920 0 +1936 1920 0 +1952 1920 0 +1968 1920 0 +1984 1920 0 +2000 1920 0 +2016 1920 0 +2032 1920 0 +2048 1920 0 +1024 1936 0 +1040 1936 0 +1056 1936 0 +1072 1936 0 +1088 1936 0 +1104 1936 0 +1120 1936 0 +1136 1936 0 +1152 1936 0 +1168 1936 0 +1184 1936 0 +1200 1936 0 +1216 1936 0 +1232 1936 0 +1248 1936 0 +1264 1936 0 +1280 1936 0 +1296 1936 0 +1312 1936 0 +1328 1936 0 +1344 1936 0 +1360 1936 0 +1376 1936 0 +1392 1936 0 +1408 1936 0 +1424 1936 0 +1440 1936 0 +1456 1936 0 +1472 1936 0 +1488 1936 0 +1504 1936 0 +1520 1936 0 +1536 1936 0 +1552 1936 0 +1568 1936 0 +1584 1936 0 +1600 1936 0 +1616 1936 0 +1632 1936 0 +1648 1936 0 +1664 1936 0 +1680 1936 0 +1696 1936 0 +1712 1936 0 +1728 1936 0 +1744 1936 0 +1760 1936 0 +1776 1936 0 +1792 1936 0 +1808 1936 0 +1824 1936 0 +1840 1936 0 +1856 1936 0 +1872 1936 0 +1888 1936 0 +1904 1936 0 +1920 1936 0 +1936 1936 0 +1952 1936 0 +1968 1936 0 +1984 1936 0 +2000 1936 0 +2016 1936 0 +2032 1936 0 +2048 1936 0 +1024 1952 0 +1040 1952 0 +1056 1952 0 +1072 1952 0 +1088 1952 0 +1104 1952 0 +1120 1952 0 +1136 1952 0 +1152 1952 0 +1168 1952 0 +1184 1952 0 +1200 1952 0 +1216 1952 0 +1232 1952 0 +1248 1952 0 +1264 1952 0 +1280 1952 0 +1296 1952 0 +1312 1952 0 +1328 1952 0 +1344 1952 0 +1360 1952 0 +1376 1952 0 +1392 1952 0 +1408 1952 0 +1424 1952 0 +1440 1952 0 +1456 1952 0 +1472 1952 0 +1488 1952 0 +1504 1952 0 +1520 1952 0 +1536 1952 0 +1552 1952 0 +1568 1952 0 +1584 1952 0 +1600 1952 0 +1616 1952 0 +1632 1952 0 +1648 1952 0 +1664 1952 0 +1680 1952 0 +1696 1952 0 +1712 1952 0 +1728 1952 0 +1744 1952 0 +1760 1952 0 +1776 1952 0 +1792 1952 0 +1808 1952 0 +1824 1952 0 +1840 1952 0 +1856 1952 0 +1872 1952 0 +1888 1952 0 +1904 1952 0 +1920 1952 0 +1936 1952 0 +1952 1952 0 +1968 1952 0 +1984 1952 0 +2000 1952 0 +2016 1952 0 +2032 1952 0 +2048 1952 0 +1024 1968 0 +1040 1968 0 +1056 1968 0 +1072 1968 0 +1088 1968 0 +1104 1968 0 +1120 1968 0 +1136 1968 0 +1152 1968 0 +1168 1968 0 +1184 1968 0 +1200 1968 0 +1216 1968 0 +1232 1968 0 +1248 1968 0 +1264 1968 0 +1280 1968 0 +1296 1968 0 +1312 1968 0 +1328 1968 0 +1344 1968 0 +1360 1968 0 +1376 1968 0 +1392 1968 0 +1408 1968 0 +1424 1968 0 +1440 1968 0 +1456 1968 0 +1472 1968 0 +1488 1968 0 +1504 1968 0 +1520 1968 0 +1536 1968 0 +1552 1968 0 +1568 1968 0 +1584 1968 0 +1600 1968 0 +1616 1968 0 +1632 1968 0 +1648 1968 0 +1664 1968 0 +1680 1968 0 +1696 1968 0 +1712 1968 0 +1728 1968 0 +1744 1968 0 +1760 1968 0 +1776 1968 0 +1792 1968 0 +1808 1968 0 +1824 1968 0 +1840 1968 0 +1856 1968 0 +1872 1968 0 +1888 1968 0 +1904 1968 0 +1920 1968 0 +1936 1968 0 +1952 1968 0 +1968 1968 0 +1984 1968 0 +2000 1968 0 +2016 1968 0 +2032 1968 0 +2048 1968 0 +1024 1984 0 +1040 1984 0 +1056 1984 0 +1072 1984 0 +1088 1984 0 +1104 1984 0 +1120 1984 0 +1136 1984 0 +1152 1984 0 +1168 1984 0 +1184 1984 0 +1200 1984 0 +1216 1984 0 +1232 1984 0 +1248 1984 0 +1264 1984 0 +1280 1984 0 +1296 1984 0 +1312 1984 0 +1328 1984 0 +1344 1984 0 +1360 1984 0 +1376 1984 0 +1392 1984 0 +1408 1984 0 +1424 1984 0 +1440 1984 0 +1456 1984 0 +1472 1984 0 +1488 1984 0 +1504 1984 0 +1520 1984 0 +1536 1984 0 +1552 1984 0 +1568 1984 0 +1584 1984 0 +1600 1984 0 +1616 1984 0 +1632 1984 0 +1648 1984 0 +1664 1984 0 +1680 1984 0 +1696 1984 0 +1712 1984 0 +1728 1984 0 +1744 1984 0 +1760 1984 0 +1776 1984 0 +1792 1984 0 +1808 1984 0 +1824 1984 0 +1840 1984 0 +1856 1984 0 +1872 1984 0 +1888 1984 0 +1904 1984 0 +1920 1984 0 +1936 1984 0 +1952 1984 0 +1968 1984 0 +1984 1984 0 +2000 1984 0 +2016 1984 0 +2032 1984 0 +2048 1984 0 +1024 2000 0 +1040 2000 0 +1056 2000 0 +1072 2000 0 +1088 2000 0 +1104 2000 0 +1120 2000 0 +1136 2000 0 +1152 2000 0 +1168 2000 0 +1184 2000 0 +1200 2000 0 +1216 2000 0 +1232 2000 0 +1248 2000 0 +1264 2000 0 +1280 2000 0 +1296 2000 0 +1312 2000 0 +1328 2000 0 +1344 2000 0 +1360 2000 0 +1376 2000 0 +1392 2000 0 +1408 2000 0 +1424 2000 0 +1440 2000 0 +1456 2000 0 +1472 2000 0 +1488 2000 0 +1504 2000 0 +1520 2000 0 +1536 2000 0 +1552 2000 0 +1568 2000 0 +1584 2000 0 +1600 2000 0 +1616 2000 0 +1632 2000 0 +1648 2000 0 +1664 2000 0 +1680 2000 0 +1696 2000 0 +1712 2000 0 +1728 2000 0 +1744 2000 0 +1760 2000 0 +1776 2000 0 +1792 2000 0 +1808 2000 0 +1824 2000 0 +1840 2000 0 +1856 2000 0 +1872 2000 0 +1888 2000 0 +1904 2000 0 +1920 2000 0 +1936 2000 0 +1952 2000 0 +1968 2000 0 +1984 2000 0 +2000 2000 0 +2016 2000 0 +2032 2000 0 +2048 2000 0 +1024 2016 0 +1040 2016 0 +1056 2016 0 +1072 2016 0 +1088 2016 0 +1104 2016 0 +1120 2016 0 +1136 2016 0 +1152 2016 0 +1168 2016 0 +1184 2016 0 +1200 2016 0 +1216 2016 0 +1232 2016 0 +1248 2016 0 +1264 2016 0 +1280 2016 0 +1296 2016 0 +1312 2016 0 +1328 2016 0 +1344 2016 0 +1360 2016 0 +1376 2016 0 +1392 2016 0 +1408 2016 0 +1424 2016 0 +1440 2016 0 +1456 2016 0 +1472 2016 0 +1488 2016 0 +1504 2016 0 +1520 2016 0 +1536 2016 0 +1552 2016 0 +1568 2016 0 +1584 2016 0 +1600 2016 0 +1616 2016 0 +1632 2016 0 +1648 2016 0 +1664 2016 0 +1680 2016 0 +1696 2016 0 +1712 2016 0 +1728 2016 0 +1744 2016 0 +1760 2016 0 +1776 2016 0 +1792 2016 0 +1808 2016 0 +1824 2016 0 +1840 2016 0 +1856 2016 0 +1872 2016 0 +1888 2016 0 +1904 2016 0 +1920 2016 0 +1936 2016 0 +1952 2016 0 +1968 2016 0 +1984 2016 0 +2000 2016 0 +2016 2016 0 +2032 2016 0 +2048 2016 0 +1024 2032 0 +1040 2032 0 +1056 2032 0 +1072 2032 0 +1088 2032 0 +1104 2032 0 +1120 2032 0 +1136 2032 0 +1152 2032 0 +1168 2032 0 +1184 2032 0 +1200 2032 0 +1216 2032 0 +1232 2032 0 +1248 2032 0 +1264 2032 0 +1280 2032 0 +1296 2032 0 +1312 2032 0 +1328 2032 0 +1344 2032 0 +1360 2032 0 +1376 2032 0 +1392 2032 0 +1408 2032 0 +1424 2032 0 +1440 2032 0 +1456 2032 0 +1472 2032 0 +1488 2032 0 +1504 2032 0 +1520 2032 0 +1536 2032 0 +1552 2032 0 +1568 2032 0 +1584 2032 0 +1600 2032 0 +1616 2032 0 +1632 2032 0 +1648 2032 0 +1664 2032 0 +1680 2032 0 +1696 2032 0 +1712 2032 0 +1728 2032 0 +1744 2032 0 +1760 2032 0 +1776 2032 0 +1792 2032 0 +1808 2032 0 +1824 2032 0 +1840 2032 0 +1856 2032 0 +1872 2032 0 +1888 2032 0 +1904 2032 0 +1920 2032 0 +1936 2032 0 +1952 2032 0 +1968 2032 0 +1984 2032 0 +2000 2032 0 +2016 2032 0 +2032 2032 0 +2048 2032 0 +1024 2048 0 +1040 2048 0 +1056 2048 0 +1072 2048 0 +1088 2048 0 +1104 2048 0 +1120 2048 0 +1136 2048 0 +1152 2048 0 +1168 2048 0 +1184 2048 0 +1200 2048 0 +1216 2048 0 +1232 2048 0 +1248 2048 0 +1264 2048 0 +1280 2048 0 +1296 2048 0 +1312 2048 0 +1328 2048 0 +1344 2048 0 +1360 2048 0 +1376 2048 0 +1392 2048 0 +1408 2048 0 +1424 2048 0 +1440 2048 0 +1456 2048 0 +1472 2048 0 +1488 2048 0 +1504 2048 0 +1520 2048 0 +1536 2048 0 +1552 2048 0 +1568 2048 0 +1584 2048 0 +1600 2048 0 +1616 2048 0 +1632 2048 0 +1648 2048 0 +1664 2048 0 +1680 2048 0 +1696 2048 0 +1712 2048 0 +1728 2048 0 +1744 2048 0 +1760 2048 0 +1776 2048 0 +1792 2048 0 +1808 2048 0 +1824 2048 0 +1840 2048 0 +1856 2048 0 +1872 2048 0 +1888 2048 0 +1904 2048 0 +1920 2048 0 +1936 2048 0 +1952 2048 0 +1968 2048 0 +1984 2048 0 +2000 2048 0 +2016 2048 0 +2032 2048 0 +2048 2048 0 diff --git a/tools/terrain/NREL.yaml b/tools/terrain/NREL.yaml deleted file mode 100644 index 5d8722a657..0000000000 --- a/tools/terrain/NREL.yaml +++ /dev/null @@ -1,29 +0,0 @@ -solver: "amrWind" -caseParent: "/Users/hgopalan/Documents/P101_AMR-Wind/Data/tempGUI" -caseFolder: "NREL" -caseType: "terrain" -caseInitial: "amr" -domainType: "center" -centerLat: 39.90613 -centerLon: -105.216 -west: 10000 -east: 10000 -south: 20000 -north: 20000 -refHeight: 2000 -cellSize: 128 -verticalAR: 4 -timeMethod: "step" -numOfSteps: 5000 -plotOutput: 1000 -restartOutput: 1000 -windX: 10.0 -windY: 0.0 -windZ: 0.0 -refTemperature: 300.0 -refRoughness: 0.1 -refHeatflux: 0.0 -refLat: 39.90613 -refPeriod: 86164.0900027328 -includeCoriolis: true -turbineMarkType: "database" \ No newline at end of file diff --git a/tools/terrain/SRTM_to_STL_example.py b/tools/terrain/SRTM_to_STL_example.py deleted file mode 100644 index b60e54e9b0..0000000000 --- a/tools/terrain/SRTM_to_STL_example.py +++ /dev/null @@ -1,149 +0,0 @@ -def SRTM_Converter(outputDir,refLat,refLon,refHeight,left,right,bottom,top): - import os - import sys - import numpy as np - import matplotlib.pyplot as plt - from matplotlib.patches import Rectangle - import xarray as xr - from scipy.interpolate import RectBivariateSpline, griddata - import utm - from stl import mesh # install with `pip install numpy-stl` - from terrain import SRTM - product = 'SRTM1' # SRTM1 | SRTM3 (30- and 90-m DEM) - ds = 10. # output resolution - - refloc=(refLat,refLon,refHeight) - xmin,xmax = -left-ds/2,right+ds/2 - ymin,ymax = -bottom-ds/2,top+ds/2 - fringe_flat=150 - shiftFlatToZero=True - fringe_w = 3000 - fringe_s = 3000 - fringe_n = 3000 - fringe_e = 3000 - case = f'wfip_xm{abs(int(xmin))}to{int(xmax)}_ym{abs(int(ymin))}to{int(ymax)}_blendFlat3N3S3E3W_ff{fringe_flat}' - x1 = np.arange(xmin, xmax+ds, ds) - y1 = np.arange(ymin, ymax+ds, ds) - xsurf,ysurf = np.meshgrid(x1, y1, indexing='ij') - print('The output bounding box is') - print('xmin: ',xsurf[0,0], '\nxmax: ',xsurf[-1,-1]) - print('ymin: ',ysurf[0,0], '\nymax: ',ysurf[-1,-1]) - srtm_bounds = west, south, east, north = (refloc[1]-0.5, refloc[0]-0.4, refloc[1]+0.62, refloc[0]+0.42) - srtm_output=f'{outdir}/{case}.tif' # need absolute path for GDAL - srtm = SRTM(srtm_bounds, fpath=srtm_output, product=product) - srtm.download() - x,y,z = srtm.to_terrain() - xref,yref,_,_ = utm.from_latlon(*refloc[:2], force_zone_number=srtm.zone_number) - vmin,vmax = 1500,2500 - fig,ax = plt.subplots(figsize=(12,8)) - cm = ax.pcolormesh(x-xref, y-yref, z, cmap='terrain')#,vmin=vmin,vmax=vmax) - cb = fig.colorbar(cm,ax=ax) - cb.set_label('elevation [m]',fontsize='x-large') - ax.tick_params(labelsize='large') - ax.set_xlabel('easting [m]') - ax.set_ylabel('northing [m]') - ax.set_title(f'{product} DEM projection') - ax.axis('scaled') - # bounding box for microscale region - les = Rectangle((xmin,ymin), xmax-xmin, ymax-ymin, edgecolor='r', lw=3, facecolor='0.5', alpha=0.5) - ax.add_patch(les) - interpfun = RectBivariateSpline(x[:,0]-xref, y[0,:]-yref, z) - zsrtm = interpfun(x1,y1,grid=True) - fig,ax = plt.subplots(figsize=(12,8)) - cm = ax.pcolormesh(xsurf, ysurf, zsrtm, cmap='terrain')#,vmin=vmin,vmax=vmax) - cb = fig.colorbar(cm,ax=ax) - cb.set_label('elevation [m]',fontsize='x-large') - ax.tick_params(labelsize='large') - ax.set_xlabel('easting [m]') - ax.set_ylabel('northing [m]') - ax.set_title(f'{product} terrain height') - ax.axis('scaled') - fig.savefig(f'{outdir}/elevation_srtm_{case}.png',dpi=150,bbox_inches='tight') - # check distance from west boundary - blend_w = np.ones(xsurf.shape) - if fringe_w > 0: - blend_w = np.minimum(np.maximum((xsurf-xmin-fringe_flat)/fringe_w, 0), 1) - blend_e = np.ones(xsurf.shape) - if fringe_e > 0: - blend_e = np.minimum(np.maximum((xmax-xsurf-fringe_flat)/fringe_e, 0), 1) - blend_s = np.ones(xsurf.shape) - if fringe_s > 0: - blend_s = np.minimum(np.maximum((ysurf-ymin-fringe_flat)/fringe_s, 0), 1) - blend_n = np.ones(xsurf.shape) - if fringe_n > 0: - blend_n = np.minimum(np.maximum((ymax-ysurf-fringe_flat)/fringe_n, 0), 1) - blend = blend_w * blend_e * blend_s * blend_n - fig,ax = plt.subplots(figsize=(12,8)) - cm = ax.pcolormesh(xsurf, ysurf, blend, cmap='magma') - cb = fig.colorbar(cm,ax=ax) - ax.tick_params(labelsize='large') - ax.set_xlabel('easting [m]') - ax.set_ylabel('northing [m]') - ax.set_title('blending function') - ax.axis('scaled') - z0 = np.amin(zsrtm) #0 #np.mean(zsrtm) - zflat = np.full(zsrtm.shape,z0) - zlowres = zflat - zblend = blend*zsrtm + (1-blend)*zlowres - fig,ax = plt.subplots(figsize=(12,8)) - cm = ax.pcolormesh(xsurf, ysurf, zblend, cmap='terrain')#,vmin=vmin,vmax=vmax) - cb = fig.colorbar(cm,ax=ax) - cb.set_label('elevation [m]',fontsize='x-large') - ax.tick_params(labelsize='large') - ax.set_xlabel('easting [m]') - ax.set_ylabel('northing [m]') - ax.set_title('blended terrain height') - ax.axis('scaled') - fig.savefig(f'{outdir}/elevation_blended_{case}.png',dpi=150,bbox_inches='tight') - if shiftFlatToZero: - zTerrainRef=zblend[0,0] - zblend = zblend - zblend[0,0] - case = case + '_flatz0' - if shiftFlatToZero: - fig,ax = plt.subplots(figsize=(12,8)) - cm = ax.pcolormesh(xsurf, ysurf, zblend, cmap='terrain')#,vmin=vmin,vmax=vmax) - cb = fig.colorbar(cm,ax=ax) - cb.set_label('elevation [m]',fontsize='x-large') - ax.tick_params(labelsize='large') - ax.set_xlabel('easting [m]') - ax.set_ylabel('northing [m]') - ax.set_title('shifted terrain height') - ax.axis('scaled') - fig.savefig(f'{outdir}/elevation_blended_{case}.png',dpi=150,bbox_inches='tight') - stlout = f'{outdir}/terrain.stl' - # output 'zblend' surface - can skip blending step and just output 'zsrtm' - Npts = np.prod(xsurf.shape) - stlpoints = np.stack((xsurf.ravel(), - ysurf.ravel(), - zblend.ravel()), # <-- output surface here - axis=-1) - - stlindices = np.reshape(np.arange(Npts), xsurf.shape) - Nx,Ny = xsurf.shape - Nfaces = (Nx-1)*(Ny-1)*2 - surf = mesh.Mesh(np.zeros(Nfaces, dtype=mesh.Mesh.dtype)) - iface = 0 - for i in range(Nx-1): - for j in range(Ny-1): - surf.vectors[iface,0,:] = stlpoints[stlindices[i,j],:] - surf.vectors[iface,1,:] = stlpoints[stlindices[i+1,j],:] - surf.vectors[iface,2,:] = stlpoints[stlindices[i+1,j+1],:] - surf.vectors[iface+1,0,:] = stlpoints[stlindices[i+1,j+1],:] - surf.vectors[iface+1,1,:] = stlpoints[stlindices[i,j+1],:] - surf.vectors[iface+1,2,:] = stlpoints[stlindices[i,j],:] - iface += 2 - assert (iface == Nfaces) - if (not dpath == '') and (not os.path.isdir(dpath)): - os.makedirs(dpath) - print('Created',dpath) - surf.save(stlout) - # surf.save(stlout, mode=mesh.stl.ASCII) # if ASCII STL is needed - print('Saved',stlout) - print(zblend[0,0]) - return xref,yref,zTerrainRef,srtm - - - - - - diff --git a/tools/terrain/backendInterface.py b/tools/terrain/backendInterface.py deleted file mode 100644 index 4a4a2f8ec3..0000000000 --- a/tools/terrain/backendInterface.py +++ /dev/null @@ -1,867 +0,0 @@ -''' -!----------------------------------------------------------------! -AMR - Wind back-end for cases with terrain ! -!----------------------------------------------------------------! -''' - -import yaml -from pathlib import Path -from terrain import SRTM -import numpy as np - - -class amrBackend(): - def __init__(self,yamlFile): - self.yamlFilePath = Path(yamlFile) - self.yamlFile=yaml.safe_load(self.yamlFilePath.open()) - self.createCase() - - def createCase(self): - self.caseParent=self.yamlFile['caseParent'] - self.caseName=self.yamlFile['caseFolder'] - self.caseType=self.yamlFile['caseType'] - self.caseInitial=self.yamlFile['caseInitial'] - caseDir=Path(self.caseParent,self.caseName) - self.caseDir=caseDir.as_posix() - caseDir.mkdir(parents=True,exist_ok=True) - casePrecursor=Path(self.caseParent,self.caseName,"precursor") - self.casePrecursor=casePrecursor.as_posix() - casePrecursor.mkdir(parents=True,exist_ok=True) - if(self.caseType=="terrain"): - caseTerrain=Path(self.caseParent,self.caseName,"terrain") - self.caseTerrain=caseTerrain.as_posix() - caseTerrain.mkdir(parents=True,exist_ok=True) - elif(self.caseType=="terrainTurbine"): - caseTerrain=Path(self.caseParent,self.caseName,"terrainTurbine") - self.caseTerrain=caseTerrain.as_posix() - caseTerrain.mkdir(parents=True,exist_ok=True) - #self.caseDomainType=self.yamlFile['domainType'] - # if(self.caseDomainType=="corners"): - # pass - self.caseNorth=self.yamlFile['north'] - self.caseSouth=self.yamlFile['south'] - self.caseEast=self.yamlFile['east'] - self.caseWest=self.yamlFile['west'] - # else: - self.caseCenterLat=self.yamlFile["centerLat"] - self.caseCenterLon=self.yamlFile["centerLon"] - self.refHeight=self.yamlFile["refHeight"] - # self.caseNorth=self.caseCenterLat+self.yamlFile['north'] - # self.caseSouth=self.caseCenterLat-self.yamlFile['south'] - # self.caseEast=self.caseCenterLon+self.yamlFile['east'] - # self.caseWest=self.caseCenterLon-self.yamlFile['west'] - - def createDomain(self): - # bounds = self.caseWest, self.caseSouth, self.caseEast, self.caseNorth - # self.terrainResolution=self.yamlFile['terrainSize'] - # dx = dy = self.terrainResolution - # product = 'SRTM1' - # try: - # tmpName=Path(self.caseParent,self.caseName,"terrain.tif") - # tmpName.unlink() - # print("Deleting file")ß - # except: - # pass - # srtm_output = Path(self.caseParent,self.caseName,"terrain.tif") - # self.srtm = SRTM(bounds,fpath=srtm_output.as_posix(),product=product) - # self.srtm.download() - # x1,x2,x3 = self.srtm.to_terrain(dx,dy) - # self.purgeCorner=self.yamlFile['purgeCorners'] - # cornerCut=self.purgeCorner - #self.terrainX1=x1[cornerCut:x1.shape[0]-cornerCut,cornerCut:x1.shape[1]-cornerCut] - #self.terrainX2=x2[cornerCut:x2.shape[0]-cornerCut,cornerCut:x2.shape[1]-cornerCut] - #self.terrainX3=x3[cornerCut:x3.shape[0]-cornerCut,cornerCut:x3.shape[1]-cornerCut] - import SRTM_to_STL_example as converter - self.xref,self.yref,self.zRef,self.srtm=converter.SRTM_Converter(Path(self.caseParent,self.caseName).as_posix(),self.caseCenterLat,self.caseCenterLon,self.refHeight, \ - self.caseWest,self.caseEast,self.caseSouth,self.caseNorth) - stlFile=Path(self.caseParent,self.caseName,"terrain.stl").as_posix() - import pyvista as pv - mesh=pv.read(stlFile) - x1=mesh.points[:,0] - x2=mesh.points[:,1] - x3=mesh.points[:,2] - self.terrainX1=x1[:] - self.terrainX2=x2[:] - self.terrainX3=x3[:] - #self.zRef=np.amin(self.terrainX3) - #meanZ3=np.mean(self.terrainX3.flatten(order='F')) - #print("Mean Height:",meanZ3) - - def createAMRFiles(self): - self.amrPrecursorFile=Path(self.caseParent,self.caseName,"precursor","precursor.inp").open("w") - self.amrPrecursorFile.write("# Generating the precursor file\n") - self.createPrecursorFiles() - if(self.caseType=='terrain'): - self.amrTerrainFile=Path(self.caseParent,self.caseName,"terrain","terrain.inp").open("w") - self.amrTerrainFile.write("# Generating the terrain file\n") - self.createTerrainFiles("terrain") - self.closeAMRFiles() - elif(self.caseType=='terrainTurbine'): - self.amrTerrainFile=Path(self.caseParent,self.caseName,"terrainTurbine","terrainTurbine.inp").open("w") - self.amrTerrainFile.write("# Generating the terrain file\n") - self.createTerrainFiles("terrainTurbine") - self.closeAMRFiles() - # Turbine files are not properly written - self.createTurbineFiles() - self.plotTurbines() - - def createPrecursorFiles(self): - print("Creating precursor") - self.createAMRGeometry(self.amrPrecursorFile,1) - self.createAMRGrid(self.amrPrecursorFile) - self.createAMRTime(self.amrPrecursorFile) - self.createSolverInfo(self.amrPrecursorFile) - self.createAMRTransport(self.amrPrecursorFile) - self.createAMRTurbulence(self.amrPrecursorFile) - self.createAMRABLData(self.amrPrecursorFile,0,1) - self.createAMRSourceTerm(self.amrPrecursorFile) - self.createAMRBC(self.amrPrecursorFile) - self.createAMRTolerance(self.amrPrecursorFile) - print(" Done creating precursor") - - def createTerrainFiles(self,folder): - print("Creating Terrain Files") - self.createAMRGeometry(self.amrTerrainFile,-1) - self.createAMRGrid(self.amrTerrainFile) - self.createAMRTime(self.amrTerrainFile) - if(self.caseType=='terrainTurbine'): - self.createSolverInfo(self.amrTerrainFile,1,1) - else: - self.createSolverInfo(self.amrTerrainFile,1) - self.createAMRTransport(self.amrTerrainFile) - self.createAMRTurbulence(self.amrTerrainFile) - self.createAMRABLData(self.amrTerrainFile,1,0) - if(self.caseType=='terrainTurbine'): - self.createAMRSourceTerm(self.amrTerrainFile,1,1) - else: - self.createAMRSourceTerm(self.amrTerrainFile,1) - self.createAMRBC(self.amrTerrainFile,1) - self.createAMRTolerance(self.amrTerrainFile,1) - self.writeTerrainData(folder) - self.writeRestart(self.amrTerrainFile) - self.createAMRPrecursorSampling(self.amrPrecursorFile) - # Terrain Monitoring and Refining - self.metMastRefinement(self.amrTerrainFile) - #self.metMastMonitoring(self.amrTerrainFile) - - def createAMRGeometry(self,target,periodic=-1): - target.write("# Geometry\n") - minX=np.amin(self.terrainX1) - minY=np.amin(self.terrainX2) - minZ=np.amin(self.terrainX3) - maxX=np.amax(self.terrainX1) - maxY=np.amax(self.terrainX2) - self.terrainZMax=np.amax(self.terrainX3) - # Add 1 km for ABL and 4 km for Rayleigh - self.ABLHeight=1000 - self.RDLHeight=2000 - self.maxZ=self.terrainZMax+self.ABLHeight+self.RDLHeight - self.maxZ=round(self.maxZ,-3) - target.write("geometry.prob_lo \t\t\t = %g %g %g \n"%(minX,minY,minZ)) - target.write("geometry.prob_hi \t\t\t = %g %g %g \n"%(maxX,maxY,self.maxZ)) - if(periodic==1): - target.write("geometry.is_periodic \t\t\t = 1 1 0\n") - else: - target.write("geometry.is_periodic \t\t\t = 0 0 0\n") - - def createAMRGrid(self,target): - self.caseCellSize=self.yamlFile['cellSize'] - nx=int((np.amax(self.terrainX1)-np.amin(self.terrainX1))/self.caseCellSize) - while (nx%8 !=0): - nx=nx+1 - ny=int((np.amax(self.terrainX2)-np.amin(self.terrainX2))/self.caseCellSize) - while (ny%8 !=0): - ny=ny+1 - # Keeping the vertical height to account for gravity waves - # terrainZMax=np.amax(self.terrainX3) - # # Add 4 km for Rayleigh - # zDomainHeight=terrainZMax+4000+4000 - # zDomainHeight=zDomainHeight-(zDomainHeight%1000) - # print("Terrain Maximum Height:",terrainZMax) - # print("Domain Height:",zDomainHeight) - self.caseverticalAR=self.yamlFile['verticalAR'] - nz=self.caseverticalAR*int(self.maxZ/self.caseCellSize) - while (nz%8 !=0): - nz=nz+1 - print("dx,dz",self.caseCellSize,self.maxZ/nz) - target.write("# Grid \n") - target.write("amr.n_cell \t\t\t = %g %g %g\n"%(nx,ny,nz)) - target.write("amr.max_level \t\t\t = 0\n") - - def createAMRTime(self,target): - self.timeMethod=self.yamlFile['timeMethod'] - if(self.timeMethod=="step"): - self.timeSteps=self.yamlFile["numOfSteps"] - else: - pass # Need to add parameters for physical time - self.plotOutput=self.yamlFile['plotOutput'] - self.restartOutput=self.yamlFile['restartOutput'] - target.write("time.stop_time \t\t\t = -1\n") - target.write("time.max_step \t\t\t = %g\n"%(self.timeSteps)) - target.write("time.initial_dt \t\t\t = 1.0\n") - target.write("time.fixed_dt \t\t\t = -1\n") - target.write("time.cfl \t\t\t = 0.9\n") - target.write('time.plot_interval \t\t\t = %g\n'%(self.plotOutput)) - target.write("time.checkpoint_interval \t\t\t = %g\n"%(self.restartOutput)) - - def createSolverInfo(self,target,terrain=-1,turbine=-1): - self.caseWindspeedX=self.yamlFile['windX'] - self.caseWindspeedY=self.yamlFile['windY'] - self.caseWindspeedZ=self.yamlFile['windZ'] - target.write("# incflo \n") - if(terrain==1 and turbine==1): - target.write("incflo.physics \t\t\t = ABL TerrainDrag Actuator\n") - elif(terrain==1): - target.write("incflo.physics \t\t\t = ABL TerrainDrag\n") - elif(turbine==1): - target.write("incflo.physics \t\t\t = ABL Actuator\n") - else: - target.write("incflo.physics \t\t\t = ABL\n") - target.write("incflo.density \t\t\t = 1.225\n") - target.write("incflo.gravity \t\t\t = 0. 0. -9.81 # Gravitational force (3D)\n") - target.write("incflo.velocity \t\t\t = %g %g %g \n"%(self.caseWindspeedX,self.caseWindspeedY,self.caseWindspeedZ)) - target.write("incflo.verbose \t\t\t = 0\n") - target.write("incflo.initial_iterations \t\t\t = 8\n") - target.write("incflo.do_initial_proj \t\t\t = true\n") - target.write("incflo.constant_density \t\t\t = true\n") - target.write("incflo.use_godunov \t\t\t = true\n") - target.write('incflo.godunov_type \t\t\t = "weno_z"\n') - target.write("incflo.diffusion_type \t\t\t = 2\n") - - def createAMRTransport(self,target): - target.write("# transport equation parameters \n") - target.write("transport.model \t\t\t = ConstTransport\n") - target.write("transport.viscosity \t\t\t = 1e-5\n") - target.write("transport.laminar_prandtl \t\t\t = 0.7\n") - target.write("transport.turbulent_prandtl \t\t\t = 0.333\n") - - def createAMRTurbulence(self,target): - target.write("# turbulence equation parameters \n") - target.write("turbulence.model \t\t\t = Kosovic\n") - target.write("Kosovic.refMOL \t\t\t = -1e30\n") - - def createAMRABLData(self,target,iomode=-1,fluctuations=1): - self.refTemperature=self.yamlFile["refTemperature"] - self.refRoughness=self.yamlFile["refRoughness"] - self.refHeatFlux=self.yamlFile["refHeatflux"] - target.write("# Atmospheric boundary layer\n") - if(fluctuations==1): - UPeriod=int((np.amax(self.terrainX1)-np.amin(self.terrainX1))/200) - VPeriod=int((np.amax(self.terrainX1)-np.amin(self.terrainX1))/200) - target.write("ABL.Uperiods \t\t\t = %g\n"%(UPeriod)) - target.write("ABL.Vperiods \t\t\t = %g\n"%(VPeriod)) - target.write("ABL.cutoff_height \t\t\t = 50.0\n") - target.write("ABL.deltaU \t\t\t = 1.0\n") - target.write("ABL.deltaV \t\t\t = 1.0\n") - target.write("ABL.perturb_ref_height \t\t\t = 50.0\n") - target.write("ABL.perturb_velocity \t\t\t = true\n") - target.write("ABL.perturb_temperature \t\t\t = false\n") - target.write("ABL.kappa \t\t\t = .41\n") - target.write("ABL.normal_direction \t\t\t = 2\n") - target.write("ABL.reference_temperature \t\t\t = %g\n"%(self.refTemperature)) - target.write("ABL.stats_output_format \t\t\t = netcdf\n") - target.write("ABL.surface_roughness_z0 \t\t\t = %g\n"%(self.refRoughness)) - # Write Heights - inversionHeight=round(self.terrainZMax,-3)+1000 - inversionLayerThickness=round(self.terrainZMax,-3)+1000+100 - lapseRate=0.003 - target.write("ABL.temperature_heights = %g %g %g %g %g \n"%(0.0,round(self.terrainZMax,-3),inversionHeight,inversionLayerThickness,self.maxZ)) - TRef=300 - print(self.maxZ-inversionLayerThickness) - target.write("ABL.temperature_values = %g %g %g %g %g "%(TRef,TRef,TRef,TRef+5,TRef+5+lapseRate*(self.maxZ-inversionLayerThickness))) - target.write("\n") - target.write("ABL.wall_shear_stress_type \t\t\t = local\n") - target.write("ABL.surface_temp_flux \t\t\t = %g\n"%(self.refHeatFlux)) - if(iomode==0): - target.write('ABL.bndry_file \t\t\t = "bndry_files"\n') - target.write("ABL.bndry_write_frequency \t\t\t = 100\n") - target.write("ABL.bndry_io_mode \t\t\t = 0\n") - if(self.caseWindspeedX>=0 and self.caseWindspeedY>=0): - target.write("ABL.bndry_planes \t\t\t = xlo ylo \n") - elif(self.caseWindspeedX>=0 and self.caseWindspeedY<0): - target.write("ABL.bndry_planes \t\t\t = xlo yhi \n") - if(self.caseWindspeedX<0 and self.caseWindspeedY>=0): - target.write("ABL.bndry_planes \t\t\t = xhi ylo \n") - elif(self.caseWindspeedX<0 and self.caseWindspeedY<0): - target.write("ABL.bndry_planes \t\t\t = xhi yhi \n") - # Guessing a start time far enough - M=np.sqrt(self.caseWindspeedX**2+self.caseWindspeedY**2) - dt=0.9*self.caseCellSize/M - startTime=0.25*(self.timeSteps/dt) - target.write("ABL.bndry_output_start_time \t\t\t = %g\n"%(startTime)) - target.write("ABL.bndry_var_names \t\t\t = velocity temperature\n") - target.write("ABL.bndry_output_format \t\t\t = native\n") - elif(iomode==1): - target.write('ABL.bndry_file \t\t\t = "../precursor/bndry_files"\n') - target.write("ABL.bndry_io_mode \t\t\t = 1\n") - target.write("ABL.bndry_var_names \t\t\t = velocity temperature\n") - target.write("ABL.bndry_output_format \t\t\t = native\n") - - def createAMRSourceTerm(self,target,terrain=-1,turbine=-1): - target.write("# Source\n") - refLat=self.yamlFile["refLat"] - refPeriod=self.yamlFile["refPeriod"] - try: - self.includeCoriolis=self.yamlFile["includeCoriolis"] - except: - self.includeCoriolis=False - if(self.includeCoriolis): - try: - self.forcingHeight=self.yamlFile["forcingHeight"] - except: - if(terrain==1 and turbine==1): - target.write("ICNS.source_terms \t\t\t = BoussinesqBuoyancy CoriolisForcing GeostrophicForcing RayleighDamping NonLinearSGSTerm DragForcing ActuatorForcing \n") - elif(terrain==1): - target.write("ICNS.source_terms \t\t\t = BoussinesqBuoyancy CoriolisForcing GeostrophicForcing RayleighDamping NonLinearSGSTerm DragForcing\n") - else: - target.write("ICNS.source_terms \t\t\t = BoussinesqBuoyancy CoriolisForcing GeostrophicForcing RayleighDamping NonLinearSGSTerm\n") - target.write("GeostrophicForcing.geostrophic_wind \t\t\t = %g %g %g\n"%(self.caseWindspeedX,self.caseWindspeedY,self.caseWindspeedZ)) - else: - if(terrain==1 and turbine==1): - target.write("ICNS.source_terms \t\t\t = BoussinesqBuoyancy CoriolisForcing ABLForcing RayleighDamping NonLinearSGSTerm DragForcing ActuatorForcing \n") - elif(terrain==1): - target.write("ICNS.source_terms \t\t\t = BoussinesqBuoyancy CoriolisForcing ABLForcing RayleighDamping NonLinearSGSTerm DragForcing\n") - else: - target.write("ICNS.source_terms \t\t\t = BoussinesqBuoyancy CoriolisForcing ABLForcing RayleighDamping NonLinearSGSTerm\n") - target.write("ABLForcing.abl_forcing_height \t\t\t = %g \n"%(self.forcingHeight)) - else: - try: - self.forcingHeight=self.yamlFile["forcingHeight"] - except: - if(terrain==1 and turbine==1): - target.write("ICNS.source_terms \t\t\t = BoussinesqBuoyancy GeostrophicForcing RayleighDamping NonLinearSGSTerm DragForcing ActuatorForcing \n") - elif(terrain==1): - target.write("ICNS.source_terms \t\t\t = BoussinesqBuoyancy GeostrophicForcing RayleighDamping NonLinearSGSTerm DragForcing\n") - else: - target.write("ICNS.source_terms \t\t\t = BoussinesqBuoyancy GeostrophicForcing RayleighDamping NonLinearSGSTerm\n") - target.write("GeostrophicForcing.geostrophic_wind \t\t\t = %g %g %g\n"%(self.caseWindspeedX,self.caseWindspeedY,self.caseWindspeedZ)) - else: - if(terrain==1 and turbine==1): - target.write("ICNS.source_terms \t\t\t = BoussinesqBuoyancy ABLForcing RayleighDamping NonLinearSGSTerm DragForcing ActuatorForcing \n") - elif(terrain==1): - target.write("ICNS.source_terms \t\t\t = BoussinesqBuoyancy ABLForcing RayleighDamping NonLinearSGSTerm DragForcing\n") - else: - target.write("ICNS.source_terms \t\t\t = BoussinesqBuoyancy ABLForcing RayleighDamping NonLinearSGSTerm\n") - target.write("ABLForcing.abl_forcing_height \t\t\t = %g \n"%(self.forcingHeight)) - if(terrain==1 or turbine==1): - target.write("Temperature.source_terms = DragTempForcing\n") - target.write("RayleighDamping.force_coord_directions= 0 0 1\n") - target.write("BoussinesqBuoyancy.reference_temperature \t\t\t = %g\n"%(self.refTemperature)) - target.write("BoussinesqBuoyancy.thermal_expansion_coeff \t\t\t = %g\n"%(1.0/self.refTemperature)) - if(self.includeCoriolis): - target.write("CoriolisForcing.east_vector \t\t\t = 1.0 0.0 0.0 \n") - target.write("CoriolisForcing.north_vector \t\t\t = 0.0 1.0 0.0 \n") - target.write("CoriolisForcing.latitude \t\t\t = %g \n"%(refLat)) - target.write("CoriolisForcing.rotational_time_period \t\t\t = %g \n"%(refPeriod)) - target.write("RayleighDamping.reference_velocity \t\t\t = %g %g %g\n"%(self.caseWindspeedX,self.caseWindspeedY,self.caseWindspeedZ)) - startRayleigh=self.maxZ-self.RDLHeight - target.write("RayleighDamping.length_sloped_damping \t\t\t = %g\n"%(500)) - target.write("RayleighDamping.length_complete_damping \t\t\t = %g\n"%(self.maxZ-startRayleigh-500)) - target.write("RayleighDamping.time_scale \t\t\t = 20.0\n") - - def createAMRBC(self,target,inflowOutflow=-1): - target.write("# BC \n") - if(inflowOutflow==1): - if(self.caseWindspeedX>=0): - target.write('xlo.type \t\t\t = "mass_inflow"\n') - target.write("xlo.density \t\t\t = 1.225\n") - target.write("xlo.temperature \t\t\t = 300\n") - target.write('xhi.type \t\t\t = "pressure_outflow"\n') - else: - target.write('xhi.type \t\t\t = "mass_inflow"\n') - target.write("xhi.density \t\t\t = 1.225\n") - target.write("xhi.temperature \t\t\t = 300\n") - target.write('xlo.type \t\t\t = "pressure_outflow"\n') - if(self.caseWindspeedY>=0): - target.write('ylo.type \t\t\t = "mass_inflow"\n') - target.write("ylo.density \t\t\t = 1.225\n") - target.write("ylo.temperature \t\t\t = 300\n") - target.write('yhi.type \t\t\t = "pressure_outflow"\n') - else: - target.write('yhi.type \t\t\t = "mass_inflow"\n') - target.write("yhi.density \t\t\t = 1.225\n") - target.write("yhi.temperature \t\t\t = 300\n") - target.write('ylo.type \t\t\t = "pressure_outflow"\n') - target.write('zhi.type \t\t\t = "slip_wall"\n') - target.write('zhi.temperature_type \t\t\t = "fixed_gradient"\n') - target.write("zhi.temperature \t\t\t = 0.003\n") - target.write('zlo.type \t\t\t = "wall_model"\n') - - def createAMRTolerance(self,target,modify=-1): - #if(modify==1): - if(self.caseverticalAR==3 or self.caseverticalAR==4): - self.smoothing=8 - elif(self.caseverticalAR>4 and self.caseverticalAR<=8): - self.smoothing=16 - elif(self.caseverticalAR>8 and self.caseverticalAR<=16): - self.smoothing=64 - if(self.caseverticalAR>=3): - target.write("mac_proj.num_pre_smooth \t\t\t = %g \n"%(self.smoothing)) - target.write("mac_proj.num_post_smooth \t\t\t = %g \n"%(self.smoothing)) - target.write("mac_proj.mg_rtol \t\t\t = 1.0e-4 \n") - target.write("mac_proj.mg_atol \t\t\t = 1.0e-8 \n") - target.write("mac_proj.maxiter \t\t\t = 360 \n") - if(self.caseverticalAR>=3): - target.write("nodal_proj.num_pre_smooth \t\t\t = %g \n"%(self.smoothing)) - target.write("nodal_proj.num_post_smooth \t\t\t = %g \n"%(self.smoothing)) - target.write("nodal_proj.mg_rtol \t\t\t = 1.0e-4 \n") - target.write("nodal_proj.mg_atol \t\t\t = 1.0e-8 \n") - target.write("diffusion.mg_rtol \t\t\t = 1.0e-6 \n") - target.write("diffusion.mg_atol \t\t\t = 1.0e-8 \n") - target.write("temperature_diffusion.mg_rtol \t\t\t = 1.0e-6 \n") - target.write("temperature_diffusion.mg_atol \t\t\t = 1.0e-8 \n") - target.write("nodal_proj.maxiter \t\t\t = 360 \n") - - def createAMRPrecursorSampling(self,target): - pass - # x1=self.terrainX1.flatten(order='F') - # x2=self.terrainX2.flatten(order='F') - # x3=self.terrainX3.flatten(order='F') - # target.write("# Cloud \n") - # target.write("sampling.labels \t\t\t = height80m \n") - # target.write("sampling.height80m.type \t\t\t = ProbeSampler \n") - # target.write('sampling.height80m.probe_location_file \t\t\t = "height80m.txt" \n') - # height80File=Path(self.caseParent,self.caseName,"precursor","height80m.txt").open("w") - # height80File.write("%g\n"%(len(self.smoothTerrainX1))) - # for i in range(0,len(self.terrainX1)): - # height80File.write("%g %g %g \n"%(self.smoothTerrainX1[i],self.smoothTerrainX2[i],self.smoothTerrainX3[i]+80)) - # height80File.close() - - def metMastRefinement(self,target): - # Read Met Mast - try: - latList=self.yamlFile['metMastLat'] - except: - return - lonList=self.yamlFile['metMastLon'] - metMastHeight=self.yamlFile['metMastHeight'] - print(latList,len(latList)) - xref=[] - yref=[] - zlower=[] - zmast=[] - for i in range(0,len(latList)): - if(i==0): - target.write("tagging.labels = metMastGrid1%g metMastGrid2%g metMastGrid3%g "%(i+1,i+1,i+1)) - else: - target.write(" metMastGrid1%g metMastGrid2%g metMastGrid3%g "%(i+1,i+1,i+1)) - xtemp,ytemp=self.srtm.to_xy(latList[i],lonList[i]) - print(xtemp,ytemp) - xref.append(xtemp-self.xref) - yref.append(ytemp-self.yref) - zmast.append(metMastHeight[i]-self.zRef) - target.write("\n") - print(xref,self.xref) - print(yref,self.yref) - # Now Write Refinemements - import pyvista as pv - for i in range(0,len(latList)): - xstart=xref[i]-4000 - ystart=yref[i]-4000 - zstart=self.interp(xref[i],yref[i]) - zdist=zmast[i]-zstart - print(zmast[i],zstart,zdist,self.zRef) - target.write("tagging.metMastGrid1%g.type \t\t\t = GeometryRefinement\n"%(i+1)) - target.write("tagging.metMastGrid1%g.shapes \t\t\t = metMast%g\n"%(i+1,i+1)) - target.write("tagging.metMastGrid1%g.level \t\t\t = 0\n"%(i+1)) - target.write("tagging.metMastGrid1%g.metMastGrid1%g.type \t\t\t = box\n"%(i+1,i+1)) - target.write("tagging.metMastGrid1%g.metMastGrid1%g.origin = %g %g %g \n"%(i+1,i+1,xstart,ystart,zstart-64)) - target.write("tagging.metMastGrid1%g.metMastGrid1%g.xaxis = %g %g %g\n"%(i+1,i+1,8000,0,0)) - target.write("tagging.metMastGrid1%g.metMastGrid1%g.yaxis = %g %g %g\n"%(i+1,i+1,0,8000,0)) - target.write("tagging.metMastGrid1%g.metMastGrid1%g.zaxis = %g %g %g\n"%(i+1,i+1,0,0,zdist+400)) - xstart=xref[i]-2000 - ystart=yref[i]-2000 - target.write("tagging.metMastGrid2%g.type \t\t\t = GeometryRefinement\n"%(i+1)) - target.write("tagging.metMastGrid2%g.shapes \t\t\t = metMastGrid2%g\n"%(i+1,i+1)) - target.write("tagging.metMastGrid2%g.min_level \t\t\t = 0\n"%(i+1)) - target.write("tagging.metMastGrid2%g.max_level \t\t\t = 1\n"%(i+1)) - target.write("tagging.metMastGrid2%g.metMastGrid2%g.type \t\t\t = box\n"%(i+1,i+1)) - target.write("tagging.metMastGrid2%g.metMastGrid2%g.origin = %g %g %g \n"%(i+1,i+1,xstart,ystart,zstart-32)) - target.write("tagging.metMastGrid2%g.metMastGrid2%g.xaxis = %g %g %g\n"%(i+1,i+1,4000,0,0)) - target.write("tagging.metMastGrid2%g.metMastGrid2%g.yaxis = %g %g %g\n"%(i+1,i+1,0,4000,0)) - target.write("tagging.metMastGrid2%g.metMastGrid2%g.zaxis = %g %g %g\n"%(i+1,i+1,0,0,zdist+200)) - xstart=xref[i]-1000 - ystart=yref[i]-1000 - target.write("tagging.metMastGrid3%g.type \t\t\t = GeometryRefinement\n"%(i+1)) - target.write("tagging.metMastGrid3%g.shapes \t\t\t = metMastGrid3%g\n"%(i+1,i+1)) - target.write("tagging.metMastGrid3%g.min_level \t\t\t = 0\n"%(i+1)) - target.write("tagging.metMastGrid3%g.max_level \t\t\t = 2\n"%(i+1)) - target.write("tagging.metMastGrid3%g.metMastGrid3%g.type \t\t\t = box\n"%(i+1,i+1)) - target.write("tagging.metMastGrid3%g.metMastGrid3%g.origin = %g %g %g \n"%(i+1,i+1,xstart,ystart,zstart-16)) - target.write("tagging.metMastGrid3%g.metMastGrid3%g.xaxis = %g %g %g\n"%(i+1,i+1,2000,0,0)) - target.write("tagging.metMastGrid3%g.metMastGrid3%g.yaxis = %g %g %g\n"%(i+1,i+1,0,2000,0)) - target.write("tagging.metMastGrid3%g.metMastGrid3%g.zaxis = %g %g %g\n"%(i+1,i+1,0,0,zdist+100)) - # Write Boxes - mesh1=pv.Box(bounds=(xref[i]-4000,xref[i]+4000,yref[i]-4000,yref[i]+4000,zstart-64,zstart+zdist+400)) - fileName=Path(self.caseParent,self.caseName,"metMastGrid1"+str(i+1)+".vtk").as_posix() - mesh1.save(fileName) - mesh1=pv.Box(bounds=(xref[i]-2000,xref[i]+2000,yref[i]-2000,yref[i]+2000,zstart-32,zstart+zdist+200)) - fileName=Path(self.caseParent,self.caseName,"metMastGrid2"+str(i+1)+".vtk").as_posix() - mesh1.save(fileName) - mesh1=pv.Box(bounds=(xref[i]-1000,xref[i]+1000,yref[i]-1000,yref[i]+1000,zstart-16,zstart+zdist+100)) - fileName=Path(self.caseParent,self.caseName,"metMastGrid2"+str(i+1)+".vtk").as_posix() - mesh1.save(fileName) - - def closeAMRFiles(self): - self.amrPrecursorFile.close() - try: - self.amrTerrainFile.close() - except: - pass - - def writeTerrainData(self,folder): - print("Writing Terrain Data") - x1=self.terrainX1.flatten(order='F') - x2=self.terrainX2.flatten(order='F') - x3=self.terrainX3.flatten(order='F') - x=np.arange(np.amin(x1),np.amax(x1),self.caseCellSize) - y=np.arange(np.amin(x2),np.amax(x2),self.caseCellSize) - from scipy.interpolate import NearestNDInterpolator - self.interp = NearestNDInterpolator(list(zip(x1,x2)),x3) - xterrain,yterrain=np.meshgrid(x,y) - zterrain = self.interp(xterrain,yterrain) - import matplotlib.pylab as plt - plt.contourf(xterrain,yterrain,zterrain) - x1=xterrain.flatten(order='F') - x2=yterrain.flatten(order='F') - x3=zterrain.flatten(order='F') - target=Path(self.caseParent,self.caseName,folder,"terrain.amrwind").open("w") - for i in range(0,len(x1)): - target.write("%g %g %g\n"%(x1[i],x2[i],x3[i])) - target.close() - data=np.column_stack([x1,x2,x3]) - import pyvista as pv - mesh=pv.PolyData(data) - mesh['elevation']=data[:,2] - mesh.save(Path(self.caseParent,self.caseName,folder,"terrainPoints.vtk").as_posix()) - #xterrain,yterrain=np.meshgrid(x,y) - # for i in range(0,xterrain.shape[0]): - # for j in range(0,xterrain.shape[1]): - # error=100000000 - # for k in range(0,len(x1)): - # error=np.sqrt((xterrain[i,j]-x1[k])**2+(yterrain[i,j]-x2[k])**2) - # if(errorxmin and lat[i]ymin and lon[i]0): - distance=tempDistance - if(distance=400 and x[i]<=600 and y[j]>=400 and y[j]<=600): - z=200 - else: - z=0 - target.write("%g %g %g\n"%(x[i],y[j],z)) -target.close() - diff --git a/tools/terrain/stl2XYZ.py b/tools/terrain/stl2XYZ.py deleted file mode 100644 index ac0bdcc232..0000000000 --- a/tools/terrain/stl2XYZ.py +++ /dev/null @@ -1,62 +0,0 @@ -''' -This utility converts a STL file of the terrain into terrain.amrwind format. -Currently it uses the STL triangulation to generate the points. -In the future, the code can be modified to use python interpolaton tools. -''' - -import sys -import pyvista as pv -import numpy as np - -fileName=sys.argv[1] -mesh=pv.read(fileName) -print(mesh.bounds) -xmin=0 -xmax=0 -ymin=0 -ymax=0 -zmin=0 -zmax=0 -meshSize=16 -dx=(xmax-xmin) -dy=(ymax-ymin) -dz=(zmax-zmin) -print(dx,dy,dz) -print(dx/meshSize,dy/meshSize,dz/meshSize) -target=open("terrain.amrwind",'w') -print(np.shape(mesh.points)) -for i in range(0,(np.shape(mesh.points))[0]): - if((mesh.points[i][2]-zmin)<20): - print(mesh.points[i][2]-zmin) - target.write("%g %g %g\n"%(mesh.points[i][0]-xmin,mesh.points[i][1]-ymin,mesh.points[i][2]-zmin)) -target.close() -data=np.genfromtxt("terrain.amrwind") -mesh=pv.PolyData(data) -mesh['elevation']=data[:,2] -surf = mesh.delaunay_2d() -surf.save("terrain.vtk") -# mesh=pv.PolyData("terrain.vtk") -# tempmesh=mesh -# bounds=tempmesh.bounds -# for i in range(0,1): -# print("Run ",i) -# bounds=tempmesh.bounds -# xmin=bounds[0] -# xmax=bounds[1] -# ymin=bounds[2] -# ymax=bounds[2] -# smoothData=tempmesh.smooth(108) -# for k in range(0,len(mesh.points)): -# xc=smoothData.points[i][0] -# yc=smoothData.points[i][1] -# zc=smoothData.points[i][2] -# if(xc>0.25*xmin and xc<0.75*xmax and yc>0.25*ymin and yc<0.75*ymax): -# smoothData.points[i]=mesh.points[i] -# tempmesh=smoothData -# print("Bounds:",bounds) -# smoothData.save("smoothTerrain.vtk") -# #smoothData=mesh -# target=open("terrain.amrwind","w") -# for i in range(0,data.shape[0]): -# target.write("%g %g %g\n"%(smoothData.points[i,0],smoothData.points[i,1],smoothData.points[i,2]-np.amin(smoothData.points[i,2]))) -# target.close() diff --git a/tools/terrain/terrain.py b/tools/terrain/terrain.py deleted file mode 100644 index d5dc2c090b..0000000000 --- a/tools/terrain/terrain.py +++ /dev/null @@ -1,884 +0,0 @@ -""" -Tools for working with terrain - -Notes ------ -For SRTM data download (in GeoTIFF (.tif) format: -- install with `conda install -c conda-forge gdal` or `pip install gdal` -- install with `conda install -c conda-forge elevation` or `pip install elevation` -- check with `eio selfcheck` - -For processing downloaded GeoTIFF data: -- install with `conda install -c conda-forge rasterio` or `pip install rasterio` -- note: like the elevation package, this also depends on gdal -""" -import sys,os,glob -import numpy as np -import xarray as xr -from scipy.interpolate import RectBivariateSpline, griddata - -import elevation -import rasterio -from rasterio import transform, warp -from rasterio.crs import CRS - -# hard-coded here because ElementTree doesn't appear to have any -# straightforward way to access the xmlns root attributes -ISO_namespace = { - 'gmd': 'http://www.isotc211.org/2005/gmd', - 'gco': 'http://www.isotc211.org/2005/gco', -} - - -class Terrain(object): - - latlon_crs = CRS.from_dict(init='epsg:4326') - - def __init__(self,latlon_bounds,fpath='terrain.tif'): - """Create container for manipulating GeoTIFF data in the - specified region - - Usage - ===== - latlon_bounds : list or tuple - Latitude/longitude corresponding to west, south, east, and - north bounds, used to define the source transformation. - fpath : str, optional - Where to save downloaded GeoTIFF (*.tif) data. - """ - self.bounds = list(latlon_bounds) - self._get_utm_crs() # from bounds - self.tiffdata = fpath - self.have_terrain = False - if not hasattr(self,'have_metadata'): - # set attribute if it hasn't been set already - self.have_metadata = False - - def _get_utm_crs(self,datum='WGS84',ellps='WGS84'): - """Get coordinate system from zone number associated with the - longitude of the northwest corner - - Parameters - ========== - datum : str, optional - Origin of destination coordinate system, used to describe - PROJ.4 string; default is WGS84. - ellps : str, optional - Ellipsoid defining the shape of the earth in the destination - coordinate system, used to describe PROJ.4 string; default - is WGS84. - """ - #west, south, east, north = self.bounds - self.zone_number = int((self.bounds[0] + 180) / 6) + 1 - proj = '+proj=utm +zone={:d} '.format(self.zone_number) \ - + '+datum={:s} +units=m +no_defs '.format(datum) \ - + '+ellps={:s} +towgs84=0,0,0'.format(ellps) - self.utm_crs = CRS.from_proj4(proj) - - def _get_bounds_from_metadata(self): - """This is a stub""" - assert self.have_metadata - raise NotImplementedError() - - def to_terrain(self,dx,dy=None,resampling=warp.Resampling.bilinear): - """Load geospatial raster data and reproject onto specified grid - - Usage - ===== - dx,dy : float - Grid spacings [m]. If dy is not specified, then uniform - spacing is assumed. - resampling : warp.Resampling value, optional - See `list(warp.Resampling)`. - """ - if dy is None: - dy = dx - - # load raster - if not os.path.isfile(self.tiffdata): - raise FileNotFoundError('Need to download()') - dem_raster = rasterio.open(self.tiffdata) - - # get source coordinate reference system, transform - west, south, east, north = self.bounds - src_height, src_width = dem_raster.shape - src_crs = dem_raster.crs - src_transform = transform.from_bounds(*self.bounds, src_width, src_height) - src = dem_raster.read(1) - - # calculate destination coordinate reference system, transform - dst_crs = self.utm_crs - print('Projecting from',src_crs,'to',dst_crs) - # - get origin (the _upper_ left corner) from bounds - orix,oriy = self.to_xy(north,west) - origin = (orix, oriy) - self.origin = origin - dst_transform = transform.from_origin(*origin, dx, dy) - # - get extents from lower right corner - SE_x,SE_y = self.to_xy(south,east) - Lx = SE_x - orix - Ly = oriy - SE_y - Nx = int(Lx / dx) - Ny = int(Ly / dy) - - # reproject to uniform grid in the UTM CRS - dem_array = np.empty((Ny, Nx)) - warp.reproject(src, dem_array, - src_transform=src_transform, src_crs=src_crs, - dst_transform=dst_transform, dst_crs=dst_crs, - resampling=resampling) - utmx = orix + np.arange(0, Nx*dx, dx) - utmy = oriy + np.arange((-Ny+1)*dy, dy, dy) - self.x,self.y = np.meshgrid(utmx,utmy,indexing='ij') - self.z = np.flipud(dem_array).T - - self.zfun = RectBivariateSpline(utmx,utmy,self.z) - self.have_terrain = True - - return self.x, self.y, self.z - - def to_latlon(self,x,y): - """Transform uniform grid to lat/lon space""" - if not hasattr(x, '__iter__'): - assert ~hasattr(x, '__iter__') - x = [x] - y = [y] - xlon, xlat = warp.transform(self.utm_crs, - self.latlon_crs, - x, y) - try: - shape = x.shape - except AttributeError: - xlat = xlat[0] - xlon = xlon[0] - else: - xlat = np.reshape(xlat, shape) - xlon = np.reshape(xlon, shape) - return xlat,xlon - - def to_xy(self,lat,lon,xref=None,yref=None): - """Transform lat/lon to UTM space""" - if not hasattr(lat, '__iter__'): - assert ~hasattr(lat, '__iter__') - lat = [lat] - lon = [lon] - x,y = warp.transform(self.latlon_crs, - self.utm_crs, - lon, lat) - try: - shape = lon.shape - except AttributeError: - x = x[0] - y = y[0] - else: - x = np.reshape(x, shape) - y = np.reshape(y, shape) - if xref is not None: - x -= xref - if yref is not None: - y -= yref - return x,y - - def xtransect(self,xy=None,latlon=None,wdir=270.0,xrange=(None,None)): - """Get terrain transect along x for a slice aligned with the - specified wind direction and going through a specified reference - point (defined by xy or latlon) - - Usage - ===== - xy : list or tuple - Reference location in the UTM coordinate reference system [m] - latlon : list-like - Reference location in latitude and longitude [deg] - wdir : float - Wind direction with which the slice is aligned [deg] - xrange : list or tuple, optional - Range of x values over which slice (or None to use min/max) - """ - assert self.have_terrain, 'Need to call to_terrain()' - assert ((xy is not None) ^ (latlon is not None)), 'Specify xy or latlon' - if xy: - refloc = xy - elif latlon: - x,y = self.to_xy(*latlon) - refloc = (x,y) - ang = 270 - wdir - print('Slice through',refloc,'at',ang,'deg') - ang *= np.pi/180. - - # direction specific code - imin = 0 if (xrange[0] is None) else np.where(self.x <= xrange[0])[0][-1] - imax = None if (xrange[1] is None) else np.where(self.x > xrange[1])[0][0] - x = self.x[imin:imax,0] - y = np.tan(ang) * (x-refloc[0]) + refloc[1] - z = self.zfun(x,y,grid=False) - - return x-refloc[0], z - - def ytransect(self,xy=None,latlon=None,wdir=180.0,yrange=(None,None)): - """Get terrain transect along x for a slice aligned with the - specified wind direction and going through a specified reference - point (defined by xy or latlon) - - Usage - ===== - xy : list or tuple - Reference location in the UTM coordinate reference system [m] - latlon : list-like - Reference location in latitude and longitude [deg] - wdir : float - Wind direction with which the slice is aligned [deg] - xrange : list or tuple, optional - Range of x values over which slice (or None to use min/max) - """ - assert self.have_terrain, 'Need to call to_terrain()' - assert ((xy is not None) ^ (latlon is not None)), 'Specify xy or latlon' - if xy: - refloc = xy - elif latlon: - x,y = self.to_xy(*latlon) - refloc = (x,y) - ang = 180 - wdir - print('Slice through',refloc,'at',ang,'deg') - ang *= np.pi/180. - - # direction specific code - jmin = 0 if (yrange[0] is None) else np.where(self.y <= yrange[0])[1][-1] - jmax = None if (yrange[1] is None) else np.where(self.y > yrange[1])[1][0] - y = self.y[0,jmin:jmax] - x = refloc[0] - np.tan(ang) * (y-refloc[1]) - z = self.zfun(x,y,grid=False) - - return y-refloc[1], z - - -class SRTM(Terrain): - """Class for working with Shuttle Radar Topography Mission (SRTM) data""" - data_products = { - 'SRTM1': 30.0, - 'SRTM3': 90.0, - } - - def __init__(self,latlon_bounds,fpath='terrain.tif',product='SRTM3', - margin=0.05): - """Create container for SRTM data in the specified region - - Usage - ===== - latlon_bounds : list or tuple - Latitude/longitude corresponding to west, south, east, and - north bounds, used to define the source transformation. - fpath : str, optional - Where to save downloaded GeoTIFF (*.tif) data. - product : str, optional - Data product name, SRTM1 or SRTM3 (corresponding to 30- and - 90-m DEM). - margin : float, optional - Decimal degree margin added to the bounds (default is 3") - when clipping the downloaded elevation data. - """ - latlon_bounds = list(latlon_bounds) - if margin is not None: - latlon_bounds[0] -= margin - latlon_bounds[1] -= margin - latlon_bounds[2] += margin - latlon_bounds[3] += margin - super().__init__(latlon_bounds,fpath=fpath) - assert (product in self.data_products.keys()), \ - 'product should be one of '+str(list(self.data_products.keys())) - self.product = product - self.margin = margin - - def download(self,cleanup=True): - """Download the SRTM data in GeoTIFF format""" - dpath = os.path.dirname(self.tiffdata) - if not os.path.isdir(dpath): - print('Creating path',dpath) - os.makedirs(dpath) - escapedpath = self.tiffdata.replace('\ ',' ').replace(' ','\ ') - try: - elevation.clip(self.bounds, product=self.product, output=escapedpath) - except: - info = sys.exc_info() - print(info[0]) - print(info[1]) - print('') - print('Note: Have elevation and gdal been installed properly?') - if cleanup: - elevation.clean() - - def to_terrain(self,dx=None,dy=None,resampling=warp.Resampling.bilinear): - """Load geospatial raster data and reproject onto specified grid - - Usage - ===== - dx,dy : float - Grid spacings [m]. If dy is not specified, then uniform - spacing is assumed. - resampling : warp.Resampling value, optional - See `list(warp.Resampling)`. - """ - if dx is None: - dx = self.data_products[self.product] - print('Output grid at ds=',dx) - if dy is None: - dy = dx - return super().to_terrain(dx, dy=dy, resampling=resampling) - - -class USGS(Terrain): - """Class for working with the US Geological Survey's 3D Elevation - Program (3DEP). Note that there is no API so the tif data must be - manually downloaded from the USGS. - """ - - def __init__(self,latlon_bounds=None,fpath='terrain.tif'): - """Create container for 3DEP data in the specified region - - Usage - ===== - latlon_bounds : list or tuple, optional - Latitude/longitude corresponding to west, south, east, and - north bounds, used to define the source transformation. If - not specified, then it will be read from a metadata file - with the same name. - fpath : str - Location of downloaded GeoTIFF (*.tif) data. - """ - self._read_metadata(fpath) - if latlon_bounds is None: - latlon_bounds = self._get_bounds_from_metadata() - print('Bounds:',latlon_bounds) - super().__init__(latlon_bounds,fpath=fpath) - - def _read_metadata(self,fpath): - from xml.etree import ElementTree - xmlfile = os.path.splitext(fpath)[0] + '.xml' - try: - metadata = ElementTree.parse(xmlfile).getroot() - except IOError: - self.have_metadata = False - else: - if not metadata.tag.endswith('MD_Metadata'): - assert metadata.tag in ['metadata','gmd:MD_Metadata','modsCollection'] - if metadata.tag == 'metadata': - # legacy metadata - print('Source CRS datum:',metadata.find('./spref/horizsys/geodetic/horizdn').text) - elif metadata.tag == 'modsCollection': - # MODS XML - print(metadata.find('./mods/titleInfo/title').text) - raise NotImplementedError('MODS XML detected -- use ISO XML instead') - else: - # ISO XML - title = metadata.find( - '/'.join([ - 'gmd:identificationInfo', - 'gmd:MD_DataIdentification', - 'gmd:citation', - 'gmd:CI_Citation', - 'gmd:title', - 'gco:CharacterString', - ]), - ISO_namespace - ).text - print(title) - self.have_metadata = True - self.metadata = metadata - - def _get_bounds_from_metadata(self): - assert self.have_metadata - if self.metadata.tag == 'metadata': - # legacy metadata - bounding = self.metadata.find('./idinfo/spdom/bounding') - bounds = [ - float(bounding.find(bcdir+'bc').text) - for bcdir in ['west','south','east','north'] - ] - else: - # ISO XML - extent = self.metadata.find( - 'gmd:identificationInfo/gmd:MD_DataIdentification/gmd:extent', - ISO_namespace - ) - bbox = extent.find( - 'gmd:EX_Extent/gmd:geographicElement/gmd:EX_GeographicBoundingBox', - ISO_namespace - ) - bounds = [ - float(bbox.find(f'gmd:{bound}/gco:Decimal',ISO_namespace).text) - for bound in [ - 'westBoundLongitude', - 'southBoundLatitude', - 'eastBoundLongitude', - 'northBoundLatitude', - ] - ] - return bounds - - def download(self): - """This is just a stub""" - print('Data must be manually downloaded!') - print('Go to https://apps.nationalmap.gov/downloader/#/,') - print('select "Data > Elevation Products (3DEP)"') - print('and then click "Find Products"') - - -def combine_raster_data(filelist,dtype=Terrain,latlon_bounds=None, - output='output.tif'): - """Combine multiple raster datasets into a single GeoTIFF file - - Usage - ===== - filelist : list or glob str - List of downloaded GeoTIFF (*.tif) data. - dtype : Terrain or derived class, optional - Used to provide helper functions if needed. - latlon_bounds : list of (list or tuple), optional - Each list or tuple of latitude/longitude corresponds to west, - south, east, and north bounds, and are used to define the bounds - of the combined raster. If not specified, then try to read these - bounds from metadata. - output : str - Location of combined GeoTIFF (*.tif) data. - """ - if not isinstance(filelist, list): - filelist = glob.glob(filelist) - print('Files:',filelist) - assert len(filelist) > 1, 'Did not find enough files to combine' - if latlon_bounds is None: - latlon_bounds = len(filelist) * [None] - else: - assert len(latlon_bounds)==len(filelist), 'Not enough specified bounds' - - terraindata = [ - dtype(bounds,fpath) for bounds,fpath in zip(latlon_bounds,filelist) - ] - - # merge rasters - from rasterio.merge import merge - merged, out_transform = merge([ - rasterio.open(data.tiffdata) for data in terraindata - ]) - - # write out merged dataset - profile = rasterio.open(filelist[0]).profile - print('Raster profile:',profile) - with rasterio.open(output,'w',**profile) as dst: - dst.write(merged) - - # get global bounds - bounds = np.empty((len(filelist),4)) - for i,data in enumerate(terraindata): - bounds[i,:] = data.bounds - bounds_min = bounds.min(axis=0) - bounds_max = bounds.max(axis=0) - return [bounds_min[0],bounds_min[1],bounds_max[2],bounds_max[3]] - -def calc_slope(x,y,z): - """Calculate local terrain slope based on project grid - - Notes: - - Uses neighborhood method (weighted second-order difference, based on - 3x3 stencil) - - Slopes are not calculated at edge points (i.e., locations where a 3x3 - stencil cannot be formed) - - Usage - ===== - x,y,z : numpy array - Equally sized 2-D arrays; if not specified, then the full terrain - will be used - """ - dx = x[1,0] - x[0,0] - dy = y[0,1] - y[0,0] - slope = np.empty_like(z) - slope[:,:] = np.nan - z1 = z[ :-2, 2: ] # upper left - z2 = z[ 1:-1, 2: ] # upper middle - z3 = z[ 2: , 2: ] # upper right - z4 = z[ :-2, 1:-1] # center left - #z5 = z[ 1:-1, 1:-1] # center - z6 = z[ 2: , 1:-1] # center right - z7 = z[ :-2, :-2] # lower left - z8 = z[ 1:-1, :-2] # lower middle - z9 = z[ 2: , :-2] # lower right - dz_dx = ((z3 + 2*z6 + z9) - (z1 + 2*z4 + z7)) / (8*dx) - dz_dy = ((z1 + 2*z2 + z3) - (z7 + 2*z8 + z9)) / (8*dy) - rise_run = np.sqrt(dz_dx**2 + dz_dy**2) - slope[1:-1,1:-1] = np.degrees(np.arctan(rise_run)) - return slope - - -def calcTRI(hgt,window=None,footprint=None): - ''' - Terrain Ruggedness Index - Riley, S. J., DeGloria, S. D., & Elliot, R. (1999). Index that - quantifies topographic heterogeneity. intermountain Journal - of sciences, 5(1-4), 23-27. - - hgt : array - Array of heights over which TRI will be calculated - window : int - Length of window in x and y direction. Must be odd. - ''' - import xarray as xr - from scipy.ndimage.filters import generic_filter - - # Window setup: - if footprint is not None: - assert window is None, 'Must specify either window or footprint' - window = np.shape(footprint)[0] - - assert (window/2.0) - np.floor(window/2.0) != 0.0, 'window must be odd...' - Hwindow = int(np.floor(window/2)) - - # Type and dimension check: - if isinstance(hgt,(xr.Dataset,xr.DataArray,xr.Variable)): - hgt = hgt.data - assert len(np.shape(hgt)) == 2, 'hgt must be 2-dimensional. Currently has {} dimensions'.format(len(np.shape(hgt))) - - ny,nx = np.shape(hgt) - - def tri_filt(x): - middle_ind = int(len(x)/2) - return((sum((x - x[middle_ind])**2.0))**0.5) - - if footprint is None: - tri = generic_filter(hgt,tri_filt, size = (window,window)) - else: - tri = generic_filter(hgt,tri_filt, footprint=footprint) - - return tri - - -def calcVRM(hgt,res,window=None,footprint=None,fill_depressions=True,return_slope_aspect=False): - ''' - Vector Ruggedness Measure - Sappington, J. M., Longshore, K. M., & Thompson, D. B. (2007). - Quantifying landscape ruggedness for animal habitat analysis: - a case study using bighorn sheep in the Mojave Desert. The - Journal of wildlife management, 71(5), 1419-1426. - - hgt : array - Array of heights over which TRI will be calculated - res : int or float - Resolution of the underlying hgt array. Should be constant in x and y - Needed for proper slope calculation - window : int - Length of window in x and y direction. Must be odd. - ''' - import richdem as rd - import xarray as xr - from scipy.ndimage.filters import generic_filter - - # Window setup: - if footprint is not None: - assert window is None, 'Must specify either window or footprint' - window = np.shape(footprint)[0] - - assert (window/2.0) - np.floor(window/2.0) != 0.0, 'window must be odd...' - Hwndw = int(np.floor(window/2)) - - # Type and dimension check: - if isinstance(hgt,(xr.Dataset,xr.DataArray,xr.Variable)): - hgt = hgt.data - assert len(np.shape(hgt)) == 2, 'hgt must be 2-dimensional. Currently has {} dimensions'.format(len(np.shape(hgt))) - ny,nx = np.shape(hgt) - - # Determine scale based on resolution of hgt array - zscale = 1/res - - # Get slope and aspect: - hgt_rd = rd.rdarray(hgt, no_data=-9999) - if fill_depressions: - rd.FillDepressions(hgt_rd, in_place=True) - slope = rd.TerrainAttribute(hgt_rd, attrib='slope_degrees',zscale=zscale) - aspect = rd.TerrainAttribute(hgt_rd, attrib='aspect') - - # Calculate vectors: - vrm = np.zeros((ny,nx)) - rugz = np.cos(np.deg2rad(slope)) - rugdxy = np.sin(np.deg2rad(slope)) - rugx = rugdxy*np.cos(np.deg2rad(aspect)) - rugy = rugdxy*np.sin(np.deg2rad(aspect)) - - def vrm_filt(x): - return(sum(x)**2) - - if footprint is None: - vrmX = generic_filter(rugx,vrm_filt, size = (window,window)) - vrmY = generic_filter(rugy,vrm_filt, size = (window,window)) - vrmZ = generic_filter(rugz,vrm_filt, size = (window,window)) - else: - vrmX = generic_filter(rugx,vrm_filt, footprint=footprint) - vrmY = generic_filter(rugy,vrm_filt, footprint=footprint) - vrmZ = generic_filter(rugz,vrm_filt, footprint=footprint) - - - if footprint is not None: - num_points = len(footprint[footprint != 0.0]) - else: - num_points = float(window**2) - vrm = 1.0 - np.sqrt(vrmX + vrmY + vrmZ)/num_points - if return_slope_aspect: - return vrm,slope,aspect - else: - return vrm - - -def calcSx(xx, yy, zagl, A, dmax, method='linear', verbose=False): - ''' - Sx is a measure of topographic shelter or exposure relative to a particular - wind direction. Calculates a whole map for all points (xi, yi) in the domain. - For each (xi, yi) pair, it uses all v points (xv, yv) upwind of (xi, yi) in - the A wind direction, up to dmax. - - Winstral, A., Marks D. "Simulating wind fields and snow redistribution using - terrain-based parameters to model snow accumulation and melt over a semi- - arid mountain catchment" Hydrol. Process. 16, 3585–3603 (2002) - - Usage - ===== - xx, yy : array - meshgrid arrays of the region extent coordinates. - zagl: arrayi, xr.DataArray - Elevation map of the region - A: float - Wind direction (deg, wind direction convention) - dmax: float - Upwind extent of the search - method: string - griddata interpolation method. Options are 'nearest', 'linear', 'cubic'. - Recommended linear or cubic. - ''' - - # get resolution (assumes uniform resolution) - res = xx[1,0] - xx[0,0] - npoints = 1+int(dmax/res) - if dmax < res: - raise ValueError('dmax needs to be larger or equal to the resolution of the grid') - - # Get upstream direction - A = A%360 - if A==0: upstreamDirX=0; upstreamDirY=-1 - elif A==90: upstreamDirX=-1; upstreamDirY=0 - elif A==180: upstreamDirX=0; upstreamDirY=1 - elif A==270: upstreamDirX=1; upstreamDirY=0 - elif A>0 and A<90: upstreamDirX=-1; upstreamDirY=-1 - elif A>90 and A<180: upstreamDirX=-1; upstreamDirY=1 - elif A>180 and A<270: upstreamDirX=1; upstreamDirY=1 - elif A>270 and A<360: upstreamDirX=1; upstreamDirY=-1 - - # change angle notation - ang = np.deg2rad(270-A) - - # array for interpolation using griddata - points = np.array( (xx.flatten(), yy.flatten()) ).T - if isinstance(zagl, xr.DataArray): - zagl = zagl.values - values = zagl.flatten() - - # create rotated grid. This way we sample into a interpolated grid that has the exact points we need - xmin = min(xx[:,0]); xmax = max(xx[:,0]) - ymin = min(yy[0,:]); ymax = max(yy[0,:]) - if A%90 == 0: - # if flow is aligned, we don't need a new grid - xrot = xx[:,0] - yrot = yy[0,:] - xxrot = xx - yyrot = yy - elevrot = zagl - else: - xrot = np.arange(xmin, xmax+0.1, abs(res*np.cos(ang))) - yrot = np.arange(ymin, ymax+0.1, abs(res*np.sin(ang))) - xxrot, yyrot = np.meshgrid(xrot, yrot, indexing='ij') - elevrot = griddata( points, values, (xxrot, yyrot), method=method ) - - # create empty rotated Sx array - Sxrot = np.empty(np.shape(elevrot)); Sxrot[:,:] = np.nan - - for i, xi in enumerate(xrot): - if verbose: print(f'Computing Sx... {100*(i+1)/len(xrot):.1f}% ', end='\r') - for j, yi in enumerate(yrot): - - # Get elevation profile along the direction asked - isel = np.linspace(i-upstreamDirX*npoints+upstreamDirX, i, npoints, dtype=int) - jsel = np.linspace(j-upstreamDirY*npoints+upstreamDirY, j, npoints, dtype=int) - try: - xsel = xrot[isel] - ysel = yrot[jsel] - elev = elevrot[isel,jsel] - except IndexError: - # At the borders, can't get a valid positions - xsel = np.zeros(np.size(isel)) - ysel = np.zeros(np.size(jsel)) - elev = np.zeros(np.size(isel)) - - # elevation of (xi, yi), for convenience - elevi = elev[-1] - - Sxrot[i,j] = np.nanmax(np.rad2deg( np.arctan( (elev[:-1] - elevi)/(((xsel[:-1]-xi)**2 + (ysel[:-1]-yi)**2)**0.5) ) )) - - # interpolate results back to original grid - pointsrot = np.array( (xxrot.flatten(), yyrot.flatten()) ).T - Sx = griddata( pointsrot, Sxrot.flatten(), (xx, yy), method=method ) - - return Sx - - -def calcSxmean(xx, yy, zagl, A, dmax, method='nearest', verbose=False): - - Asweep = np.linspace(A-15, A+15, 7)%360 - Sxmean = np.mean([calcSx(xx, yy, zagl, a, dmax, method, verbose=verbose) for a in Asweep ], axis=0) - - return Sxmean - - -def calcSb(xx, yy, zagl, A, sepdist=60): - ''' - Sb is a measure of upwind slope break and can be used to delineate zones of - possible flow separation. This function follows the definition of Sx0 from - the reference listed below and uses 1000m separation. - - Winstral, A., Marks D. "Simulating wind fields and snow redistribution using - terrain-based parameters to model snow accumulation and melt over a semi- - arid mountain catchment" Hydrol. Process. 16, 3585–3603 (2002) - - Usage - ===== - xx, yy : array - meshgrid arrays of the region extent coordinates. - zagl: array - Elevation map of the region - A: float - Wind direction (deg, wind direction convention) - sepdist : float, default 60 - Separation between between two regional Sx calculations. - Suggested value: 60 m. - ''' - - # local Sx - Sx1 = calcSx(xx, yy, zagl, A, dmax=sepdist) - - # outlying Sx. Computing it at (xo, yo), and not at (xi, yi) - xxo = xx - sepdist*np.cos(np.deg2rad(270-A)) - yyo = yy - sepdist*np.sin(np.deg2rad(270-A)) - points = np.array( (xx.flatten(), yy.flatten()) ).T - values = zagl.flatten() - zaglo = griddata( points, values, (xxo,yyo), method='linear' ) - Sx0 = calcSx(xxo, yyo, zaglo, A, dmax=1000) - - Sb = Sx1 - Sx0 - - return Sb - -def calcSbmean(xx, yy, zagl, A, sepdist): - - Asweep = np.linspace(A-15, A+15, 7)%360 - Sbmean = np.mean([calcSb(xx, yy, zagl, a, sepdist) for a in Asweep ], axis=0) - - return Sbmean - - -def calcTPI(xx, yy, zagl, r): - ''' - Topographic Position Index - - Reu, J, et al. Application of the topographic position index to heterogeneous - landscapes. Geomorphology, 186, 39-49 (2013) - ''' - from scipy.signal import convolve2d - - # get resolution (assumes uniform resolution) - res = xx[1,0] - xx[0,0] - rpoints = int(r/res) - if r < res: - raise ValueError('Averaging radium needs to be larger the resolution of the grid') - - y,x = np.ogrid[-rpoints:rpoints+1, -rpoints:rpoints+1] - kernel = x**2+y**2 <= rpoints**2 - - zaglmean = convolve2d(zagl, kernel*1, mode='same', boundary='fill', fillvalue=0) - zaglmean = zaglmean/np.sum(kernel*1) - - return zagl - zaglmean - - -def extract_elevation_from_stl(stlpath, x, y, interp_method = 'cubic'): - from stl import mesh - - x = [x] if isinstance(x, (int,float)) else x - y = [y] if isinstance(y, (int,float)) else y - - assert len(x)==len(y), 'x and y need to have the same dimenension' - - try: - msh = mesh.Mesh.from_file(stlpath) - except FileNotFoundError: - print('File does not exist.') - - xstl = msh.vectors[:,:,0].ravel() - ystl = msh.vectors[:,:,1].ravel() - zstl = msh.vectors[:,:,2].ravel() - - points = np.stack((xstl,ystl), axis=-1) - xi = np.stack((x,y), axis=-1) - elev = griddata(points, zstl, xi, method=interp_method) - - if len(x)==1: - return np.array(list(zip(x,y,elev))[0]) - else: - return np.array(list(zip(x,y,elev))) - - -def readSTL(stlpath, stlres=None, method='cubic'): - ''' - Function to read in an STL and get result in an orthogonal grid. - The resolution is optional, but check the warnings if you don't - pass one. - If a down- or upsampling of a STL is needed, then pass the desired - resolution and ignore the warnings. - - Usage - ===== - stlpath: str - Path to STL file, including its extension - stlres: int, float - Resolution of the underlying grid that the data will be - interpolated to - method: str, optional - Interpolation method. Options: 'nearest', 'linear', 'cubic' - Default is cubic - ''' - - from stl import mesh - - try: - msh = mesh.Mesh.from_file(stlpath) - except FileNotFoundError: - print('File does not exist.') - - xstl = msh.vectors[:,:,0].ravel() - ystl = msh.vectors[:,:,1].ravel() - zstl = msh.vectors[:,:,2].ravel() - - # STLs are complex and the computation below may not always get the proper resolution - apparentres = xstl[1]-xstl[0] - if stlres==None: - print(f'Using {apparentres} m resolution obtained from the STL. This resolution may not be entirely ' - 'accurate. If not, please provide a proper value using the `stlres` parameter.') - elif stlres != apparentres: - print(f'The {stlres} m resolution provided does not match what the function thinks the resolution is, {apparentres} ' - 'm, based on the STL. This apparent resolution may not be entirely accurate. Trust yours, but verify.') - - xmin = min(xstl); xmax = max(xstl) - ymin = min(ystl); ymax = max(ystl) - - xx, yy = np.meshgrid(np.arange(xmin,xmax+0.1, stlres), np.arange(ymin, ymax+0.1, stlres), indexing='ij') - - points = np.array( (xstl, ystl) ).T - values = zstl.flatten() - z = griddata( points, values, (xx, yy), method=method ) - - return xx, yy, z - From d1a5381940282f6fb874fc773941129c9100646a Mon Sep 17 00:00:00 2001 From: hgopalan Date: Mon, 22 Jul 2024 15:18:54 -0600 Subject: [PATCH 52/77] Reformulated the boundary conditions to improve the surface layer prediction. Added a blanking sensitive wall boundary condition to set the lower wall boundary condition in terrain to zero gradient as it is not required. --- .../icns/source_terms/DragForcing.H | 3 +- .../icns/source_terms/DragForcing.cpp | 31 ++++++++++------- .../source_terms/DragTempForcing.H | 6 ++-- .../source_terms/DragTempForcing.cpp | 24 ++++++++++---- amr-wind/turbulence/LES/Kosovic.cpp | 23 ++++++------- amr-wind/wind_energy/ABLWallFunction.cpp | 33 +++++++++++++------ 6 files changed, 77 insertions(+), 43 deletions(-) diff --git a/amr-wind/equation_systems/icns/source_terms/DragForcing.H b/amr-wind/equation_systems/icns/source_terms/DragForcing.H index 4524c956f5..460466b677 100644 --- a/amr-wind/equation_systems/icns/source_terms/DragForcing.H +++ b/amr-wind/equation_systems/icns/source_terms/DragForcing.H @@ -30,12 +30,13 @@ public: const amrex::Array4& src_term) const override; private: + const SimTime& m_time; const CFDSim& m_sim; const amrex::AmrCore& m_mesh; const Field& m_velocity; amrex::Gpu::DeviceVector m_device_vel_ht; amrex::Gpu::DeviceVector m_device_vel_vals; - amrex::Real m_drag{100.0}; + amrex::Real m_drag{10.0}; amrex::Real m_sponge_strength{1.0}; amrex::Real m_sponge_density{1.0}; amrex::Real m_sponge_distanceX{1000}; diff --git a/amr-wind/equation_systems/icns/source_terms/DragForcing.cpp b/amr-wind/equation_systems/icns/source_terms/DragForcing.cpp index 47d0c3182f..92565a5b09 100644 --- a/amr-wind/equation_systems/icns/source_terms/DragForcing.cpp +++ b/amr-wind/equation_systems/icns/source_terms/DragForcing.cpp @@ -8,7 +8,8 @@ namespace amr_wind::pde::icns { DragForcing::DragForcing(const CFDSim& sim) - : m_sim(sim) + : m_time(sim.time()) + , m_sim(sim) , m_mesh(sim.mesh()) , m_velocity(sim.repo().get_field("velocity")) { @@ -79,6 +80,7 @@ void DragForcing::operator()( const auto* device_vel_ht = m_device_vel_ht.data(); const auto* device_vel_vals = m_device_vel_vals.data(); const unsigned vsize = m_device_vel_ht.size(); + const auto& dt = m_time.deltaT(); amrex::ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept { const amrex::Real x = prob_lo[0] + (i + 0.5) * dx[0]; const amrex::Real y = prob_lo[1] + (j + 0.5) * dx[1]; @@ -93,7 +95,7 @@ void DragForcing::operator()( : (startY - y) / (startY - prob_lo[1]); yi = std::max(yi, 0.0); ydamping = sponge_strength * yi * yi; - const amrex::Real Cd = dragCoefficient / dx[0]; + const amrex::Real Cd = dragCoefficient / dx[2]; amrex::Real spongeVelX = 0.0; amrex::Real spongeVelY = 0.0; amrex::Real spongeVelZ = 0.0; @@ -111,35 +113,42 @@ void DragForcing::operator()( spongeVelZ = device_vel_vals[iz]; } } - // Terrain Drag amrex::Real Dxz = 0.0; amrex::Real Dyz = 0.0; + amrex::Real bcforcing_x = 0; + amrex::Real bcforcing_y = 0; const amrex::Real ux1 = vel(i, j, k, 0); const amrex::Real uy1 = vel(i, j, k, 1); const amrex::Real uz1 = vel(i, j, k, 2); const amrex::Real m = std::sqrt(ux1 * ux1 + uy1 * uy1 + uz1 * uz1); if (drag(i, j, k) == 1) { - const amrex::Real m1 = std::sqrt(ux1 * ux1 + uy1 * uy1); - const amrex::Real ux2 = vel(i, j, k - 1, 0); - const amrex::Real uy2 = vel(i, j, k - 1, 1); + const amrex::Real ux2 = vel(i, j, k + 1, 0); + const amrex::Real uy2 = vel(i, j, k + 1, 1); const amrex::Real m2 = std::sqrt(ux2 * ux2 + uy2 * uy2); const amrex::Real kappa = 0.41; const amrex::Real z0 = std::max(terrainz0(i, j, k), 1e-4); - const amrex::Real ustar = std::min(sponge_strength, 1.0) * - std::abs(m2 - m1) * kappa / - std::log((z + z0) / z0); + const amrex::Real ustar = m2 * kappa / std::log(1.5 * dx[2] / z0); + const amrex::Real uTarget = + ustar / kappa * std::log(0.5 * dx[2] / z0); + const amrex::Real uxTarget = + uTarget * ux2 / (1e-5 + std::sqrt(ux2 * ux2 + uy2 * uy2)); + const amrex::Real uyTarget = + uTarget * uy2 / (1e-5 + std::sqrt(ux2 * ux2 + uy2 * uy2)); + bcforcing_x = -(uxTarget - ux1) / dt; + bcforcing_y = -(uyTarget - uy1) / dt; Dxz = -ustar * ustar * ux1 / (1e-5 + std::sqrt(ux1 * ux1 + uy1 * uy1)) / dx[2]; Dyz = -ustar * ustar * uy1 / (1e-5 + std::sqrt(ux1 * ux1 + uy1 * uy1)) / dx[2]; } - // Adjusting Cd for momentum - const amrex::Real CdM = std::min(Cd / (m + 1e-5), 1000.0); + const amrex::Real CdM = std::min(Cd / (m + 1e-5), 1000.0 / dx[2]); src_term(i, j, k, 0) -= (CdM * m * ux1 * blank(i, j, k) + Dxz * drag(i, j, k) + + bcforcing_x * drag(i, j, k) + (xdamping + ydamping) * (ux1 - sponge_density * spongeVelX)); src_term(i, j, k, 1) -= (CdM * m * uy1 * blank(i, j, k) + Dyz * drag(i, j, k) + + bcforcing_y * drag(i, j, k) + (xdamping + ydamping) * (uy1 - sponge_density * spongeVelY)); src_term(i, j, k, 2) -= (CdM * m * uz1 * blank(i, j, k) + diff --git a/amr-wind/equation_systems/temperature/source_terms/DragTempForcing.H b/amr-wind/equation_systems/temperature/source_terms/DragTempForcing.H index 084e41ac6d..4894d5f4d2 100644 --- a/amr-wind/equation_systems/temperature/source_terms/DragTempForcing.H +++ b/amr-wind/equation_systems/temperature/source_terms/DragTempForcing.H @@ -33,11 +33,11 @@ public: private: const CFDSim& m_sim; const amrex::AmrCore& m_mesh; - Field& m_temperature; - amrex::Real m_drag{10.0}; + const Field& m_velocity; + const Field& m_temperature; + amrex::Real m_drag{1.0}; amrex::Real m_internalRefT{300.0}; }; } // namespace amr_wind::pde::temperature - #endif diff --git a/amr-wind/equation_systems/temperature/source_terms/DragTempForcing.cpp b/amr-wind/equation_systems/temperature/source_terms/DragTempForcing.cpp index 8e6678e7a9..bc44db3910 100644 --- a/amr-wind/equation_systems/temperature/source_terms/DragTempForcing.cpp +++ b/amr-wind/equation_systems/temperature/source_terms/DragTempForcing.cpp @@ -10,10 +10,11 @@ namespace amr_wind::pde::temperature { DragTempForcing::DragTempForcing(const CFDSim& sim) : m_sim(sim) , m_mesh(sim.mesh()) + , m_velocity(sim.repo().get_field("velocity")) , m_temperature(sim.repo().get_field("temperature")) { amrex::ParmParse pp("DragTempForcing"); - pp.query("drag_coefficient", m_drag); + pp.query("dragCoefficient", m_drag); pp.query("RefT", m_internalRefT); } @@ -23,10 +24,14 @@ void DragTempForcing::operator()( const int lev, const amrex::MFIter& mfi, const amrex::Box& bx, - const FieldState /*fstate*/, + const FieldState fstate, const amrex::Array4& src_term) const { - const auto temperature = m_temperature(lev).const_array(mfi); + const auto& vel = + m_velocity.state(field_impl::dof_state(fstate))(lev).const_array(mfi); + const auto& temperature = + m_temperature.state(field_impl::dof_state(fstate))(lev).const_array( + mfi); const bool is_terrain = this->m_sim.repo().int_field_exists("terrain_blank"); if (!is_terrain) { @@ -37,12 +42,17 @@ void DragTempForcing::operator()( const auto& blank = (*m_terrain_blank)(lev).const_array(mfi); const auto& geom = m_mesh.Geom(lev); const auto& dx = geom.CellSizeArray(); - const amrex::Real drag = m_drag; - const amrex::Real TRef = m_internalRefT; + const amrex::Real gpu_drag = m_drag / dx[2]; + const amrex::Real gpu_TRef = m_internalRefT; amrex::ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept { - const amrex::Real Cd = drag / dx[0]; + const amrex::Real ux1 = vel(i, j, k, 0); + const amrex::Real uy1 = vel(i, j, k, 1); + const amrex::Real uz1 = vel(i, j, k, 2); + const amrex::Real m = std::sqrt(ux1 * ux1 + uy1 * uy1 + uz1 * uz1); + const amrex::Real Cd = std::min(gpu_drag / (m + 1e-5), 10 / dx[2]); + ; src_term(i, j, k, 0) -= - (Cd * (temperature(i, j, k, 0) - TRef) * blank(i, j, k)); + (Cd * (temperature(i, j, k, 0) - gpu_TRef) * blank(i, j, k, 0)); }); } diff --git a/amr-wind/turbulence/LES/Kosovic.cpp b/amr-wind/turbulence/LES/Kosovic.cpp index 558bdafd88..1016481e77 100644 --- a/amr-wind/turbulence/LES/Kosovic.cpp +++ b/amr-wind/turbulence/LES/Kosovic.cpp @@ -54,11 +54,11 @@ void Kosovic::update_turbulent_viscosity( const auto& den = m_rho.state(fstate); const auto& geom_vec = repo.mesh().Geom(); const amrex::Real Cs_sqr = this->m_Cs * this->m_Cs; - const bool is_terrain = + const bool has_terrain = this->m_sim.repo().int_field_exists("terrain_blank"); const auto* m_terrain_blank = - is_terrain ? &this->m_sim.repo().get_int_field("terrain_blank") - : nullptr; + has_terrain ? &this->m_sim.repo().get_int_field("terrain_blank") + : nullptr; // Populate strainrate into the turbulent viscosity arrays to avoid creating // a temporary buffer fvm::strainrate(mu_turb, vel); @@ -86,20 +86,21 @@ void Kosovic::update_turbulent_viscosity( const auto& mu_arr = mu_turb(lev).array(mfi); const auto& rho_arr = den(lev).const_array(mfi); const auto& divNijLevel = (this->m_divNij)(lev).array(mfi); + // const auto& blank_arr = (*m_terrain_blank)(lev).array(mfi); const auto& blank_arr = - is_terrain ? (*m_terrain_blank)(lev).const_array(mfi) - : amrex::Array4(); + has_terrain ? (*m_terrain_blank)(lev).const_array(mfi) + : amrex::Array4(); amrex::ParallelFor( bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept { const amrex::Real rho = rho_arr(i, j, k); - const amrex::Real z = problo[2] + (k + 0.5) * dz; - const amrex::Real fmu = std::exp(-z / locSwitchLoc); + const amrex::Real x3 = problo[2] + (k + 0.5) * dz; + const amrex::Real fmu = std::exp(-x3 / locSwitchLoc); const amrex::Real phiM = - (locMOL < 0) ? std::pow(1 - 16 * z / locMOL, -0.25) - : 1 + 5 * z / locMOL; + (locMOL < 0) ? std::pow(1 - 16 * x3 / locMOL, -0.25) + : 1 + 5 * x3 / locMOL; const amrex::Real ransL = std::pow(0.41 * (k + 1) * dz / phiM, 2); - amrex::Real turnOff = std::exp(-z / locLESTurnOff); + amrex::Real turnOff = std::exp(-x3 / locLESTurnOff); amrex::Real viscosityScale = locSurfaceFactor * (std::pow(1 - fmu, locSurfaceRANSExp) * @@ -107,7 +108,7 @@ void Kosovic::update_turbulent_viscosity( std::pow(fmu, locSurfaceRANSExp) * ransL) + (1 - locSurfaceFactor) * smag_factor; const amrex::Real blankTerrain = - (is_terrain) ? 1 - blank_arr(i, j, k, 0) : 1.0; + (has_terrain) ? 1 - blank_arr(i, j, k, 0) : 1.0; mu_arr(i, j, k) *= rho * viscosityScale * turnOff * blankTerrain; amrex::Real stressScale = diff --git a/amr-wind/wind_energy/ABLWallFunction.cpp b/amr-wind/wind_energy/ABLWallFunction.cpp index 5e7a123c6b..a4b41d029a 100644 --- a/amr-wind/wind_energy/ABLWallFunction.cpp +++ b/amr-wind/wind_energy/ABLWallFunction.cpp @@ -171,7 +171,6 @@ void ABLVelWallFunc::wall_model( const auto& density = repo.get_field("density", rho_state); const auto& viscosity = repo.get_field("velocity_mueff"); const int nlevels = repo.num_active_levels(); - amrex::Orientation zlo(amrex::Direction::z, amrex::Orientation::low); amrex::Orientation zhi(amrex::Direction::z, amrex::Orientation::high); if (velocity.bc_type()[zhi] == BC::wall_model) { @@ -180,7 +179,9 @@ void ABLVelWallFunc::wall_model( if (velocity.bc_type()[zlo] != BC::wall_model) { return; } - + const bool has_terrain = repo.int_field_exists("terrain_blank"); + const auto* m_terrain_blank = + has_terrain ? &repo.get_int_field("terrain_blank") : nullptr; for (int lev = 0; lev < nlevels; ++lev) { const auto& geom = repo.mesh().Geom(lev); const auto& domain = geom.Domain(); @@ -203,7 +204,9 @@ void ABLVelWallFunc::wall_model( const auto& vold_arr = vold_lev.const_array(mfi); const auto& den = rho_lev.const_array(mfi); const auto& eta = eta_lev.const_array(mfi); - + const auto& blank_arr = + has_terrain ? (*m_terrain_blank)(lev).const_array(mfi) + : amrex::Array4(); if (bx.smallEnd(idim) == domain.smallEnd(idim) && velocity.bc_type()[zlo] == BC::wall_model) { amrex::ParallelFor( @@ -216,12 +219,15 @@ void ABLVelWallFunc::wall_model( // Dirichlet BC varr(i, j, k - 1, 2) = 0.0; - + const amrex::Real blankTerrain = + (has_terrain) ? 1 - blank_arr(i, j, k, 0) : 1.0; // Shear stress BC - varr(i, j, k - 1, 0) = - tau.calc_vel_x(uu, wspd) * den(i, j, k) / mu; - varr(i, j, k - 1, 1) = - tau.calc_vel_y(vv, wspd) * den(i, j, k) / mu; + varr(i, j, k - 1, 0) = blankTerrain * + tau.calc_vel_x(uu, wspd) * + den(i, j, k) / mu; + varr(i, j, k - 1, 1) = blankTerrain * + tau.calc_vel_y(vv, wspd) * + den(i, j, k) / mu; }); } } @@ -292,7 +298,9 @@ void ABLTempWallFunc::wall_model( const auto& density = repo.get_field("density", rho_state); const auto& alpha = repo.get_field("temperature_mueff"); const int nlevels = repo.num_active_levels(); - + const bool has_terrain = repo.int_field_exists("terrain_blank"); + const auto* m_terrain_blank = + has_terrain ? &repo.get_int_field("terrain_blank") : nullptr; for (int lev = 0; lev < nlevels; ++lev) { const auto& geom = repo.mesh().Geom(lev); const auto& domain = geom.Domain(); @@ -317,6 +325,9 @@ void ABLTempWallFunc::wall_model( const auto& tarr = theta.array(mfi); const auto& den = rho_lev.const_array(mfi); const auto& eta = eta_lev.const_array(mfi); + const auto& blank_arr = + has_terrain ? (*m_terrain_blank)(lev).const_array(mfi) + : amrex::Array4(); if (bx.smallEnd(idim) == domain.smallEnd(idim) && temperature.bc_type()[zlo] == BC::wall_model) { @@ -328,7 +339,9 @@ void ABLTempWallFunc::wall_model( const amrex::Real vv = vold_arr(i, j, k, 1); const amrex::Real wspd = std::sqrt(uu * uu + vv * vv); const amrex::Real theta2 = told_arr(i, j, k); - tarr(i, j, k - 1) = den(i, j, k) * + const amrex::Real blankTerrain = + (has_terrain) ? 1 - blank_arr(i, j, k, 0) : 1.0; + tarr(i, j, k - 1) = blankTerrain * den(i, j, k) * tau.calc_theta(wspd, theta2) / alphaT; }); From dea867a26ae8387cd8ae3e9ee5a5114b26daa747 Mon Sep 17 00:00:00 2001 From: hgopalan Date: Mon, 22 Jul 2024 15:59:03 -0600 Subject: [PATCH 53/77] Update AMRex conflict --- amr-wind/wind_energy/ABLWallFunction.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/amr-wind/wind_energy/ABLWallFunction.cpp b/amr-wind/wind_energy/ABLWallFunction.cpp index a4b41d029a..e6c7ea17b5 100644 --- a/amr-wind/wind_energy/ABLWallFunction.cpp +++ b/amr-wind/wind_energy/ABLWallFunction.cpp @@ -22,7 +22,6 @@ ABLWallFunction::ABLWallFunction(const CFDSim& sim) } amrex::ParmParse pp("ABL"); - pp.query("kappa", m_mo.kappa); pp.query("mo_gamma_m", m_mo.gamma_m); pp.query("mo_gamma_h", m_mo.gamma_h); From 406628d162f3c934c93cd9f7f6c67ac8567ec332 Mon Sep 17 00:00:00 2001 From: hgopalan Date: Mon, 22 Jul 2024 16:16:35 -0600 Subject: [PATCH 54/77] Wall Function Update --- amr-wind/wind_energy/ABLWallFunction.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/amr-wind/wind_energy/ABLWallFunction.cpp b/amr-wind/wind_energy/ABLWallFunction.cpp index e6c7ea17b5..04c5c86cc1 100644 --- a/amr-wind/wind_energy/ABLWallFunction.cpp +++ b/amr-wind/wind_energy/ABLWallFunction.cpp @@ -221,6 +221,8 @@ void ABLVelWallFunc::wall_model( const amrex::Real blankTerrain = (has_terrain) ? 1 - blank_arr(i, j, k, 0) : 1.0; // Shear stress BC + // Blank Terrain added to keep the boundary condition backward compatible + // while adding terrain sensitive BC varr(i, j, k - 1, 0) = blankTerrain * tau.calc_vel_x(uu, wspd) * den(i, j, k) / mu; From f8241191438008fd367000afc3ca956e64f2d61d Mon Sep 17 00:00:00 2001 From: hgopalan Date: Mon, 22 Jul 2024 17:08:54 -0600 Subject: [PATCH 55/77] Drag Force Information --- amr-wind/equation_systems/icns/source_terms/DragForcing.H | 1 + 1 file changed, 1 insertion(+) diff --git a/amr-wind/equation_systems/icns/source_terms/DragForcing.H b/amr-wind/equation_systems/icns/source_terms/DragForcing.H index 460466b677..d93cdbf3c5 100644 --- a/amr-wind/equation_systems/icns/source_terms/DragForcing.H +++ b/amr-wind/equation_systems/icns/source_terms/DragForcing.H @@ -36,6 +36,7 @@ private: const Field& m_velocity; amrex::Gpu::DeviceVector m_device_vel_ht; amrex::Gpu::DeviceVector m_device_vel_vals; + // Smaller value gives a nice smooth start amrex::Real m_drag{10.0}; amrex::Real m_sponge_strength{1.0}; amrex::Real m_sponge_density{1.0}; From bebab496444a8e5765729dce2ca6aae0a50dfa67 Mon Sep 17 00:00:00 2001 From: hgopalan Date: Mon, 22 Jul 2024 17:17:51 -0600 Subject: [PATCH 56/77] Updating amrex submob --- submods/amrex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/submods/amrex b/submods/amrex index 259db7cfb9..1da91151ae 160000 --- a/submods/amrex +++ b/submods/amrex @@ -1 +1 @@ -Subproject commit 259db7cfb99e7d1d2ab4bec9b1587fdf624a138a +Subproject commit 1da91151ae161c6d58afc182512075542e127b07 From 332dfef4ab01f84d803e624eb3f7f003f6f53ed1 Mon Sep 17 00:00:00 2001 From: hgopalan Date: Mon, 22 Jul 2024 17:20:19 -0600 Subject: [PATCH 57/77] Clang Format for Wall Function --- amr-wind/wind_energy/ABLWallFunction.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/amr-wind/wind_energy/ABLWallFunction.cpp b/amr-wind/wind_energy/ABLWallFunction.cpp index 04c5c86cc1..f78450241d 100644 --- a/amr-wind/wind_energy/ABLWallFunction.cpp +++ b/amr-wind/wind_energy/ABLWallFunction.cpp @@ -221,8 +221,8 @@ void ABLVelWallFunc::wall_model( const amrex::Real blankTerrain = (has_terrain) ? 1 - blank_arr(i, j, k, 0) : 1.0; // Shear stress BC - // Blank Terrain added to keep the boundary condition backward compatible - // while adding terrain sensitive BC + // Blank Terrain added to keep the boundary condition + // backward compatible while adding terrain sensitive BC varr(i, j, k - 1, 0) = blankTerrain * tau.calc_vel_x(uu, wspd) * den(i, j, k) / mu; From f23d79a62e223be4ce8186e452a4804ea140aac8 Mon Sep 17 00:00:00 2001 From: hgopalan Date: Mon, 22 Jul 2024 17:22:09 -0600 Subject: [PATCH 58/77] Clang Formatting --- amr-wind/equation_systems/icns/source_terms/DragForcing.H | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/amr-wind/equation_systems/icns/source_terms/DragForcing.H b/amr-wind/equation_systems/icns/source_terms/DragForcing.H index d93cdbf3c5..30f026e664 100644 --- a/amr-wind/equation_systems/icns/source_terms/DragForcing.H +++ b/amr-wind/equation_systems/icns/source_terms/DragForcing.H @@ -36,7 +36,7 @@ private: const Field& m_velocity; amrex::Gpu::DeviceVector m_device_vel_ht; amrex::Gpu::DeviceVector m_device_vel_vals; - // Smaller value gives a nice smooth start + // Smaller value gives a nice smooth start amrex::Real m_drag{10.0}; amrex::Real m_sponge_strength{1.0}; amrex::Real m_sponge_density{1.0}; From 36e7fe719f5dc5d8eade41acf2a2bf42f48d071c Mon Sep 17 00:00:00 2001 From: hgopalan Date: Mon, 22 Jul 2024 18:00:13 -0600 Subject: [PATCH 59/77] Clang formatting for deltaT --- amr-wind/equation_systems/icns/source_terms/DragForcing.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/amr-wind/equation_systems/icns/source_terms/DragForcing.cpp b/amr-wind/equation_systems/icns/source_terms/DragForcing.cpp index 92565a5b09..cf5241e54a 100644 --- a/amr-wind/equation_systems/icns/source_terms/DragForcing.cpp +++ b/amr-wind/equation_systems/icns/source_terms/DragForcing.cpp @@ -80,7 +80,7 @@ void DragForcing::operator()( const auto* device_vel_ht = m_device_vel_ht.data(); const auto* device_vel_vals = m_device_vel_vals.data(); const unsigned vsize = m_device_vel_ht.size(); - const auto& dt = m_time.deltaT(); + const auto& dt = m_time.delta_t(); amrex::ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept { const amrex::Real x = prob_lo[0] + (i + 0.5) * dx[0]; const amrex::Real y = prob_lo[1] + (j + 0.5) * dx[1]; From 19af0be430dc82b9b181bc5ac032d1497a4cfe3f Mon Sep 17 00:00:00 2001 From: hgopalan Date: Mon, 22 Jul 2024 18:20:37 -0600 Subject: [PATCH 60/77] Kosovic Model Update --- amr-wind/turbulence/LES/Kosovic.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/amr-wind/turbulence/LES/Kosovic.cpp b/amr-wind/turbulence/LES/Kosovic.cpp index 1016481e77..dfae6d5f0a 100644 --- a/amr-wind/turbulence/LES/Kosovic.cpp +++ b/amr-wind/turbulence/LES/Kosovic.cpp @@ -86,7 +86,6 @@ void Kosovic::update_turbulent_viscosity( const auto& mu_arr = mu_turb(lev).array(mfi); const auto& rho_arr = den(lev).const_array(mfi); const auto& divNijLevel = (this->m_divNij)(lev).array(mfi); - // const auto& blank_arr = (*m_terrain_blank)(lev).array(mfi); const auto& blank_arr = has_terrain ? (*m_terrain_blank)(lev).const_array(mfi) : amrex::Array4(); From 512e87f277ef35ef9030c43606f0f114863ca850 Mon Sep 17 00:00:00 2001 From: hgopalan Date: Mon, 22 Jul 2024 18:57:53 -0600 Subject: [PATCH 61/77] Adjusting for clang tidy --- amr-wind/physics/TerrainDrag.H | 2 +- amr-wind/physics/TerrainDrag.cpp | 2 +- unit_tests/wind_energy/test_abl_terrain.cpp | 13 ++++++------- 3 files changed, 8 insertions(+), 9 deletions(-) diff --git a/amr-wind/physics/TerrainDrag.H b/amr-wind/physics/TerrainDrag.H index 9f93b1e9d3..dd5b1c6056 100644 --- a/amr-wind/physics/TerrainDrag.H +++ b/amr-wind/physics/TerrainDrag.H @@ -36,7 +36,7 @@ public: void post_advance_work() override {} - int returnBlankValue(int i, int j, int k); + int return_blank_value(int i, int j, int k); private: CFDSim& m_sim; diff --git a/amr-wind/physics/TerrainDrag.cpp b/amr-wind/physics/TerrainDrag.cpp index 1f31e9506e..1274d9523a 100644 --- a/amr-wind/physics/TerrainDrag.cpp +++ b/amr-wind/physics/TerrainDrag.cpp @@ -172,7 +172,7 @@ void TerrainDrag::pre_init_actions() BL_PROFILE("amr-wind::" + this->identifier() + "::pre_init_actions"); } -int TerrainDrag::returnBlankValue(int i, int j, int k) +int TerrainDrag::return_blank_value(int i, int j, int k) { int lev = 0; amrex::MFIter mfi(m_terrain_blank(lev)); diff --git a/unit_tests/wind_energy/test_abl_terrain.cpp b/unit_tests/wind_energy/test_abl_terrain.cpp index 51b0f54d18..3032c4a6d7 100644 --- a/unit_tests/wind_energy/test_abl_terrain.cpp +++ b/unit_tests/wind_energy/test_abl_terrain.cpp @@ -27,7 +27,7 @@ void write_terrain(const std::string& fname) namespace amr_wind_tests { // Testing the terrain drag reading to ensure that terrain is properly setup -class terrainTest : public MeshTest +class terraintest : public MeshTest { protected: void populate_parameters() override @@ -47,15 +47,14 @@ class terrainTest : public MeshTest pp.addarr("prob_hi", probhi); } } - std::string terrain_fname = "terrain.amrwind"; + std::string terrainfname = "terrain.amrwind"; }; -TEST_F(terrainTest, terrain) +TEST_F(terraintest, terrain) { constexpr amrex::Real tol = 0; - // Write target wind file - write_terrain(terrain_fname); + write_terrain(terrainfname); populate_parameters(); initialize_mesh(); auto& pde_mgr = sim().pde_manager(); @@ -68,10 +67,10 @@ TEST_F(terrainTest, terrain) terrain_drag.post_init_actions(); int value = 100; // Outside Point - value = terrain_drag.returnBlankValue(5, 5, 1); + value = terrain_drag.return_blank_value(5, 5, 1); EXPECT_EQ(value, tol); // Inside Point - value = terrain_drag.returnBlankValue(15, 10, 1); + value = terrain_drag.return_blank_value(15, 10, 1); EXPECT_EQ(value, 1 + tol); } From 03be705ad613e8eed5597971b6cebb6c6c8e798f Mon Sep 17 00:00:00 2001 From: Harish Date: Wed, 7 Aug 2024 14:22:14 -0600 Subject: [PATCH 62/77] Update CMakeLists.txt --- amr-wind/physics/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/amr-wind/physics/CMakeLists.txt b/amr-wind/physics/CMakeLists.txt index a169a38994..f57edb26d1 100644 --- a/amr-wind/physics/CMakeLists.txt +++ b/amr-wind/physics/CMakeLists.txt @@ -16,7 +16,7 @@ target_sources(${amr_wind_lib_name} ScalarAdvection.cpp VortexDipole.cpp BurggrafFlow.cpp - TerrainDrag.cpp + ActuatorSourceTagging.cpp ) add_subdirectory(multiphase) From 62a97a9296f20bb0d41e292b50470a0d8f595003 Mon Sep 17 00:00:00 2001 From: hgopalan Date: Wed, 7 Aug 2024 14:26:52 -0600 Subject: [PATCH 63/77] Update with main --- amr-wind/physics/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/amr-wind/physics/CMakeLists.txt b/amr-wind/physics/CMakeLists.txt index f57edb26d1..f09db6823a 100644 --- a/amr-wind/physics/CMakeLists.txt +++ b/amr-wind/physics/CMakeLists.txt @@ -16,6 +16,7 @@ target_sources(${amr_wind_lib_name} ScalarAdvection.cpp VortexDipole.cpp BurggrafFlow.cpp + TerrainDrag.cpp ActuatorSourceTagging.cpp ) From 532bcd42e6c5ba4b8f82837ed1461d029dbeb760 Mon Sep 17 00:00:00 2001 From: hgopalan Date: Wed, 7 Aug 2024 14:35:37 -0600 Subject: [PATCH 64/77] Added commit for failed test --- test/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 09b8525f87..073562dbfa 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -265,6 +265,7 @@ if(AMR_WIND_ENABLE_NETCDF) add_test_re(abl_meso_input_ipa) add_test_re(abl_kosovic_neutral) add_test_re(abl_kosovic_neutral_ib) + add_test_re(nrel_precursor) endif() if(AMR_WIND_ENABLE_MASA) From 5099d332254c22c0df66d64663f6c71c1b9eb1c9 Mon Sep 17 00:00:00 2001 From: Harish Date: Mon, 26 Aug 2024 07:33:04 -0600 Subject: [PATCH 65/77] Update CMakeLists.txt --- test/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 073562dbfa..1d04a9c8ad 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -264,6 +264,7 @@ if(AMR_WIND_ENABLE_NETCDF) add_test_re(abl_meso_input_dpa) add_test_re(abl_meso_input_ipa) add_test_re(abl_kosovic_neutral) + add_test_re(abl_sampling_netcdf) add_test_re(abl_kosovic_neutral_ib) add_test_re(nrel_precursor) endif() From 150adf083575aa3cd8cea42351109339fd5248b7 Mon Sep 17 00:00:00 2001 From: Harish Date: Mon, 26 Aug 2024 07:34:20 -0600 Subject: [PATCH 66/77] Update CMakeLists.txt --- test/CMakeLists.txt | 2 -- 1 file changed, 2 deletions(-) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 1d04a9c8ad..4eb3cfed44 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -265,8 +265,6 @@ if(AMR_WIND_ENABLE_NETCDF) add_test_re(abl_meso_input_ipa) add_test_re(abl_kosovic_neutral) add_test_re(abl_sampling_netcdf) - add_test_re(abl_kosovic_neutral_ib) - add_test_re(nrel_precursor) endif() if(AMR_WIND_ENABLE_MASA) From bef083cee89d8fee303eb2d97994071ed457e3d0 Mon Sep 17 00:00:00 2001 From: Harish Date: Mon, 26 Aug 2024 07:35:19 -0600 Subject: [PATCH 67/77] Update CMakeLists.txt --- test/CMakeLists.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index bce98fbdf5..b6d127ab6e 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -283,6 +283,8 @@ if(AMR_WIND_ENABLE_NETCDF) add_test_re(abl_meso_input_ipa) add_test_re(abl_kosovic_neutral) add_test_re(abl_sampling_netcdf) + add_test_re(abl_kosovic_neutral_ib) + add_test_re(nrel_precursor) endif() if(AMR_WIND_ENABLE_MASA) From 1ed85449695e6c86eda3360dcb040791f4a09f0f Mon Sep 17 00:00:00 2001 From: hgopalan Date: Mon, 26 Aug 2024 07:42:01 -0600 Subject: [PATCH 68/77] Added damping for all the horizontal directions and made them separate. --- .../icns/source_terms/DragForcing.H | 44 ++++---- .../icns/source_terms/DragForcing.cpp | 101 ++++++++++-------- .../source_terms/DragTempForcing.H | 4 +- .../source_terms/DragTempForcing.cpp | 32 +++--- amr-wind/physics/TerrainDrag.H | 3 +- amr-wind/physics/TerrainDrag.cpp | 30 +++--- 6 files changed, 116 insertions(+), 98 deletions(-) diff --git a/amr-wind/equation_systems/icns/source_terms/DragForcing.H b/amr-wind/equation_systems/icns/source_terms/DragForcing.H index 30f026e664..2189645b36 100644 --- a/amr-wind/equation_systems/icns/source_terms/DragForcing.H +++ b/amr-wind/equation_systems/icns/source_terms/DragForcing.H @@ -7,15 +7,15 @@ namespace amr_wind::pde::icns { -/** Adds the forcing term to include the presence of immersed boundary - * - * \ingroup icns_src - * - * - */ -class DragForcing : public MomentumSource::Register -{ -public: + /** Adds the forcing term to include the presence of immersed boundary + * + * \ingroup icns_src + * + * + */ + class DragForcing : public MomentumSource::Register + { + public: static std::string identifier() { return "DragForcing"; } explicit DragForcing(const CFDSim& sim); @@ -23,26 +23,32 @@ public: ~DragForcing() override; void operator()( - const int lev, - const amrex::MFIter& mfi, - const amrex::Box& bx, - const FieldState fstate, - const amrex::Array4& src_term) const override; + const int lev, + const amrex::MFIter& mfi, + const amrex::Box& bx, + const FieldState fstate, + const amrex::Array4& src_term) const override; -private: + private: const SimTime& m_time; const CFDSim& m_sim; const amrex::AmrCore& m_mesh; const Field& m_velocity; amrex::Gpu::DeviceVector m_device_vel_ht; amrex::Gpu::DeviceVector m_device_vel_vals; - // Smaller value gives a nice smooth start amrex::Real m_drag{10.0}; amrex::Real m_sponge_strength{1.0}; amrex::Real m_sponge_density{1.0}; - amrex::Real m_sponge_distanceX{1000}; - amrex::Real m_sponge_distanceY{1000}; -}; + amrex::Real m_sponge_distance_west{-1000}; + amrex::Real m_sponge_distance_east{1000}; + amrex::Real m_sponge_distance_south{-1000}; + amrex::Real m_sponge_distance_north{1000}; + int m_sponge_west{0}; + int m_sponge_east{1}; + int m_sponge_south{0}; + int m_sponge_north{1}; + bool m_is_laminar{false}; + }; } // namespace amr_wind::pde::icns diff --git a/amr-wind/equation_systems/icns/source_terms/DragForcing.cpp b/amr-wind/equation_systems/icns/source_terms/DragForcing.cpp index cf5241e54a..4560ce07e4 100644 --- a/amr-wind/equation_systems/icns/source_terms/DragForcing.cpp +++ b/amr-wind/equation_systems/icns/source_terms/DragForcing.cpp @@ -8,8 +8,8 @@ namespace amr_wind::pde::icns { DragForcing::DragForcing(const CFDSim& sim) - : m_time(sim.time()) - , m_sim(sim) + :m_time(sim.time()) + ,m_sim(sim) , m_mesh(sim.mesh()) , m_velocity(sim.repo().get_field("velocity")) { @@ -17,8 +17,15 @@ DragForcing::DragForcing(const CFDSim& sim) pp.query("drag_coefficient", m_drag); pp.query("sponge_strength", m_sponge_strength); pp.query("sponge_density", m_sponge_density); - pp.query("sponge_distanceX", m_sponge_distanceX); - pp.query("sponge_distanceY", m_sponge_distanceY); + pp.query("sponge_distance_west", m_sponge_distance_west); + pp.query("sponge_distance_east", m_sponge_distance_east); + pp.query("sponge_distance_south", m_sponge_distance_south); + pp.query("sponge_distance_north", m_sponge_distance_north); + pp.query("sponge_west", m_sponge_west); + pp.query("sponge_east", m_sponge_east); + pp.query("sponge_south", m_sponge_south); + pp.query("sponge_north", m_sponge_north); + pp.query("is_laminar",m_is_laminar); const auto& phy_mgr = m_sim.physics_manager(); if (phy_mgr.contains("ABL")) { const auto& abl = m_sim.physics_manager().get(); @@ -68,34 +75,42 @@ void DragForcing::operator()( const amrex::Real dragCoefficient = m_drag; const amrex::Real sponge_strength = m_sponge_strength; const amrex::Real sponge_density = m_sponge_density; - const amrex::Real startX = (m_sponge_distanceX > 0) - ? prob_hi[0] - m_sponge_distanceX - : prob_lo[0] - m_sponge_distanceX; - const amrex::Real startY = (m_sponge_distanceY > 0) - ? prob_hi[1] - m_sponge_distanceY - : prob_lo[1] - m_sponge_distanceY; - const unsigned spongeX = (m_sponge_distanceX > 0) ? 1 : 0; - const unsigned spongeY = (m_sponge_distanceY > 0) ? 1 : 0; + const amrex::Real start_east = prob_hi[0] - m_sponge_distance_east; + const amrex::Real start_west = prob_lo[0] - m_sponge_distance_west; + const amrex::Real start_north = prob_hi[1] - m_sponge_distance_north; + const amrex::Real start_south = prob_lo[1] - m_sponge_distance_south; + const int sponge_east=m_sponge_east; + const int sponge_west=m_sponge_west; + const int sponge_south=m_sponge_south; + const int sponge_north=m_sponge_north; // Copy Data const auto* device_vel_ht = m_device_vel_ht.data(); const auto* device_vel_vals = m_device_vel_vals.data(); const unsigned vsize = m_device_vel_ht.size(); const auto& dt = m_time.delta_t(); + bool is_laminar=m_is_laminar; + const amrex::Real scale_factor = (dx[2]<1.0) ? 1.0:1.0/dx[2]; + const amrex::Real Cd = (is_laminar && dx[2]<1)? dragCoefficient:dragCoefficient / dx[2]; amrex::ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept { const amrex::Real x = prob_lo[0] + (i + 0.5) * dx[0]; const amrex::Real y = prob_lo[1] + (j + 0.5) * dx[1]; const amrex::Real z = prob_lo[2] + (k + 0.5) * dx[2]; - amrex::Real xdamping = 0; - amrex::Real ydamping = 0; - amrex::Real xi = (spongeX == 1) ? (x - startX) / (prob_hi[0] - startX) - : (startX - x) / (startX - prob_lo[0]); - xi = std::max(xi, 0.0); - xdamping = sponge_strength * xi * xi; - amrex::Real yi = (spongeY == 1) ? (y - startY) / (prob_hi[1] - startY) - : (startY - y) / (startY - prob_lo[1]); - yi = std::max(yi, 0.0); - ydamping = sponge_strength * yi * yi; - const amrex::Real Cd = dragCoefficient / dx[2]; + amrex::Real xstart_damping = 0; + amrex::Real ystart_damping = 0; + amrex::Real xend_damping=0; + amrex::Real yend_damping=0; + amrex::Real xi_end = (x - start_east) / (prob_hi[0] - start_east); + amrex::Real xi_start = (start_west - x) / (start_west - prob_lo[0]); + xi_start = sponge_west*std::max(xi_start, 0.0); + xi_end = sponge_east*std::max(xi_end, 0.0); + xstart_damping = sponge_west*sponge_strength * xi_start * xi_start; + xend_damping = sponge_east*sponge_strength * xi_end * xi_end; + amrex::Real yi_end = (y - start_north) / (prob_hi[1] - start_north); + amrex::Real yi_start = (start_south - y) / (start_south - prob_lo[1]); + yi_start = sponge_south*std::max(yi_start, 0.0); + yi_end = sponge_north*std::max(yi_end, 0.0); + ystart_damping = sponge_strength * yi_start * yi_start; + yend_damping = sponge_strength * yi_end * yi_end; amrex::Real spongeVelX = 0.0; amrex::Real spongeVelY = 0.0; amrex::Real spongeVelZ = 0.0; @@ -115,44 +130,42 @@ void DragForcing::operator()( } amrex::Real Dxz = 0.0; amrex::Real Dyz = 0.0; - amrex::Real bcforcing_x = 0; - amrex::Real bcforcing_y = 0; + amrex::Real bcforcing_x=0; + amrex::Real bcforcing_y=0; const amrex::Real ux1 = vel(i, j, k, 0); const amrex::Real uy1 = vel(i, j, k, 1); const amrex::Real uz1 = vel(i, j, k, 2); const amrex::Real m = std::sqrt(ux1 * ux1 + uy1 * uy1 + uz1 * uz1); - if (drag(i, j, k) == 1) { + if (drag(i,j,k) == 1 && (! is_laminar)) { const amrex::Real ux2 = vel(i, j, k + 1, 0); const amrex::Real uy2 = vel(i, j, k + 1, 1); const amrex::Real m2 = std::sqrt(ux2 * ux2 + uy2 * uy2); const amrex::Real kappa = 0.41; const amrex::Real z0 = std::max(terrainz0(i, j, k), 1e-4); - const amrex::Real ustar = m2 * kappa / std::log(1.5 * dx[2] / z0); - const amrex::Real uTarget = - ustar / kappa * std::log(0.5 * dx[2] / z0); - const amrex::Real uxTarget = - uTarget * ux2 / (1e-5 + std::sqrt(ux2 * ux2 + uy2 * uy2)); - const amrex::Real uyTarget = - uTarget * uy2 / (1e-5 + std::sqrt(ux2 * ux2 + uy2 * uy2)); - bcforcing_x = -(uxTarget - ux1) / dt; - bcforcing_y = -(uyTarget - uy1) / dt; - Dxz = -ustar * ustar * ux1 / + const amrex::Real ustar = m2 * kappa / + std::log(1.5*dx[2] / z0); + const amrex::Real uTarget= ustar/kappa*std::log(0.5*dx[2]/z0); + const amrex::Real uxTarget = uTarget * ux2 / + (1e-5 + std::sqrt(ux2 * ux2 + uy2 * uy2)); + const amrex::Real uyTarget = uTarget * uy2 / + (1e-5 + std::sqrt(ux2 * ux2 + uy2 * uy2)); + bcforcing_x=-(uxTarget-ux1)/dt; + bcforcing_y=-(uyTarget-uy1)/dt; + Dxz = -ustar*ustar* ux1 / (1e-5 + std::sqrt(ux1 * ux1 + uy1 * uy1)) / dx[2]; Dyz = -ustar * ustar * uy1 / (1e-5 + std::sqrt(ux1 * ux1 + uy1 * uy1)) / dx[2]; } - const amrex::Real CdM = std::min(Cd / (m + 1e-5), 1000.0 / dx[2]); + const amrex::Real CdM = std::min(Cd / (m + 1e-5), 1000.0/scale_factor); src_term(i, j, k, 0) -= - (CdM * m * ux1 * blank(i, j, k) + Dxz * drag(i, j, k) + - bcforcing_x * drag(i, j, k) + - (xdamping + ydamping) * (ux1 - sponge_density * spongeVelX)); + (CdM * m * ux1 * blank(i, j, k) + Dxz * drag(i, j, k) + bcforcing_x * drag(i,j,k) + + (xstart_damping + xend_damping+ ystart_damping+yend_damping) * (ux1 - sponge_density * spongeVelX)); src_term(i, j, k, 1) -= - (CdM * m * uy1 * blank(i, j, k) + Dyz * drag(i, j, k) + - bcforcing_y * drag(i, j, k) + - (xdamping + ydamping) * (uy1 - sponge_density * spongeVelY)); + (CdM * m * uy1 * blank(i, j, k) + Dyz * drag(i, j, k) + bcforcing_y * drag(i,j,k) + + (xstart_damping + xend_damping+ ystart_damping+yend_damping) * (uy1 - sponge_density * spongeVelY)); src_term(i, j, k, 2) -= (CdM * m * uz1 * blank(i, j, k) + - (xdamping + ydamping) * (uz1 - sponge_density * spongeVelZ)); + (xstart_damping + xend_damping+ ystart_damping+yend_damping) * (uz1 - sponge_density * spongeVelZ)); }); } diff --git a/amr-wind/equation_systems/temperature/source_terms/DragTempForcing.H b/amr-wind/equation_systems/temperature/source_terms/DragTempForcing.H index 4894d5f4d2..085d4675f4 100644 --- a/amr-wind/equation_systems/temperature/source_terms/DragTempForcing.H +++ b/amr-wind/equation_systems/temperature/source_terms/DragTempForcing.H @@ -7,7 +7,7 @@ namespace amr_wind::pde::temperature { -/** Adding the source term to momentum equation to account for immersed +/** Adding the source term to energy equation to account for immersed * boundary. * * \ingroup temperature_src @@ -33,7 +33,7 @@ public: private: const CFDSim& m_sim; const amrex::AmrCore& m_mesh; - const Field& m_velocity; + const Field& m_velocity; const Field& m_temperature; amrex::Real m_drag{1.0}; amrex::Real m_internalRefT{300.0}; diff --git a/amr-wind/equation_systems/temperature/source_terms/DragTempForcing.cpp b/amr-wind/equation_systems/temperature/source_terms/DragTempForcing.cpp index bc44db3910..2e068ab8ed 100644 --- a/amr-wind/equation_systems/temperature/source_terms/DragTempForcing.cpp +++ b/amr-wind/equation_systems/temperature/source_terms/DragTempForcing.cpp @@ -1,3 +1,4 @@ + #include "amr-wind/equation_systems/temperature/source_terms/DragTempForcing.H" #include "amr-wind/utilities/IOManager.H" @@ -27,32 +28,27 @@ void DragTempForcing::operator()( const FieldState fstate, const amrex::Array4& src_term) const { - const auto& vel = - m_velocity.state(field_impl::dof_state(fstate))(lev).const_array(mfi); - const auto& temperature = - m_temperature.state(field_impl::dof_state(fstate))(lev).const_array( - mfi); - const bool is_terrain = - this->m_sim.repo().int_field_exists("terrain_blank"); + const auto& vel = + m_velocity.state(field_impl::dof_state(fstate))(lev).const_array(mfi); + const auto& temperature = m_temperature.state(field_impl::dof_state(fstate))(lev).const_array(mfi); + const bool is_terrain = this->m_sim.repo().int_field_exists("terrain_blank"); if (!is_terrain) { amrex::Abort("Need terrain blanking variable to use this source term"); } - auto* const m_terrain_blank = - &this->m_sim.repo().get_int_field("terrain_blank"); + auto* const m_terrain_blank = &this->m_sim.repo().get_int_field("terrain_blank"); const auto& blank = (*m_terrain_blank)(lev).const_array(mfi); const auto& geom = m_mesh.Geom(lev); const auto& dx = geom.CellSizeArray(); - const amrex::Real gpu_drag = m_drag / dx[2]; + const amrex::Real gpu_drag = m_drag/dx[2]; const amrex::Real gpu_TRef = m_internalRefT; amrex::ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept { - const amrex::Real ux1 = vel(i, j, k, 0); - const amrex::Real uy1 = vel(i, j, k, 1); - const amrex::Real uz1 = vel(i, j, k, 2); - const amrex::Real m = std::sqrt(ux1 * ux1 + uy1 * uy1 + uz1 * uz1); - const amrex::Real Cd = std::min(gpu_drag / (m + 1e-5), 10 / dx[2]); - ; - src_term(i, j, k, 0) -= - (Cd * (temperature(i, j, k, 0) - gpu_TRef) * blank(i, j, k, 0)); + const amrex::Real ux1 = vel(i, j, k, 0); + const amrex::Real uy1 = vel(i, j, k, 1); + const amrex::Real uz1 = vel(i, j, k, 2); + const amrex::Real m = std::sqrt(ux1 * ux1 + uy1 * uy1 + uz1 * uz1); + const amrex::Real Cd = std::min(gpu_drag/(m+1e-5),10/dx[2]); + src_term(i, j, k, 0) -= + (Cd * (temperature(i, j, k, 0) - gpu_TRef) * blank(i,j,k,0)); }); } diff --git a/amr-wind/physics/TerrainDrag.H b/amr-wind/physics/TerrainDrag.H index dd5b1c6056..874ea97052 100644 --- a/amr-wind/physics/TerrainDrag.H +++ b/amr-wind/physics/TerrainDrag.H @@ -36,7 +36,7 @@ public: void post_advance_work() override {} - int return_blank_value(int i, int j, int k); + int returnBlankValue(int i, int j, int k); private: CFDSim& m_sim; @@ -53,6 +53,7 @@ private: amrex::Vector m_zterrain; // Roughness Field Field& m_terrainz0; + Field& m_terrain_height; // Reading the Roughness Coordinates from file - Not Fully there yet // Need updates to ABLWallFunction in future amrex::Vector m_xrough; diff --git a/amr-wind/physics/TerrainDrag.cpp b/amr-wind/physics/TerrainDrag.cpp index 1274d9523a..660b0ab8aa 100644 --- a/amr-wind/physics/TerrainDrag.cpp +++ b/amr-wind/physics/TerrainDrag.cpp @@ -16,9 +16,10 @@ TerrainDrag::TerrainDrag(CFDSim& sim) , m_repo(sim.repo()) , m_mesh(sim.mesh()) , m_velocity(sim.repo().get_field("velocity")) - , m_terrain_blank(sim.repo().declare_int_field("terrain_blank", 1, 1, 1)) - , m_terrain_drag(sim.repo().declare_int_field("terrain_drag", 1, 1, 1)) + , m_terrain_blank(sim.repo().declare_int_field("terrain_blank", 1,1,1)) + , m_terrain_drag(sim.repo().declare_int_field("terrain_drag", 1,1,1)) , m_terrainz0(sim.repo().declare_field("terrainz0", 1, 1, 1)) + , m_terrain_height(sim.repo().declare_field("terrain_height", 1, 1, 1)) { std::string terrainfile("terrain.amrwind"); std::ifstream file(terrainfile, std::ios::in); @@ -41,9 +42,10 @@ TerrainDrag::TerrainDrag(CFDSim& sim) m_z0rough.push_back(value3); } file1.close(); - m_sim.io_manager().register_output_int_var("terrainDrag"); - m_sim.io_manager().register_output_int_var("terrainBlank"); + m_sim.io_manager().register_output_int_var("terrain_drag"); + m_sim.io_manager().register_output_int_var("terrain_blank"); m_sim.io_manager().register_io_var("terrainz0"); + m_sim.io_manager().register_io_var("terrain_height"); } void TerrainDrag::post_init_actions() @@ -58,6 +60,7 @@ void TerrainDrag::post_init_actions() auto& velocity = m_velocity(level); auto& blanking = m_terrain_blank(level); auto& terrainz0 = m_terrainz0(level); + auto& terrain_height=m_terrain_height(level); auto& drag = m_terrain_drag(level); // copy terrain data to gpu amrex::Gpu::DeviceVector device_xterrain( @@ -99,6 +102,7 @@ void TerrainDrag::post_init_actions() auto levelBlanking = blanking.array(mfi); auto levelDrag = drag.array(mfi); auto levelz0 = terrainz0.array(mfi); + auto levelheight=terrain_height.array(mfi); const unsigned terrainSize = m_xterrain.size(); const unsigned roughnessSize = m_xrough.size(); amrex::ParallelFor( @@ -118,13 +122,11 @@ void TerrainDrag::post_init_actions() residual = radius; terrainHt = zterrain_ptr[ii]; } - if (radius < dx[0]) { - break; - } - } + } levelBlanking(i, j, k, 0) = static_cast(z <= terrainHt); - residual = 10000; + levelheight(i,j,k,0)=std::max(std::abs(z-terrainHt),0.5*dx[2]); + residual = 10000; amrex::Real roughz0 = 0.1; for (unsigned ii = 0; ii < roughnessSize; ++ii) { const amrex::Real radius = std::sqrt( @@ -139,7 +141,7 @@ void TerrainDrag::post_init_actions() } } levelz0(i, j, k, 0) = roughz0; - }); + }); amrex::ParallelFor( vbx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept { // Terrain Height @@ -163,7 +165,7 @@ void TerrainDrag::post_init_actions() levelDrag(i, j, k, 0) = 1; } }); - } + } } } @@ -172,12 +174,12 @@ void TerrainDrag::pre_init_actions() BL_PROFILE("amr-wind::" + this->identifier() + "::pre_init_actions"); } -int TerrainDrag::return_blank_value(int i, int j, int k) +int TerrainDrag::returnBlankValue(int i, int j, int k) { int lev = 0; amrex::MFIter mfi(m_terrain_blank(lev)); - const auto& levelBlanking = m_terrain_blank(lev).const_array(mfi); - return int(levelBlanking(i, j, k)); + const auto& terrain_blank = m_terrain_blank(lev).const_array(mfi); + return int(terrain_blank(i, j, k)); } } // namespace amr_wind::terraindrag From cb3843b4bb6f8759f04efd88f5524098a4713d35 Mon Sep 17 00:00:00 2001 From: hgopalan Date: Mon, 26 Aug 2024 07:43:56 -0600 Subject: [PATCH 69/77] Clang formatting --- .../icns/source_terms/DragForcing.H | 34 ++++---- .../icns/source_terms/DragForcing.cpp | 87 ++++++++++--------- .../source_terms/DragTempForcing.H | 2 +- .../source_terms/DragTempForcing.cpp | 30 ++++--- amr-wind/physics/TerrainDrag.H | 2 +- amr-wind/physics/TerrainDrag.cpp | 19 ++-- 6 files changed, 93 insertions(+), 81 deletions(-) diff --git a/amr-wind/equation_systems/icns/source_terms/DragForcing.H b/amr-wind/equation_systems/icns/source_terms/DragForcing.H index 2189645b36..67ec12b5b1 100644 --- a/amr-wind/equation_systems/icns/source_terms/DragForcing.H +++ b/amr-wind/equation_systems/icns/source_terms/DragForcing.H @@ -7,15 +7,15 @@ namespace amr_wind::pde::icns { - /** Adds the forcing term to include the presence of immersed boundary - * - * \ingroup icns_src - * - * - */ - class DragForcing : public MomentumSource::Register - { - public: +/** Adds the forcing term to include the presence of immersed boundary + * + * \ingroup icns_src + * + * + */ +class DragForcing : public MomentumSource::Register +{ +public: static std::string identifier() { return "DragForcing"; } explicit DragForcing(const CFDSim& sim); @@ -23,13 +23,13 @@ namespace amr_wind::pde::icns { ~DragForcing() override; void operator()( - const int lev, - const amrex::MFIter& mfi, - const amrex::Box& bx, - const FieldState fstate, - const amrex::Array4& src_term) const override; + const int lev, + const amrex::MFIter& mfi, + const amrex::Box& bx, + const FieldState fstate, + const amrex::Array4& src_term) const override; - private: +private: const SimTime& m_time; const CFDSim& m_sim; const amrex::AmrCore& m_mesh; @@ -46,9 +46,9 @@ namespace amr_wind::pde::icns { int m_sponge_west{0}; int m_sponge_east{1}; int m_sponge_south{0}; - int m_sponge_north{1}; + int m_sponge_north{1}; bool m_is_laminar{false}; - }; +}; } // namespace amr_wind::pde::icns diff --git a/amr-wind/equation_systems/icns/source_terms/DragForcing.cpp b/amr-wind/equation_systems/icns/source_terms/DragForcing.cpp index 4560ce07e4..ac25a676cd 100644 --- a/amr-wind/equation_systems/icns/source_terms/DragForcing.cpp +++ b/amr-wind/equation_systems/icns/source_terms/DragForcing.cpp @@ -8,8 +8,8 @@ namespace amr_wind::pde::icns { DragForcing::DragForcing(const CFDSim& sim) - :m_time(sim.time()) - ,m_sim(sim) + : m_time(sim.time()) + , m_sim(sim) , m_mesh(sim.mesh()) , m_velocity(sim.repo().get_field("velocity")) { @@ -25,7 +25,7 @@ DragForcing::DragForcing(const CFDSim& sim) pp.query("sponge_east", m_sponge_east); pp.query("sponge_south", m_sponge_south); pp.query("sponge_north", m_sponge_north); - pp.query("is_laminar",m_is_laminar); + pp.query("is_laminar", m_is_laminar); const auto& phy_mgr = m_sim.physics_manager(); if (phy_mgr.contains("ABL")) { const auto& abl = m_sim.physics_manager().get(); @@ -77,38 +77,39 @@ void DragForcing::operator()( const amrex::Real sponge_density = m_sponge_density; const amrex::Real start_east = prob_hi[0] - m_sponge_distance_east; const amrex::Real start_west = prob_lo[0] - m_sponge_distance_west; - const amrex::Real start_north = prob_hi[1] - m_sponge_distance_north; + const amrex::Real start_north = prob_hi[1] - m_sponge_distance_north; const amrex::Real start_south = prob_lo[1] - m_sponge_distance_south; - const int sponge_east=m_sponge_east; - const int sponge_west=m_sponge_west; - const int sponge_south=m_sponge_south; - const int sponge_north=m_sponge_north; + const int sponge_east = m_sponge_east; + const int sponge_west = m_sponge_west; + const int sponge_south = m_sponge_south; + const int sponge_north = m_sponge_north; // Copy Data const auto* device_vel_ht = m_device_vel_ht.data(); const auto* device_vel_vals = m_device_vel_vals.data(); const unsigned vsize = m_device_vel_ht.size(); const auto& dt = m_time.delta_t(); - bool is_laminar=m_is_laminar; - const amrex::Real scale_factor = (dx[2]<1.0) ? 1.0:1.0/dx[2]; - const amrex::Real Cd = (is_laminar && dx[2]<1)? dragCoefficient:dragCoefficient / dx[2]; + bool is_laminar = m_is_laminar; + const amrex::Real scale_factor = (dx[2] < 1.0) ? 1.0 : 1.0 / dx[2]; + const amrex::Real Cd = + (is_laminar && dx[2] < 1) ? dragCoefficient : dragCoefficient / dx[2]; amrex::ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept { const amrex::Real x = prob_lo[0] + (i + 0.5) * dx[0]; const amrex::Real y = prob_lo[1] + (j + 0.5) * dx[1]; const amrex::Real z = prob_lo[2] + (k + 0.5) * dx[2]; amrex::Real xstart_damping = 0; amrex::Real ystart_damping = 0; - amrex::Real xend_damping=0; - amrex::Real yend_damping=0; + amrex::Real xend_damping = 0; + amrex::Real yend_damping = 0; amrex::Real xi_end = (x - start_east) / (prob_hi[0] - start_east); - amrex::Real xi_start = (start_west - x) / (start_west - prob_lo[0]); - xi_start = sponge_west*std::max(xi_start, 0.0); - xi_end = sponge_east*std::max(xi_end, 0.0); - xstart_damping = sponge_west*sponge_strength * xi_start * xi_start; - xend_damping = sponge_east*sponge_strength * xi_end * xi_end; + amrex::Real xi_start = (start_west - x) / (start_west - prob_lo[0]); + xi_start = sponge_west * std::max(xi_start, 0.0); + xi_end = sponge_east * std::max(xi_end, 0.0); + xstart_damping = sponge_west * sponge_strength * xi_start * xi_start; + xend_damping = sponge_east * sponge_strength * xi_end * xi_end; amrex::Real yi_end = (y - start_north) / (prob_hi[1] - start_north); - amrex::Real yi_start = (start_south - y) / (start_south - prob_lo[1]); - yi_start = sponge_south*std::max(yi_start, 0.0); - yi_end = sponge_north*std::max(yi_end, 0.0); + amrex::Real yi_start = (start_south - y) / (start_south - prob_lo[1]); + yi_start = sponge_south * std::max(yi_start, 0.0); + yi_end = sponge_north * std::max(yi_end, 0.0); ystart_damping = sponge_strength * yi_start * yi_start; yend_damping = sponge_strength * yi_end * yi_end; amrex::Real spongeVelX = 0.0; @@ -130,42 +131,48 @@ void DragForcing::operator()( } amrex::Real Dxz = 0.0; amrex::Real Dyz = 0.0; - amrex::Real bcforcing_x=0; - amrex::Real bcforcing_y=0; + amrex::Real bcforcing_x = 0; + amrex::Real bcforcing_y = 0; const amrex::Real ux1 = vel(i, j, k, 0); const amrex::Real uy1 = vel(i, j, k, 1); const amrex::Real uz1 = vel(i, j, k, 2); const amrex::Real m = std::sqrt(ux1 * ux1 + uy1 * uy1 + uz1 * uz1); - if (drag(i,j,k) == 1 && (! is_laminar)) { + if (drag(i, j, k) == 1 && (!is_laminar)) { const amrex::Real ux2 = vel(i, j, k + 1, 0); const amrex::Real uy2 = vel(i, j, k + 1, 1); const amrex::Real m2 = std::sqrt(ux2 * ux2 + uy2 * uy2); const amrex::Real kappa = 0.41; const amrex::Real z0 = std::max(terrainz0(i, j, k), 1e-4); - const amrex::Real ustar = m2 * kappa / - std::log(1.5*dx[2] / z0); - const amrex::Real uTarget= ustar/kappa*std::log(0.5*dx[2]/z0); - const amrex::Real uxTarget = uTarget * ux2 / - (1e-5 + std::sqrt(ux2 * ux2 + uy2 * uy2)); - const amrex::Real uyTarget = uTarget * uy2 / - (1e-5 + std::sqrt(ux2 * ux2 + uy2 * uy2)); - bcforcing_x=-(uxTarget-ux1)/dt; - bcforcing_y=-(uyTarget-uy1)/dt; - Dxz = -ustar*ustar* ux1 / + const amrex::Real ustar = m2 * kappa / std::log(1.5 * dx[2] / z0); + const amrex::Real uTarget = + ustar / kappa * std::log(0.5 * dx[2] / z0); + const amrex::Real uxTarget = + uTarget * ux2 / (1e-5 + std::sqrt(ux2 * ux2 + uy2 * uy2)); + const amrex::Real uyTarget = + uTarget * uy2 / (1e-5 + std::sqrt(ux2 * ux2 + uy2 * uy2)); + bcforcing_x = -(uxTarget - ux1) / dt; + bcforcing_y = -(uyTarget - uy1) / dt; + Dxz = -ustar * ustar * ux1 / (1e-5 + std::sqrt(ux1 * ux1 + uy1 * uy1)) / dx[2]; Dyz = -ustar * ustar * uy1 / (1e-5 + std::sqrt(ux1 * ux1 + uy1 * uy1)) / dx[2]; } - const amrex::Real CdM = std::min(Cd / (m + 1e-5), 1000.0/scale_factor); + const amrex::Real CdM = + std::min(Cd / (m + 1e-5), 1000.0 / scale_factor); src_term(i, j, k, 0) -= - (CdM * m * ux1 * blank(i, j, k) + Dxz * drag(i, j, k) + bcforcing_x * drag(i,j,k) + - (xstart_damping + xend_damping+ ystart_damping+yend_damping) * (ux1 - sponge_density * spongeVelX)); + (CdM * m * ux1 * blank(i, j, k) + Dxz * drag(i, j, k) + + bcforcing_x * drag(i, j, k) + + (xstart_damping + xend_damping + ystart_damping + yend_damping) * + (ux1 - sponge_density * spongeVelX)); src_term(i, j, k, 1) -= - (CdM * m * uy1 * blank(i, j, k) + Dyz * drag(i, j, k) + bcforcing_y * drag(i,j,k) + - (xstart_damping + xend_damping+ ystart_damping+yend_damping) * (uy1 - sponge_density * spongeVelY)); + (CdM * m * uy1 * blank(i, j, k) + Dyz * drag(i, j, k) + + bcforcing_y * drag(i, j, k) + + (xstart_damping + xend_damping + ystart_damping + yend_damping) * + (uy1 - sponge_density * spongeVelY)); src_term(i, j, k, 2) -= (CdM * m * uz1 * blank(i, j, k) + - (xstart_damping + xend_damping+ ystart_damping+yend_damping) * (uz1 - sponge_density * spongeVelZ)); + (xstart_damping + xend_damping + ystart_damping + yend_damping) * + (uz1 - sponge_density * spongeVelZ)); }); } diff --git a/amr-wind/equation_systems/temperature/source_terms/DragTempForcing.H b/amr-wind/equation_systems/temperature/source_terms/DragTempForcing.H index 085d4675f4..4cc232b31d 100644 --- a/amr-wind/equation_systems/temperature/source_terms/DragTempForcing.H +++ b/amr-wind/equation_systems/temperature/source_terms/DragTempForcing.H @@ -33,7 +33,7 @@ public: private: const CFDSim& m_sim; const amrex::AmrCore& m_mesh; - const Field& m_velocity; + const Field& m_velocity; const Field& m_temperature; amrex::Real m_drag{1.0}; amrex::Real m_internalRefT{300.0}; diff --git a/amr-wind/equation_systems/temperature/source_terms/DragTempForcing.cpp b/amr-wind/equation_systems/temperature/source_terms/DragTempForcing.cpp index 2e068ab8ed..a45d70f244 100644 --- a/amr-wind/equation_systems/temperature/source_terms/DragTempForcing.cpp +++ b/amr-wind/equation_systems/temperature/source_terms/DragTempForcing.cpp @@ -28,27 +28,31 @@ void DragTempForcing::operator()( const FieldState fstate, const amrex::Array4& src_term) const { - const auto& vel = - m_velocity.state(field_impl::dof_state(fstate))(lev).const_array(mfi); - const auto& temperature = m_temperature.state(field_impl::dof_state(fstate))(lev).const_array(mfi); - const bool is_terrain = this->m_sim.repo().int_field_exists("terrain_blank"); + const auto& vel = + m_velocity.state(field_impl::dof_state(fstate))(lev).const_array(mfi); + const auto& temperature = + m_temperature.state(field_impl::dof_state(fstate))(lev).const_array( + mfi); + const bool is_terrain = + this->m_sim.repo().int_field_exists("terrain_blank"); if (!is_terrain) { amrex::Abort("Need terrain blanking variable to use this source term"); } - auto* const m_terrain_blank = &this->m_sim.repo().get_int_field("terrain_blank"); + auto* const m_terrain_blank = + &this->m_sim.repo().get_int_field("terrain_blank"); const auto& blank = (*m_terrain_blank)(lev).const_array(mfi); const auto& geom = m_mesh.Geom(lev); const auto& dx = geom.CellSizeArray(); - const amrex::Real gpu_drag = m_drag/dx[2]; + const amrex::Real gpu_drag = m_drag / dx[2]; const amrex::Real gpu_TRef = m_internalRefT; amrex::ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept { - const amrex::Real ux1 = vel(i, j, k, 0); - const amrex::Real uy1 = vel(i, j, k, 1); - const amrex::Real uz1 = vel(i, j, k, 2); - const amrex::Real m = std::sqrt(ux1 * ux1 + uy1 * uy1 + uz1 * uz1); - const amrex::Real Cd = std::min(gpu_drag/(m+1e-5),10/dx[2]); - src_term(i, j, k, 0) -= - (Cd * (temperature(i, j, k, 0) - gpu_TRef) * blank(i,j,k,0)); + const amrex::Real ux1 = vel(i, j, k, 0); + const amrex::Real uy1 = vel(i, j, k, 1); + const amrex::Real uz1 = vel(i, j, k, 2); + const amrex::Real m = std::sqrt(ux1 * ux1 + uy1 * uy1 + uz1 * uz1); + const amrex::Real Cd = std::min(gpu_drag / (m + 1e-5), 10 / dx[2]); + src_term(i, j, k, 0) -= + (Cd * (temperature(i, j, k, 0) - gpu_TRef) * blank(i, j, k, 0)); }); } diff --git a/amr-wind/physics/TerrainDrag.H b/amr-wind/physics/TerrainDrag.H index 874ea97052..a5e9c2dad6 100644 --- a/amr-wind/physics/TerrainDrag.H +++ b/amr-wind/physics/TerrainDrag.H @@ -53,7 +53,7 @@ private: amrex::Vector m_zterrain; // Roughness Field Field& m_terrainz0; - Field& m_terrain_height; + Field& m_terrain_height; // Reading the Roughness Coordinates from file - Not Fully there yet // Need updates to ABLWallFunction in future amrex::Vector m_xrough; diff --git a/amr-wind/physics/TerrainDrag.cpp b/amr-wind/physics/TerrainDrag.cpp index 660b0ab8aa..8cb0a8e7d5 100644 --- a/amr-wind/physics/TerrainDrag.cpp +++ b/amr-wind/physics/TerrainDrag.cpp @@ -16,8 +16,8 @@ TerrainDrag::TerrainDrag(CFDSim& sim) , m_repo(sim.repo()) , m_mesh(sim.mesh()) , m_velocity(sim.repo().get_field("velocity")) - , m_terrain_blank(sim.repo().declare_int_field("terrain_blank", 1,1,1)) - , m_terrain_drag(sim.repo().declare_int_field("terrain_drag", 1,1,1)) + , m_terrain_blank(sim.repo().declare_int_field("terrain_blank", 1, 1, 1)) + , m_terrain_drag(sim.repo().declare_int_field("terrain_drag", 1, 1, 1)) , m_terrainz0(sim.repo().declare_field("terrainz0", 1, 1, 1)) , m_terrain_height(sim.repo().declare_field("terrain_height", 1, 1, 1)) { @@ -60,7 +60,7 @@ void TerrainDrag::post_init_actions() auto& velocity = m_velocity(level); auto& blanking = m_terrain_blank(level); auto& terrainz0 = m_terrainz0(level); - auto& terrain_height=m_terrain_height(level); + auto& terrain_height = m_terrain_height(level); auto& drag = m_terrain_drag(level); // copy terrain data to gpu amrex::Gpu::DeviceVector device_xterrain( @@ -102,7 +102,7 @@ void TerrainDrag::post_init_actions() auto levelBlanking = blanking.array(mfi); auto levelDrag = drag.array(mfi); auto levelz0 = terrainz0.array(mfi); - auto levelheight=terrain_height.array(mfi); + auto levelheight = terrain_height.array(mfi); const unsigned terrainSize = m_xterrain.size(); const unsigned roughnessSize = m_xrough.size(); amrex::ParallelFor( @@ -122,11 +122,12 @@ void TerrainDrag::post_init_actions() residual = radius; terrainHt = zterrain_ptr[ii]; } - } + } levelBlanking(i, j, k, 0) = static_cast(z <= terrainHt); - levelheight(i,j,k,0)=std::max(std::abs(z-terrainHt),0.5*dx[2]); - residual = 10000; + levelheight(i, j, k, 0) = + std::max(std::abs(z - terrainHt), 0.5 * dx[2]); + residual = 10000; amrex::Real roughz0 = 0.1; for (unsigned ii = 0; ii < roughnessSize; ++ii) { const amrex::Real radius = std::sqrt( @@ -141,7 +142,7 @@ void TerrainDrag::post_init_actions() } } levelz0(i, j, k, 0) = roughz0; - }); + }); amrex::ParallelFor( vbx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept { // Terrain Height @@ -165,7 +166,7 @@ void TerrainDrag::post_init_actions() levelDrag(i, j, k, 0) = 1; } }); - } + } } } From f9b249fcd8df9a15b8206ae433ca0b0322b08db9 Mon Sep 17 00:00:00 2001 From: hgopalan Date: Mon, 26 Aug 2024 07:47:44 -0600 Subject: [PATCH 70/77] Adjusing the formatting for unit test --- amr-wind/physics/TerrainDrag.H | 2 +- amr-wind/physics/TerrainDrag.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/amr-wind/physics/TerrainDrag.H b/amr-wind/physics/TerrainDrag.H index a5e9c2dad6..0ffc8627e5 100644 --- a/amr-wind/physics/TerrainDrag.H +++ b/amr-wind/physics/TerrainDrag.H @@ -36,7 +36,7 @@ public: void post_advance_work() override {} - int returnBlankValue(int i, int j, int k); + int return_blank_value(int i, int j, int k); private: CFDSim& m_sim; diff --git a/amr-wind/physics/TerrainDrag.cpp b/amr-wind/physics/TerrainDrag.cpp index 8cb0a8e7d5..e651dc5ce8 100644 --- a/amr-wind/physics/TerrainDrag.cpp +++ b/amr-wind/physics/TerrainDrag.cpp @@ -175,7 +175,7 @@ void TerrainDrag::pre_init_actions() BL_PROFILE("amr-wind::" + this->identifier() + "::pre_init_actions"); } -int TerrainDrag::returnBlankValue(int i, int j, int k) +int TerrainDrag::return_blank_value(int i, int j, int k) { int lev = 0; amrex::MFIter mfi(m_terrain_blank(lev)); From 61630e2158601e35a791863b22214c2898b909cb Mon Sep 17 00:00:00 2001 From: hgopalan Date: Tue, 8 Oct 2024 12:26:52 -0400 Subject: [PATCH 71/77] Some code clean up for readability. --- .../icns/source_terms/DragForcing.cpp | 20 ++++++++++--------- .../source_terms/DragTempForcing.cpp | 4 +++- unit_tests/wind_energy/test_abl_terrain.cpp | 8 ++++---- 3 files changed, 18 insertions(+), 14 deletions(-) diff --git a/amr-wind/equation_systems/icns/source_terms/DragForcing.cpp b/amr-wind/equation_systems/icns/source_terms/DragForcing.cpp index ac25a676cd..c9ed3d528e 100644 --- a/amr-wind/equation_systems/icns/source_terms/DragForcing.cpp +++ b/amr-wind/equation_systems/icns/source_terms/DragForcing.cpp @@ -29,8 +29,7 @@ DragForcing::DragForcing(const CFDSim& sim) const auto& phy_mgr = m_sim.physics_manager(); if (phy_mgr.contains("ABL")) { const auto& abl = m_sim.physics_manager().get(); - const VelPlaneAveraging& fa_velocity = - abl.abl_statistics().vel_profile_coarse(); + const auto& fa_velocity = abl.abl_statistics().vel_profile_coarse(); m_device_vel_ht.resize(fa_velocity.line_centroids().size()); m_device_vel_vals.resize(fa_velocity.line_average().size()); amrex::Gpu::copy( @@ -92,6 +91,10 @@ void DragForcing::operator()( const amrex::Real scale_factor = (dx[2] < 1.0) ? 1.0 : 1.0 / dx[2]; const amrex::Real Cd = (is_laminar && dx[2] < 1) ? dragCoefficient : dragCoefficient / dx[2]; + const int z0_min = 1e-4; + const auto tiny = std::numeric_limits::epsilon(); + const amrex::Real kappa = 0.41; + const amrex::Real cd_max = 1000.0; amrex::ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept { const amrex::Real x = prob_lo[0] + (i + 0.5) * dx[0]; const amrex::Real y = prob_lo[1] + (j + 0.5) * dx[1]; @@ -141,24 +144,23 @@ void DragForcing::operator()( const amrex::Real ux2 = vel(i, j, k + 1, 0); const amrex::Real uy2 = vel(i, j, k + 1, 1); const amrex::Real m2 = std::sqrt(ux2 * ux2 + uy2 * uy2); - const amrex::Real kappa = 0.41; - const amrex::Real z0 = std::max(terrainz0(i, j, k), 1e-4); + const amrex::Real z0 = std::max(terrainz0(i, j, k), z0_min); const amrex::Real ustar = m2 * kappa / std::log(1.5 * dx[2] / z0); const amrex::Real uTarget = ustar / kappa * std::log(0.5 * dx[2] / z0); const amrex::Real uxTarget = - uTarget * ux2 / (1e-5 + std::sqrt(ux2 * ux2 + uy2 * uy2)); + uTarget * ux2 / (tiny + std::sqrt(ux2 * ux2 + uy2 * uy2)); const amrex::Real uyTarget = - uTarget * uy2 / (1e-5 + std::sqrt(ux2 * ux2 + uy2 * uy2)); + uTarget * uy2 / (tiny + std::sqrt(ux2 * ux2 + uy2 * uy2)); bcforcing_x = -(uxTarget - ux1) / dt; bcforcing_y = -(uyTarget - uy1) / dt; Dxz = -ustar * ustar * ux1 / - (1e-5 + std::sqrt(ux1 * ux1 + uy1 * uy1)) / dx[2]; + (tiny + std::sqrt(ux1 * ux1 + uy1 * uy1)) / dx[2]; Dyz = -ustar * ustar * uy1 / - (1e-5 + std::sqrt(ux1 * ux1 + uy1 * uy1)) / dx[2]; + (tiny + std::sqrt(ux1 * ux1 + uy1 * uy1)) / dx[2]; } const amrex::Real CdM = - std::min(Cd / (m + 1e-5), 1000.0 / scale_factor); + std::min(Cd / (m + tiny), cd_max / scale_factor); src_term(i, j, k, 0) -= (CdM * m * ux1 * blank(i, j, k) + Dxz * drag(i, j, k) + bcforcing_x * drag(i, j, k) + diff --git a/amr-wind/equation_systems/temperature/source_terms/DragTempForcing.cpp b/amr-wind/equation_systems/temperature/source_terms/DragTempForcing.cpp index a45d70f244..56ad0b8441 100644 --- a/amr-wind/equation_systems/temperature/source_terms/DragTempForcing.cpp +++ b/amr-wind/equation_systems/temperature/source_terms/DragTempForcing.cpp @@ -45,12 +45,14 @@ void DragTempForcing::operator()( const auto& dx = geom.CellSizeArray(); const amrex::Real gpu_drag = m_drag / dx[2]; const amrex::Real gpu_TRef = m_internalRefT; + const auto tiny = std::numeric_limits::epsilon(); + const amrex::Real cd_max = 10.0; amrex::ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept { const amrex::Real ux1 = vel(i, j, k, 0); const amrex::Real uy1 = vel(i, j, k, 1); const amrex::Real uz1 = vel(i, j, k, 2); const amrex::Real m = std::sqrt(ux1 * ux1 + uy1 * uy1 + uz1 * uz1); - const amrex::Real Cd = std::min(gpu_drag / (m + 1e-5), 10 / dx[2]); + const amrex::Real Cd = std::min(gpu_drag / (m + tiny), cd_max / dx[2]); src_term(i, j, k, 0) -= (Cd * (temperature(i, j, k, 0) - gpu_TRef) * blank(i, j, k, 0)); }); diff --git a/unit_tests/wind_energy/test_abl_terrain.cpp b/unit_tests/wind_energy/test_abl_terrain.cpp index 3032c4a6d7..296593339a 100644 --- a/unit_tests/wind_energy/test_abl_terrain.cpp +++ b/unit_tests/wind_energy/test_abl_terrain.cpp @@ -27,7 +27,7 @@ void write_terrain(const std::string& fname) namespace amr_wind_tests { // Testing the terrain drag reading to ensure that terrain is properly setup -class terraintest : public MeshTest +class TerrainTest : public MeshTest { protected: void populate_parameters() override @@ -47,14 +47,14 @@ class terraintest : public MeshTest pp.addarr("prob_hi", probhi); } } - std::string terrainfname = "terrain.amrwind"; + std::string terrain_fname = "terrain.amrwind"; }; TEST_F(terraintest, terrain) { constexpr amrex::Real tol = 0; // Write target wind file - write_terrain(terrainfname); + write_terrain(terrain_fname); populate_parameters(); initialize_mesh(); auto& pde_mgr = sim().pde_manager(); @@ -65,7 +65,7 @@ TEST_F(terraintest, terrain) pp.addarr("physics", physics); amr_wind::terraindrag::TerrainDrag terrain_drag(sim()); terrain_drag.post_init_actions(); - int value = 100; + const int value = 100; // Outside Point value = terrain_drag.return_blank_value(5, 5, 1); EXPECT_EQ(value, tol); From c8fc54aa85ad07c811492fc305c2a4e1c81c532f Mon Sep 17 00:00:00 2001 From: hgopalan Date: Tue, 8 Oct 2024 12:34:44 -0400 Subject: [PATCH 72/77] Updated comments for Doxygen style. Changing int to float for z0_min. --- .../icns/source_terms/DragForcing.cpp | 2 +- amr-wind/physics/TerrainDrag.H | 12 ++++++------ amr-wind/physics/TerrainDrag.cpp | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/amr-wind/equation_systems/icns/source_terms/DragForcing.cpp b/amr-wind/equation_systems/icns/source_terms/DragForcing.cpp index c9ed3d528e..69036ed179 100644 --- a/amr-wind/equation_systems/icns/source_terms/DragForcing.cpp +++ b/amr-wind/equation_systems/icns/source_terms/DragForcing.cpp @@ -91,7 +91,7 @@ void DragForcing::operator()( const amrex::Real scale_factor = (dx[2] < 1.0) ? 1.0 : 1.0 / dx[2]; const amrex::Real Cd = (is_laminar && dx[2] < 1) ? dragCoefficient : dragCoefficient / dx[2]; - const int z0_min = 1e-4; + const amrex::Real z0_min = 1e-4; const auto tiny = std::numeric_limits::epsilon(); const amrex::Real kappa = 0.41; const amrex::Real cd_max = 1000.0; diff --git a/amr-wind/physics/TerrainDrag.H b/amr-wind/physics/TerrainDrag.H index 0ffc8627e5..e95a736126 100644 --- a/amr-wind/physics/TerrainDrag.H +++ b/amr-wind/physics/TerrainDrag.H @@ -43,19 +43,19 @@ private: const FieldRepo& m_repo; const amrex::AmrCore& m_mesh; Field& m_velocity; - // Blanking Field for Terrain or Buildings + //! Blanking Field for Terrain or Buildings IntField& m_terrain_blank; - // Terrain Drag Force Term + //! Terrain Drag Force Term IntField& m_terrain_drag; - // Reading the Terrain Coordinates from file + //! Reading the Terrain Coordinates from file amrex::Vector m_xterrain; amrex::Vector m_yterrain; amrex::Vector m_zterrain; - // Roughness Field + //! Roughness Field Field& m_terrainz0; Field& m_terrain_height; - // Reading the Roughness Coordinates from file - Not Fully there yet - // Need updates to ABLWallFunction in future + //! Reading the Roughness Coordinates from file - Not Fully there yet + //! Need updates to ABLWallFunction in future amrex::Vector m_xrough; amrex::Vector m_yrough; amrex::Vector m_z0rough; diff --git a/amr-wind/physics/TerrainDrag.cpp b/amr-wind/physics/TerrainDrag.cpp index e651dc5ce8..26ebf71035 100644 --- a/amr-wind/physics/TerrainDrag.cpp +++ b/amr-wind/physics/TerrainDrag.cpp @@ -24,7 +24,7 @@ TerrainDrag::TerrainDrag(CFDSim& sim) std::string terrainfile("terrain.amrwind"); std::ifstream file(terrainfile, std::ios::in); if (!file.good()) { - amrex::Abort("Cannot find terrain.amrwind file"); + amrex::Abort("Cannot find terrain.amrwind file"); } amrex::Real value1, value2, value3; while (file >> value1 >> value2 >> value3) { From cd583e6828dcae14cc69afa56797c7e9406bfeba Mon Sep 17 00:00:00 2001 From: hgopalan Date: Tue, 8 Oct 2024 12:47:14 -0400 Subject: [PATCH 73/77] Cosmetic changes and fixes for unit test error. --- .../icns/source_terms/DragForcing.H | 2 +- .../icns/source_terms/DragForcing.cpp | 20 +++++++++---------- .../source_terms/DragTempForcing.H | 4 ++-- .../source_terms/DragTempForcing.cpp | 10 +++++----- unit_tests/wind_energy/test_abl_terrain.cpp | 4 ++-- 5 files changed, 20 insertions(+), 20 deletions(-) diff --git a/amr-wind/equation_systems/icns/source_terms/DragForcing.H b/amr-wind/equation_systems/icns/source_terms/DragForcing.H index 67ec12b5b1..283ccd7bdc 100644 --- a/amr-wind/equation_systems/icns/source_terms/DragForcing.H +++ b/amr-wind/equation_systems/icns/source_terms/DragForcing.H @@ -36,7 +36,7 @@ private: const Field& m_velocity; amrex::Gpu::DeviceVector m_device_vel_ht; amrex::Gpu::DeviceVector m_device_vel_vals; - amrex::Real m_drag{10.0}; + amrex::Real m_drag_coefficient{10.0}; amrex::Real m_sponge_strength{1.0}; amrex::Real m_sponge_density{1.0}; amrex::Real m_sponge_distance_west{-1000}; diff --git a/amr-wind/equation_systems/icns/source_terms/DragForcing.cpp b/amr-wind/equation_systems/icns/source_terms/DragForcing.cpp index 69036ed179..36655d04ec 100644 --- a/amr-wind/equation_systems/icns/source_terms/DragForcing.cpp +++ b/amr-wind/equation_systems/icns/source_terms/DragForcing.cpp @@ -14,7 +14,7 @@ DragForcing::DragForcing(const CFDSim& sim) , m_velocity(sim.repo().get_field("velocity")) { amrex::ParmParse pp("DragForcing"); - pp.query("drag_coefficient", m_drag); + pp.query("drag_coefficient", m_drag_coefficient); pp.query("sponge_strength", m_sponge_strength); pp.query("sponge_density", m_sponge_density); pp.query("sponge_distance_west", m_sponge_distance_west); @@ -71,7 +71,7 @@ void DragForcing::operator()( const auto& dx = geom.CellSizeArray(); const auto& prob_lo = geom.ProbLoArray(); const auto& prob_hi = geom.ProbHiArray(); - const amrex::Real dragCoefficient = m_drag; + const amrex::Real drag_coefficient = m_drag_coefficient; const amrex::Real sponge_strength = m_sponge_strength; const amrex::Real sponge_density = m_sponge_density; const amrex::Real start_east = prob_hi[0] - m_sponge_distance_east; @@ -87,10 +87,10 @@ void DragForcing::operator()( const auto* device_vel_vals = m_device_vel_vals.data(); const unsigned vsize = m_device_vel_ht.size(); const auto& dt = m_time.delta_t(); - bool is_laminar = m_is_laminar; + const bool is_laminar = m_is_laminar; const amrex::Real scale_factor = (dx[2] < 1.0) ? 1.0 : 1.0 / dx[2]; const amrex::Real Cd = - (is_laminar && dx[2] < 1) ? dragCoefficient : dragCoefficient / dx[2]; + (is_laminar && dx[2] < 1) ? drag_coefficient : drag_coefficient / dx[2]; const amrex::Real z0_min = 1e-4; const auto tiny = std::numeric_limits::epsilon(); const amrex::Real kappa = 0.41; @@ -134,8 +134,8 @@ void DragForcing::operator()( } amrex::Real Dxz = 0.0; amrex::Real Dyz = 0.0; - amrex::Real bcforcing_x = 0; - amrex::Real bcforcing_y = 0; + amrex::Real bc_forcing_x = 0; + amrex::Real bc_forcing_y = 0; const amrex::Real ux1 = vel(i, j, k, 0); const amrex::Real uy1 = vel(i, j, k, 1); const amrex::Real uz1 = vel(i, j, k, 2); @@ -152,8 +152,8 @@ void DragForcing::operator()( uTarget * ux2 / (tiny + std::sqrt(ux2 * ux2 + uy2 * uy2)); const amrex::Real uyTarget = uTarget * uy2 / (tiny + std::sqrt(ux2 * ux2 + uy2 * uy2)); - bcforcing_x = -(uxTarget - ux1) / dt; - bcforcing_y = -(uyTarget - uy1) / dt; + bc_forcing_x = -(uxTarget - ux1) / dt; + bc_forcing_y = -(uyTarget - uy1) / dt; Dxz = -ustar * ustar * ux1 / (tiny + std::sqrt(ux1 * ux1 + uy1 * uy1)) / dx[2]; Dyz = -ustar * ustar * uy1 / @@ -163,12 +163,12 @@ void DragForcing::operator()( std::min(Cd / (m + tiny), cd_max / scale_factor); src_term(i, j, k, 0) -= (CdM * m * ux1 * blank(i, j, k) + Dxz * drag(i, j, k) + - bcforcing_x * drag(i, j, k) + + bc_forcing_x * drag(i, j, k) + (xstart_damping + xend_damping + ystart_damping + yend_damping) * (ux1 - sponge_density * spongeVelX)); src_term(i, j, k, 1) -= (CdM * m * uy1 * blank(i, j, k) + Dyz * drag(i, j, k) + - bcforcing_y * drag(i, j, k) + + bc_forcing_y * drag(i, j, k) + (xstart_damping + xend_damping + ystart_damping + yend_damping) * (uy1 - sponge_density * spongeVelY)); src_term(i, j, k, 2) -= diff --git a/amr-wind/equation_systems/temperature/source_terms/DragTempForcing.H b/amr-wind/equation_systems/temperature/source_terms/DragTempForcing.H index 4cc232b31d..28dac339bc 100644 --- a/amr-wind/equation_systems/temperature/source_terms/DragTempForcing.H +++ b/amr-wind/equation_systems/temperature/source_terms/DragTempForcing.H @@ -35,8 +35,8 @@ private: const amrex::AmrCore& m_mesh; const Field& m_velocity; const Field& m_temperature; - amrex::Real m_drag{1.0}; - amrex::Real m_internalRefT{300.0}; + amrex::Real m_drag_coefficient{1.0}; + amrex::Real m_reference_temperature{300.0}; }; } // namespace amr_wind::pde::temperature diff --git a/amr-wind/equation_systems/temperature/source_terms/DragTempForcing.cpp b/amr-wind/equation_systems/temperature/source_terms/DragTempForcing.cpp index 56ad0b8441..2e7a259973 100644 --- a/amr-wind/equation_systems/temperature/source_terms/DragTempForcing.cpp +++ b/amr-wind/equation_systems/temperature/source_terms/DragTempForcing.cpp @@ -15,7 +15,7 @@ DragTempForcing::DragTempForcing(const CFDSim& sim) , m_temperature(sim.repo().get_field("temperature")) { amrex::ParmParse pp("DragTempForcing"); - pp.query("dragCoefficient", m_drag); + pp.query("dragCoefficient", m_drag_coefficient); pp.query("RefT", m_internalRefT); } @@ -43,8 +43,8 @@ void DragTempForcing::operator()( const auto& blank = (*m_terrain_blank)(lev).const_array(mfi); const auto& geom = m_mesh.Geom(lev); const auto& dx = geom.CellSizeArray(); - const amrex::Real gpu_drag = m_drag / dx[2]; - const amrex::Real gpu_TRef = m_internalRefT; + const amrex::Real drag_coefficient = m_drag_coefficient / dx[2]; + const amrex::Real reference_temperature = m_reference_temperature; const auto tiny = std::numeric_limits::epsilon(); const amrex::Real cd_max = 10.0; amrex::ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept { @@ -52,9 +52,9 @@ void DragTempForcing::operator()( const amrex::Real uy1 = vel(i, j, k, 1); const amrex::Real uz1 = vel(i, j, k, 2); const amrex::Real m = std::sqrt(ux1 * ux1 + uy1 * uy1 + uz1 * uz1); - const amrex::Real Cd = std::min(gpu_drag / (m + tiny), cd_max / dx[2]); + const amrex::Real Cd = std::min(drag_coefficient / (m + tiny), cd_max / dx[2]); src_term(i, j, k, 0) -= - (Cd * (temperature(i, j, k, 0) - gpu_TRef) * blank(i, j, k, 0)); + (Cd * (temperature(i, j, k, 0) - reference_temperature) * blank(i, j, k, 0)); }); } diff --git a/unit_tests/wind_energy/test_abl_terrain.cpp b/unit_tests/wind_energy/test_abl_terrain.cpp index 296593339a..e09c1d2413 100644 --- a/unit_tests/wind_energy/test_abl_terrain.cpp +++ b/unit_tests/wind_energy/test_abl_terrain.cpp @@ -50,7 +50,7 @@ class TerrainTest : public MeshTest std::string terrain_fname = "terrain.amrwind"; }; -TEST_F(terraintest, terrain) +TEST_F(TerrainTest, terrain) { constexpr amrex::Real tol = 0; // Write target wind file @@ -65,7 +65,7 @@ TEST_F(terraintest, terrain) pp.addarr("physics", physics); amr_wind::terraindrag::TerrainDrag terrain_drag(sim()); terrain_drag.post_init_actions(); - const int value = 100; + int value = 100; // Outside Point value = terrain_drag.return_blank_value(5, 5, 1); EXPECT_EQ(value, tol); From 4c279fcc90c1e1b0a4d86bb0bca6c234bc97d1fc Mon Sep 17 00:00:00 2001 From: hgopalan Date: Tue, 8 Oct 2024 12:51:52 -0400 Subject: [PATCH 74/77] Clang formatting. --- .../temperature/source_terms/DragTempForcing.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/amr-wind/equation_systems/temperature/source_terms/DragTempForcing.cpp b/amr-wind/equation_systems/temperature/source_terms/DragTempForcing.cpp index 2e7a259973..d5b370ea64 100644 --- a/amr-wind/equation_systems/temperature/source_terms/DragTempForcing.cpp +++ b/amr-wind/equation_systems/temperature/source_terms/DragTempForcing.cpp @@ -52,9 +52,11 @@ void DragTempForcing::operator()( const amrex::Real uy1 = vel(i, j, k, 1); const amrex::Real uz1 = vel(i, j, k, 2); const amrex::Real m = std::sqrt(ux1 * ux1 + uy1 * uy1 + uz1 * uz1); - const amrex::Real Cd = std::min(drag_coefficient / (m + tiny), cd_max / dx[2]); + const amrex::Real Cd = + std::min(drag_coefficient / (m + tiny), cd_max / dx[2]); src_term(i, j, k, 0) -= - (Cd * (temperature(i, j, k, 0) - reference_temperature) * blank(i, j, k, 0)); + (Cd * (temperature(i, j, k, 0) - reference_temperature) * + blank(i, j, k, 0)); }); } From 119a1562d33ff030d97da47ab0eff46b7e6dee81 Mon Sep 17 00:00:00 2001 From: hgopalan Date: Tue, 8 Oct 2024 12:55:05 -0400 Subject: [PATCH 75/77] Silly error --- .../temperature/source_terms/DragTempForcing.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/amr-wind/equation_systems/temperature/source_terms/DragTempForcing.cpp b/amr-wind/equation_systems/temperature/source_terms/DragTempForcing.cpp index d5b370ea64..098e806cc0 100644 --- a/amr-wind/equation_systems/temperature/source_terms/DragTempForcing.cpp +++ b/amr-wind/equation_systems/temperature/source_terms/DragTempForcing.cpp @@ -15,8 +15,8 @@ DragTempForcing::DragTempForcing(const CFDSim& sim) , m_temperature(sim.repo().get_field("temperature")) { amrex::ParmParse pp("DragTempForcing"); - pp.query("dragCoefficient", m_drag_coefficient); - pp.query("RefT", m_internalRefT); + pp.query("drag_coefficient", m_drag_coefficient); + pp.query("reference_temperature", m_reference_temperature); } DragTempForcing::~DragTempForcing() = default; From 2161761a7474187819ee15d8db4fb29c0d81a39b Mon Sep 17 00:00:00 2001 From: hgopalan Date: Tue, 8 Oct 2024 14:07:51 -0400 Subject: [PATCH 76/77] Removing group causing warning message. --- .../equation_systems/temperature/source_terms/DragTempForcing.H | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/amr-wind/equation_systems/temperature/source_terms/DragTempForcing.H b/amr-wind/equation_systems/temperature/source_terms/DragTempForcing.H index 28dac339bc..b8367f1331 100644 --- a/amr-wind/equation_systems/temperature/source_terms/DragTempForcing.H +++ b/amr-wind/equation_systems/temperature/source_terms/DragTempForcing.H @@ -10,7 +10,7 @@ namespace amr_wind::pde::temperature { /** Adding the source term to energy equation to account for immersed * boundary. * - * \ingroup temperature_src + * * * */ From 42d211c3255bf743b8cb599d78438b801b19fc76 Mon Sep 17 00:00:00 2001 From: hgopalan Date: Tue, 8 Oct 2024 14:10:43 -0400 Subject: [PATCH 77/77] Comments removed --- .../temperature/source_terms/DragTempForcing.H | 7 ------- 1 file changed, 7 deletions(-) diff --git a/amr-wind/equation_systems/temperature/source_terms/DragTempForcing.H b/amr-wind/equation_systems/temperature/source_terms/DragTempForcing.H index b8367f1331..8c504d0ffb 100644 --- a/amr-wind/equation_systems/temperature/source_terms/DragTempForcing.H +++ b/amr-wind/equation_systems/temperature/source_terms/DragTempForcing.H @@ -7,13 +7,6 @@ namespace amr_wind::pde::temperature { -/** Adding the source term to energy equation to account for immersed - * boundary. - * - * - * - * - */ class DragTempForcing : public TemperatureSource::Register { public: