|
ERF
Energy Research and Forecasting: An Atmospheric Modeling Code
|
#include <ERF_IBFaceSet.H>

Classes | |
| struct | SunState |
| Sun and irradiances of the last compute_shortwave() call, for reports. More... | |
| struct | TwoStreamSun |
| The two-stream sun of the next compute_shortwave() (sun_mode = two_stream). More... | |
Public Member Functions | |
| IBFaceSet (const IBSEBParams ¶ms, int lev, int qv_comp=-1) | |
| void | build (const amrex::MultiFab &blanking, const amrex::Geometry &geom) |
| void | add_outside_occluders (const std::vector< const IBFaceSet * > &below) |
| void | set_two_stream_sun (amrex::Real declination, amrex::Real hour_angle, amrex::Real latitude_deg, amrex::Real toa_irradiance) |
| void | map_buildings_to_level0 (const IBFaceSet &coarser, const amrex::IntVect &ratio) |
| int | building_level0 (int b) const |
| void | release_labels () |
| ibseb::RayMap | ray_map () const |
| amrex::IntVect | ray_halo () const |
| bool | ray_map_spans_domain () const |
| int | n_faces () const |
| int | n_buildings () const |
| int | n_layers () const |
| void | compute_view_fractions () |
| void | compute_longwave (const amrex::MultiFab &cons, const TwoStreamCanopyView &canopy=TwoStreamCanopyView{}) |
| void | assign_materials () |
| void | compute_ground (amrex::Real dt) |
| void | solve_balance (amrex::Real dt) |
| void | compute_sensible (const amrex::MultiFab &cons, const amrex::MultiFab &xvel, const amrex::MultiFab &yvel, const amrex::MultiFab &zvel, amrex::Real c_p, const amrex::MultiFab *olen_ground=nullptr, const amrex::MultiFab *pblh_ground=nullptr, amrex::Real z_i_bulk=0.0) |
| void | add_heat_flux_to_source (amrex::MultiFab &source, const amrex::MultiFab &cons, const amrex::Geometry &geom, amrex::Real c_p, amrex::Real rdOcp) const |
| void | compute_shortwave (amrex::Real time, const TwoStreamCanopyView &canopy=TwoStreamCanopyView{}) |
| int | top_sample_interface () const |
| bool | has_faces () const |
| void | check_canopy_layout (const amrex::MultiFab &cons, const TwoStreamCanopyView &canopy) const |
| void | compute_shortwave_two_stream (const TwoStreamCanopyView &canopy) |
| void | compute_longwave_two_stream (const amrex::MultiFab &cons, const TwoStreamCanopyView &canopy) |
| void | scatter_field (const amrex::Gpu::DeviceVector< amrex::Real > &v, amrex::MultiFab &out) const |
| void | dump_faces (const std::string &prefix) const |
| void | scatter_diagnostics (amrex::MultiFab &nfaces, amrex::MultiFab &tskin) const |
| void | write_state (const std::string &file) const |
| void | read_state (const std::string &file) |
| void | report (amrex::Real time, int step, bool write_csv) const |
| const SunState & | sun () const |
| void | print_debug_summary () const |
| void | add_cost (double seconds) |
| void | set_init_cost (double seconds) |
| const std::vector< int > & | fab_start () const |
| void | build_ray_map (const std::vector< const IBFaceSet * > &below) |
Public Attributes | |
| amrex::Gpu::DeviceVector< int > | d_i |
| amrex::Gpu::DeviceVector< int > | d_j |
| amrex::Gpu::DeviceVector< int > | d_k |
| Fluid cell of the face. More... | |
| amrex::Gpu::DeviceVector< int > | d_dir |
| Face direction: 0 x, 1 y, 2 z. More... | |
| amrex::Gpu::DeviceVector< int > | d_side |
| Solid neighbour at -1 (low) or +1 (high) side. More... | |
| amrex::Gpu::DeviceVector< int > | d_bid |
| Building id (1-based) More... | |
| amrex::Gpu::DeviceVector< int > | d_mat |
| Material id (0 = uniform inputs) More... | |
| amrex::Gpu::DeviceVector< amrex::Real > | d_albedo |
| amrex::Gpu::DeviceVector< amrex::Real > | d_emis |
| Optical properties of the face. More... | |
| amrex::Gpu::DeviceVector< amrex::Real > | d_kth |
| amrex::Gpu::DeviceVector< amrex::Real > | d_rhocp |
| amrex::Gpu::DeviceVector< amrex::Real > | d_thick |
| Slab conductivity [W/m/K], heat capacity [J/m3/K], thickness [m]. More... | |
| amrex::Gpu::DeviceVector< amrex::Real > | d_area |
| Face area [m2]. More... | |
| amrex::Gpu::DeviceVector< amrex::Real > | d_xf |
| amrex::Gpu::DeviceVector< amrex::Real > | d_yf |
| amrex::Gpu::DeviceVector< amrex::Real > | d_zf |
| Face centre [m]. More... | |
| amrex::Gpu::DeviceVector< amrex::Real > | d_T_skin |
| Skin temperature [K]. More... | |
| amrex::Gpu::DeviceVector< amrex::Real > | d_T_slab |
| Slab layers [K], face-major: [face * n_layers + layer]. More... | |
| amrex::Gpu::DeviceVector< amrex::Real > | d_f_sky |
| amrex::Gpu::DeviceVector< amrex::Real > | d_f_ground |
| amrex::Gpu::DeviceVector< amrex::Real > | d_f_bldg |
| View fractions, sum to 1. More... | |
| amrex::Gpu::DeviceVector< amrex::Real > | d_SW_abs |
| amrex::Gpu::DeviceVector< amrex::Real > | d_LW_net |
| amrex::Gpu::DeviceVector< amrex::Real > | d_H |
| amrex::Gpu::DeviceVector< amrex::Real > | d_LE |
| amrex::Gpu::DeviceVector< amrex::Real > | d_G |
| amrex::Gpu::DeviceVector< amrex::Real > | d_Q_ext |
| External incident flux [W/m2], e.g. fire radiation. More... | |
| amrex::Gpu::DeviceVector< amrex::Real > | d_shadow |
| 1 when the ray to the sun hits a building, else 0 More... | |
| amrex::Gpu::DeviceVector< amrex::Real > | d_SW_direct_in |
| Direct beam incident on the face. More... | |
| amrex::Gpu::DeviceVector< amrex::Real > | d_SW_diffuse_in |
| Sky and ground-reflected diffuse incident. More... | |
| amrex::Gpu::DeviceVector< amrex::Real > | d_LW_down_in |
| Incoming longwave on the face (sky, ground and walls) More... | |
| amrex::Gpu::DeviceVector< amrex::Real > | d_T_air |
| Air temperature of the fluid cell. More... | |
| amrex::Gpu::DeviceVector< amrex::Real > | d_theta_air |
| Potential temperature of the fluid cell [K]. More... | |
| amrex::Gpu::DeviceVector< amrex::Real > | d_rho |
| Density of the fluid cell [kg/m3]. More... | |
| amrex::Gpu::DeviceVector< amrex::Real > | d_U_tan |
| Tangential wind speed at the fluid cell [m/s]. More... | |
| amrex::Gpu::DeviceVector< amrex::Real > | d_ustar |
| Friction velocity of the wall function [m/s]. More... | |
| amrex::Gpu::DeviceVector< amrex::Real > | d_H_coeff |
| H = H_coeff (theta_skin - theta_air) [W/m2/K]. More... | |
| amrex::Gpu::DeviceVector< amrex::Real > | d_hbld |
| Height of the face's building column [m]. More... | |
| amrex::Gpu::DeviceVector< amrex::Real > | d_w_star |
| Convective velocity scale of the step [m/s]. More... | |
| amrex::Gpu::DeviceVector< amrex::Real > | d_olen |
| Obukhov length used [m] (1e30 when neutral) More... | |
| amrex::Gpu::DeviceVector< amrex::Real > | d_z_i |
| Depth in w* [m]: mixed layer above a roof, building height for a wall. More... | |
| amrex::Gpu::DeviceVector< amrex::Real > | d_LW_ext |
| Incoming longwave from sky and ground only [W/m2]. More... | |
| amrex::Gpu::DeviceVector< amrex::Real > | d_resid |
| |balance| after the solve [W/m2] More... | |
| amrex::Gpu::DeviceVector< int > | d_niter |
| Newton iterations of the last solve. More... | |
| amrex::iMultiFab | m_col_valid |
| amrex::iMultiFab | m_ray_patch |
| amrex::Box | m_patch_box |
| This rank's patch (empty without boxes) More... | |
| amrex::IntVect | m_halo {AMREX_D_DECL(0, 0, 0)} |
| Halo of the patch in cells. More... | |
| bool | m_wrap_x = false |
| bool | m_wrap_y = false |
| The patch spans the periodic domain in x / y. More... | |
| bool | m_map_spans_domain = false |
| Every rank's patch spans the domain. More... | |
| int | m_max_steps = 0 |
| Columns a walk is followed for: the halo's reach in x plus y, before the domain cap. More... | |
Private Member Functions | |
| void | warn_fixed_sun_below_floor () const |
Private Attributes | |
| IBSEBParams | m_params |
| Copy of the inputs. More... | |
| int | m_lev = 0 |
| AMR level, for reports. More... | |
| int | m_qv_comp = -1 |
| State component of rho qv, -1 without a moisture model. More... | |
| int | m_nface = 0 |
| Faces owned by this rank. More... | |
| int | m_top_sample = -1 |
| Highest interface a face samples, over all ranks (-1: no faces) More... | |
| int | m_nbld = 0 |
| Buildings of the level (global) More... | |
| std::vector< int > | m_fab_start |
| See fab_start() More... | |
| std::vector< amrex::Long > | m_bld_nface |
| Faces per building. More... | |
| std::vector< amrex::Real > | m_bld_area |
| Face area per building [m2]. More... | |
| amrex::Long | m_nface_dir [3] = {0, 0, 0} |
| Faces per direction. More... | |
| amrex::Real | m_area_total = 0.0 |
| Total face area [m2]. More... | |
| std::vector< amrex::Long > | m_bld_ncol |
| std::vector< int > | m_bld_ilo |
| std::vector< int > | m_bld_ihi |
| std::vector< int > | m_bld_jlo |
| std::vector< int > | m_bld_jhi |
| std::vector< int > | m_to_lev0 |
| amrex::iMultiFab | m_lab |
| amrex::Geometry | m_geom |
| Geometry of the level. More... | |
| int | m_nx = 0 |
| int | m_ny = 0 |
| int | m_nz = 0 |
| Cells of the domain in x, y and z. More... | |
| amrex::IntVect | m_dom_lo {AMREX_D_DECL(0, 0, 0)} |
| Low corner of the level's domain. More... | |
| amrex::Real | m_x_lo = 0.0 |
| amrex::Real | m_y_lo = 0.0 |
| Domain origin [m]. More... | |
| amrex::Real | m_dx [3] = {0.0, 0.0, 0.0} |
| Cell sizes [m]. More... | |
| bool | m_per_x = false |
| bool | m_per_y = false |
| Periodicity in x and y. More... | |
| amrex::Real | m_col_top_max = 0.0 |
| Tallest column the ray map holds [m] (the levels below included after add_outside_occluders()) More... | |
| amrex::Real | m_z_ground = 0.0 |
| Ground height [m] (flat, the domain bottom) More... | |
| SunState | m_sun |
| TwoStreamSun | m_ts_sun |
| double | m_cost_s = 0.0 |
| Wall-clock seconds spent in the per-step update on this rank. More... | |
| amrex::Long | m_cost_n = 0 |
| Number of per-step updates timed. More... | |
| double | m_init_cost_s = 0.0 |
| Wall-clock seconds of build() and compute_view_fractions() More... | |
|
inline |
Construct an empty face set for one level; build() fills it.
| params | Inputs of the balance (copied; the set never reads ParmParse). |
| lev | AMR level the set belongs to, for reports only. |
| qv_comp | State component of rho qv (SolverChoice::moisture_indices.qv), negative without a moisture model. The air temperature and the Exner function of a fluid cell take its vapour through the equation of state, as the rest of ERF does; with no moisture model they take none. |
|
inline |
Add the wall-clock time of one per-step update of this rank, for the cost line of report().
| void IBFaceSet::add_heat_flux_to_source | ( | amrex::MultiFab & | source, |
| const amrex::MultiFab & | cons, | ||
| const amrex::Geometry & | geom, | ||
| amrex::Real | c_p, | ||
| amrex::Real | rdOcp | ||
| ) | const |
Add the face heat flux to the temperature equation: every face deposits H A / (c_p V Pi) into the rho-theta source of its fluid cell (Pi the Exner function, so the flux heats the cell by H A / (c_p V) in temperature). Called after the sources are rebuilt at every slow stage; adds, never overwrites, and uses atomic adds because a corner cell receives several faces.
Face flux into the temperature equation. The rho-theta tendency of the fluid cell is H A / (c_p V Pi); with several faces on one cell the adds are atomic.

| void IBFaceSet::add_outside_occluders | ( | const std::vector< const IBFaceSet * > & | below | ) |
Add the buildings this refined level does not hold to the ray map of its ray cast, from the column maps of the levels below.
build() takes the map from the level's own cells, so on a refined level that covers part of the domain the rays of the shortwave and the view fractions would pass through every building outside it. The ray map is rebuilt with the halo for the tallest column of every level, and each column of the patch that this level's grids do not cover takes the top of the finest level below that covers it (ERF::ibseb_check_refined_levels() has made sure a building is wholly inside or wholly outside each level), on the ratio x ratio columns of this level beneath the coarse one, at the same height. Only the ray cast reads the result: the building ids, the face heights of the wall function and the reports keep the level's own buildings. Call after build() of every level involved and before compute_view_fractions().
| below | Face sets of levels 0 to this level's minus one, in that order. |
Rebuild the ray map with the buildings of the levels below (see the header and build_ray_map()).

| void IBFaceSet::assign_materials | ( | ) |
Assign every face its material properties: from the material library by building id, or the uniform inputs. Called once after build(); fills d_mat, d_albedo, d_emis, d_k, d_rhocp, d_thick and initialises the slab layers to the skin temperature.
Materials per face from the library by building id, or the uniform inputs. Host work on the static geometry, once.

| void IBFaceSet::build | ( | const amrex::MultiFab & | blanking, |
| const amrex::Geometry & | geom | ||
| ) |
Detect this rank's faces from the cell-centred blanking and allocate every per-face array.
Runs on the host once at initialisation: the blanking is copied fab by fab (a pinned copy on GPU builds), the valid cells are scanned, and the arrays are uploaded to the device at the end. Must be called after the blanking has been built and its ghost cells filled, since the solid neighbour of a fluid cell on a box edge lives in a ghost cell. Stops when a solid cell outside the level's grids neighbours a cell of the level, fluid or solid: a building across the edge of a refined level.
| blanking | Cell-centred blanking of the level (needs at least one ghost cell, filled). |
| geom | Geometry of the level: cell sizes for the face areas, domain and periodicity for the neighbour tests. |
Detect the faces owned by this rank and allocate the per-face arrays.
The scan visits every valid cell of every local fab in MFIter order, once. A fluid cell (blanking < 0.5) contributes one face for each of its six neighbours that is solid (blanking >= 0.5); the neighbour may sit in a ghost cell, which is why the blanking must have its ghost cells filled. Neighbours outside the domain in a non-periodic direction are skipped, so a building against a non-periodic boundary has no face there. Solid cells contribute no face, only the column map (the highest solid cell of each column of the level's own boxes) that the building ids and the ray cast read. A solid neighbour outside the level's grids, of a fluid or a solid cell, means a building crosses the edge of a refined level; the scan counts them and stops the run once all ranks have reported.
Faces are appended in scan order, which makes them contiguous per fab; m_fab_start records where each fab's faces begin. The per-direction, per-building and total counts are reduced over all ranks here, once, so report() does not have to reduce static numbers every time. Nothing of the size of the domain is gathered: the column map is exchanged through its ghost cells, the building labels through theirs (see the header), and the one gather is of the distinct labels, one per building.

| void IBFaceSet::build_ray_map | ( | const std::vector< const IBFaceSet * > & | below | ) |
Build the ray map (m_ray_patch) from m_col_valid and the levels below. The halo is sized for the shallowest ray the map must follow to its end: the shallowest ray of the hemisphere sampling (ibseb::hemisphere_min_sz()) and a sun erf.ibseb.sun_min_elev_deg above the horizon, over the tallest column of this level and the levels below, height / tan(elevation) cells in x and in y (ibseb::ray_halo_cells()). A rising ray stops above the tallest column and a falling one at the ground, so within that reach the walk is exact, and beyond it only a sun lower than the floor is concerned, whose direct beam the clear-sky attenuation has all but removed; a building farther than the halo from a face then casts no shadow on it (the far field is open ground). The patch is this rank's boxes grown by the halo, clipped to the domain where it is not periodic and, where it is, reduced to one domain width when the grown box is at least that wide, in which case the walk wraps round and is exact for any reach.
| below | Face sets of the levels below (empty on level 0), each with its build() done. |
Public because it launches a GPU lambda, which nvcc rejects in a private member function.
The ray map of this rank (see the header): the halo, this rank's patch, every rank's patch as one box array, and its contents from the levels below (coarsest first, so the finest level that covers a column has the last word) and then this level's own columns with their periodic images.

|
inline |
Level 0's number for building b of this level (1-based; 0 for one only this level resolves).
| void IBFaceSet::check_canopy_layout | ( | const amrex::MultiFab & | cons, |
| const TwoStreamCanopyView & | canopy | ||
| ) | const |
Stop unless the fields of canopy (this level's two-stream view) lie on the columns of cons, with the same distribution: the two-stream kernels read the column of a face from the fabs with the local index of the face's own fab.
The fields of a two-stream view must lie on this level's columns, with the level's distribution, so that the fabs of local index n hold the columns of the faces fab_start()[n] .. fab_start()[n+1]-1 own: the interface fluxes on the level's own grids (with the top-of-atmosphere ghost, which a face whose cell is the top of the domain reads); the beam on its boxes in x and y with the interfaces from the surface up to at least top_sample_interface() in z; the cosine of the zenith on them flattened to index 0 in z.

| void IBFaceSet::compute_ground | ( | amrex::Real | dt | ) |
Ground heat flux of the current step: advance every face's slab by dt with the skin temperature at the top and the interior temperature at the bottom (implicit, ERF_IBSEBSlab.H) and store the conduction into the slab, G, positive into the wall.
Slab conduction on every face: one kernel over the faces, each solving its own tridiagonal system with the skin at the top and the interior at the bottom.

| void IBFaceSet::compute_longwave | ( | const amrex::MultiFab & | cons, |
| const TwoStreamCanopyView & | canopy = TwoStreamCanopyView{} |
||
| ) |
Longwave of the current step. Incoming on a face: f_sky LW_sky + f_ground LW_ground + f_bldg sigma T_skin^4, the sky term fixed or gray (sky_emissivity sigma T_air^4 with the air temperature of the face's fluid cell, its water vapour included) with the ground term eps_g sigma T_g^4, or with lw_mode = two_stream the longwave down and up at the face's height in the face's column (canopy); the building term is the isothermal-surroundings approximation. Net: eps (LW_in - sigma T_skin^4), positive into the face.
| cons | Conserved state of the level, for the air temperature. |
| canopy | With lw_mode = two_stream, this step's two-stream view of the level (ERF_TwoStreamCanopyForcing.H), or an empty one before the first sweep, when the incoming and net longwave are zero. |
Longwave of the current step. One kernel per fab over that fab's faces, reading the air temperature of the fluid cell from the conserved state (dry density, potential temperature and, with a moisture model, water vapour through the equation of state; cell_qv()). With lw_mode = two_stream the sky and ground terms come from the canopy forcing of the face's column, read from the 2D fab of the same local index (the level's grids flattened, on the same distribution).

| void IBFaceSet::compute_longwave_two_stream | ( | const amrex::MultiFab & | cons, |
| const TwoStreamCanopyView & | canopy | ||
| ) |
Longwave of the current step with lw_mode = two_stream: the sky term is the longwave down of the face's column at the face's height (a roof's interface, a wall's mean of its cell's two; two_stream_canopy_sample()), the ground term its longwave up at the same height (the ground seen through the air in between), so the ground's temperature, emissivity and reflection of the sky are the column's (two_stream_face_sky()). Before the level's first sweep (an empty canopy, the initial report) the air temperature is read and the incoming and net longwave are zero.

| void IBFaceSet::compute_sensible | ( | const amrex::MultiFab & | cons, |
| const amrex::MultiFab & | xvel, | ||
| const amrex::MultiFab & | yvel, | ||
| const amrex::MultiFab & | zvel, | ||
| amrex::Real | c_p, | ||
| const amrex::MultiFab * | olen_ground = nullptr, |
||
| const amrex::MultiFab * | pblh_ground = nullptr, |
||
| amrex::Real | z_i_bulk = 0.0 |
||
| ) |
Sensible heat of the current step through a wall function on every face: the tangential wind of the fluid cell at half a cell from the wall gives u* with the roughness z0_wall, the skin-to-air potential-temperature difference gives theta* with z0h_wall, and H = rho c_p u* theta*, positive out of the face. Neutral, or with the surface layer's stability functions on roofs when asked. The latent flux is not modelled and stays zero.
Beyond neutral: with convective_velocity = deardorff the wind is sqrt(U_tan^2 + (beta w*)^2) with w* from the previous step's H (zero when H is into the face) and a depth that is the mixed layer above a roof or the building height for a wall; with stability_correction the roofs iterate the similarity functions on the face's own Obukhov length, seeded from the ground surface layer's 2D field at the face's column when given.
Fills d_H, d_ustar, d_U_tan, d_rho, d_theta_air, d_H_coeff (the coefficient of the skin-to-air potential-temperature difference that the balance keeps frozen), d_w_star, d_olen and d_z_i; T_air was read by compute_longwave(), which must run first in a step.
| cons | Conserved state of the level (density, rho theta). |
| xvel,yvel,zvel | Face-centred velocities of the level. |
| c_p | Specific heat of air [J/kg/K]. |
| olen_ground | Ground surface layer's Obukhov length (2D field on the level's box array collapsed to k = 0), or null. |
| pblh_ground | Its boundary-layer height field, or null. |
| z_i_bulk | Mixed-layer depth of the level from the bulk Richardson diagnostic or the fixed input [m]. |
Wall function on every face. One kernel per fab over that fab's faces: the cell-centred velocity of the fluid cell from its face values, its tangential part with respect to the wall, the neutral log law for u* and theta*, and on request two additions: a convective velocity scale in the wind (Beljaars' gustiness form with Deardorff's w* from the previous step's flux) and, on roofs, the surface layer's similarity functions iterated on the face's own Obukhov length. The skin temperature is converted to a potential temperature with the fluid cell's Exner function before the difference is taken.
The Obukhov length of a face is L = u*^2 theta / (kappa g theta*) (negative over a hot face). Walls stay on the log law even with the stability correction: the similarity functions assume a horizontal surface, and the convective scale is what carries free convection on a wall. The ground's 2D Obukhov field only seeds the roof iteration.
| void IBFaceSet::compute_shortwave | ( | amrex::Real | time, |
| const TwoStreamCanopyView & | canopy = TwoStreamCanopyView{} |
||
| ) |
Shortwave of the current step: the sun's position (sun_mode), the irradiances of the prescribed provider or, with radiation = two_stream, those of the face's own column at its height (canopy), then per face the direct beam on the face (zero when the ray toward the sun hits a building), the diffuse light through the view fractions, and the absorbed sum.
Fills d_shadow, d_SW_direct_in, d_SW_diffuse_in and d_SW_abs; stores the sun vector and irradiances for the reports (with two_stream the means over all the level's faces of the direct-normal and diffuse irradiance each takes, written to every row of the level).
| time | Simulation time [s]; with sun_mode = solar it is added to time_zero_utc_s (with sun_mode = two_stream the sun comes from set_two_stream_sun()). |
| canopy | With radiation = two_stream, this step's two-stream view of the level (see compute_longwave()), or an empty one before the first sweep, when every face gets no shortwave. |
Shortwave of the current step. The sun and the irradiances are scalars computed on the host from the provider inputs; the per-face work is one kernel: incidence cosine, ray cast against the column tops, direct and diffuse incident, absorbed.
With sun_mode = fixed the direct-normal irradiance and the horizontal diffuse are the inputs as given. With sun_mode = solar the sun follows the site and time and the clear-sky formulas give both irradiances; with sun_mode = two_stream the position and the top-of-atmosphere irradiance are the two-stream radiation's (set_two_stream_sun()) and the same clear-sky formulas give the irradiances. The sun below the horizon gives zero everywhere.
Diffuse on a face: f_sky * diffuse_h + f_ground * albedo_ground * (direct_h + diffuse_h), the second term being the ground-reflected part, with the direct on a horizontal surface direct_h = dni * cos z. The view fractions are the placeholders of build() until compute_view_fractions() has run.

| void IBFaceSet::compute_shortwave_two_stream | ( | const TwoStreamCanopyView & | canopy | ) |
Shortwave of the current step with radiation = two_stream, after compute_shortwave() has placed the sun (m_sun): per face, the direct-normal irradiance of its column at its height (two_stream_face_sky(): a roof's interface, a wall's mean of its cell's two), the beam over the column's own cosine of the zenith, on the face (shadowed by the same ray cast), the diffuse light of the sky there through f_sky, and the ground's reflection, the column's shortwave up at the face's height, through f_ground. One kernel per fab, reading the view's fields of the same local index.
The faces' sun (sun_mode) and the sweep's are required to be one sun (ERF::ibseb_check_sun_matches_two_stream()); the kernel checks it, column by column: a cosine of the zenith more than 1e-4 (1e-3 in single precision) from the faces' stops the run, since a direct beam divided by the wrong cosine and laid along the wrong direction would still look plausible.
Before the level's first sweep (an empty canopy, the initial report) every face gets no shortwave. The reported direct-normal and diffuse irradiances are the means over the level's faces of their columns'.
Referenced by compute_shortwave().


| void IBFaceSet::compute_view_fractions | ( | ) |
View fractions: sample a cosine-weighted hemisphere around every face's outward normal with view_n_az x view_n_el rays through the column walk and count where they end: sky, ground or a building. The three fractions sum to one and are view factors. Called once at initialisation; the geometry is static.
Hemisphere sampling for the view fractions. One kernel over the faces, each looping over its rays; the count of rays ending on the sky, the ground and a building over the total gives the three fractions. Roofs point up and never see the ground; a wall on flat open ground sees half sky and half ground, which the regression test checks.

| void IBFaceSet::dump_faces | ( | const std::string & | prefix | ) | const |
Write every face of this rank to <prefix>.rank<N>.csv with its geometry, view fractions, shadow flag, shortwave terms and skin temperature, for the regression tests and for users who want the raw list.
Per-rank face dump. Every rank writes its own file so no gather is needed; readers concatenate <prefix>.rank*.csv.
Referenced by report().


|
inline |
First face of each local fab in MFIter order; size number of fabs + 1. Faces fab_start()[n] to fab_start()[n+1]-1 belong to the fab with local index n, which is what the scatter kernels rely on.
|
inline |
Whether the level has faces on any rank.
| void IBFaceSet::map_buildings_to_level0 | ( | const IBFaceSet & | coarser, |
| const amrex::IntVect & | ratio | ||
| ) |
Number this refined level's buildings as level 0 numbers them.
Each level labels its buildings from its own cells, so the ids of a refined level differ from level 0's wherever the levels see different buildings: a building outside the refined level, or two that level 0 merges into one. Inputs that go by building (erf.ibseb.material_by_building) and the report's building_level0 column use level 0's numbering, so every building of this level is looked up in the labels of the level below, and through that level's own map in level 0's: each of its columns votes with the id under it and the majority wins. A building only this level resolves maps to 0 (the default material), with a warning. Call after build() of both levels; the level below keeps its labels until release_labels().
| coarser | Face set of the level below, already mapped. |
| ratio | Refinement ratio from the level below to this one. |
Map this level's buildings to level 0's numbering through the labels of the level below (see the header). Every column of a building votes with the level-0 id of the coarse column under it (through the level below's own map), unlabelled coarse columns abstaining, and the most frequent id wins (the lowest on a tie). No single column is trusted: the coarse blanking is a volume average, so a column the coarse level leaves unlabelled (a spire alone in its coarse cell) cannot unmap a building the level below resolves through its other columns. A building none of whose columns lies under a labelled coarse column is one only this level resolves; it maps to 0, and a warning names it when the level below has buildings at all. The level below's ids are brought under this level's columns by a parallel copy; the votes, a few per building, are gathered from every rank and summed, so every rank reaches the same verdict.

|
inline |
Number of buildings of the level, the same on every rank.
|
inline |
|
inline |
Conduction layers per face, from erf.ibseb.n_slab_layers.
Referenced by dump_faces(), print_debug_summary(), read_state(), and write_state().

| void IBFaceSet::print_debug_summary | ( | ) | const |
Print the [IBSEB DEBUG] description of the set: the inputs, every rank's face count and per-fab ranges, the buildings with their footprint columns and bounding boxes, and the device memory of the arrays. Called once from build() when erf.ibseb.debug is set.
Debug description of the set, in the style of the fire module's [FIRE DEBUG] lines: what was read, what every rank holds, what the buildings look like, and what the arrays cost. Per-rank lines use AllPrint() so every rank reports; the rest is printed by the I/O rank.

|
inline |
Halo of the ray map in cells (x, y), from the last build_ray_map().
| ibseb::RayMap IBFaceSet::ray_map | ( | ) | const |
The ray map of this rank for the kernels of the shortwave and the view fractions: the column tops over this rank's patch and the grid they are drawn on (ibseb::RayMap). A rank without boxes has no patch and no faces.
Referenced by compute_shortwave(), and compute_shortwave_two_stream().


|
inline |
Whether every rank's patch spans the whole domain, so every ray is followed to its end.
| void IBFaceSet::read_state | ( | const std::string & | file | ) |
Read the face state back from a file written by write_state(), after build() has recreated the list from the blanking.
The I/O rank reads the table; every rank sends it the keys of its own faces; the I/O rank finds each one by binary search and sends the records back. Only the I/O rank ever holds the whole table, and a restart on any number of ranks finds every face. Stops when the file holds another number of slab layers than the deck's erf.ibseb.n_slab_layers, another domain size or another number of faces, or when a face of this list has no record: a checkpoint of other buildings. Collective: every rank must call it.
The inverse of write_state(): the I/O rank reads the table and checks the header against this level (every rank gets the header, so all stop together on a mismatch); each rank sends the keys of its own faces, the I/O rank looks them up by binary search and sends the records back; each rank then unpacks its records into the device arrays.

|
inline |
Free the column labels once the level above has been mapped (map_buildings_to_level0()).
| void IBFaceSet::report | ( | amrex::Real | time, |
| int | step, | ||
| bool | write_csv | ||
| ) | const |
Print the [IBSEB] summary line and, when asked, append one row per building to erf.ibseb.csv_file.
The summary carries the global face counts per direction, the number of buildings, the total face area and the range of the skin temperature; the CSV rows carry per building the face count, the area, the area-weighted mean fluxes and skin temperature with its range, the largest balance residual, and the sun the step used, from its start (zenith, azimuth, direct-normal and diffuse irradiance), on a row stamped with the time at the end of the step. All numbers are reduced over the ranks; the file is written by the I/O rank only, with a header only when the file does not exist yet, so a restarted run appends. Every level appends to the same file, its rows marked by the level column. With erf.ibseb.dump_faces_file the rows come with a face dump, dump_faces() to <prefix>[.levN][.stepNNNNNN].rank<N>.csv: a refined level N adds .levN so it does not overwrite the level below, and erf.ibseb.dump_faces_tag_step the step.
| time | Simulation time [s] written to the rows. |
| step | Step number written to the rows. |
| write_csv | Whether to append rows, or only print the summary. |
Summary line and per-building CSV rows. The dynamic quantities (skin temperature range and area-weighted mean per building) are gathered on the host from the device arrays and reduced; the static counts and areas were reduced in build().

| void IBFaceSet::scatter_diagnostics | ( | amrex::MultiFab & | nfaces, |
| amrex::MultiFab & | tskin | ||
| ) | const |
Scatter the faces into two cell-centred diagnostics for the plotfile.
| [out] | nfaces | Number of wall faces touching each fluid cell (0 away from buildings; up to 3 at an outside corner, 6 in a one-cell slot). |
| [out] | tskin | Mean skin temperature of those faces, 0 where there are none. |
Both fields must be on the level's box array with no ghost cells. Faces of one fab are accumulated with atomic adds because a corner cell receives several faces.
Scatter the face count and the mean skin temperature into cell-centred fields. One kernel per fab over that fab's faces (contiguous, see fab_start()), with atomic adds since a corner cell collects several faces, then a kernel over the box divides the temperature sum by the count.

| void IBFaceSet::scatter_field | ( | const amrex::Gpu::DeviceVector< amrex::Real > & | v, |
| amrex::MultiFab & | out | ||
| ) | const |
Scatter one per-face array into a cell-centred field as the mean over the faces touching each cell (zero where there are none).
Scatter one per-face array as a per-cell mean, the same accumulation as scatter_diagnostics() with the face count as the divisor.

|
inline |
Record the wall-clock time of the initialisation (build and view fractions).
|
inline |
Give the sun of the next compute_shortwave() with erf.ibseb.sun_mode = two_stream: the two-stream radiation's declination and hour angle at that time, its site latitude and its top-of-atmosphere irradiance (the date's distance factor included). ERF::ibseb_set_two_stream_sun() calls it before every call; the call uses it up, so a shortwave without a fresh sun stops rather than reusing an old one.
| void IBFaceSet::solve_balance | ( | amrex::Real | dt | ) |
Prognostic balance of the current step. Per face: the slab's linear response to the skin temperature for this step, the Newton solve of ERF_IBSEBBalance.H with the shortwave, the external flux, the sky and ground longwave, the frozen wall-function coefficient and the latent flux, the slab advanced with the solution, and the fluxes (LW_in, LW_net, H, G) rewritten at the solution. Fills d_resid (|balance| at the end, non-zero only at a bound or the iteration cap) and d_niter. Needs compute_shortwave(), compute_longwave() and compute_sensible() of the same step first.
| dt | Atmospheric time step [s], the slab's step. |
Prognostic balance on every face: one kernel over the faces, each with its own slab response, Newton solve and slab advance. Everything the solve needs was stored by the three flux routines of the step, so no fab data is touched here. The fluxes are rewritten at the solution so that the dump, the reports and the heat deposited into the air all describe the same closed balance; d_resid holds what is left of it.

|
inline |
The highest interface of the level's vertical grid that any of its faces samples with radiation = two_stream (a roof the bottom of its fluid cell, a ceiling and a wall the top of its cell too), counted from the domain bottom, over all ranks; -1 when the level has no faces. The two-stream beam the faces read holds the interfaces up to there.
|
private |
Warn once when a fixed sun stands below erf.ibseb.sun_min_elev_deg and the map does not span the domain.
Warn when a fixed sun stands below erf.ibseb.sun_min_elev_deg and the ray map does not span the domain: the shadows of buildings beyond the halo are then not cast. Printed once per level by the I/O rank.
| void IBFaceSet::write_state | ( | const std::string & | file | ) | const |
Write the face state (skin temperature, sensible flux and slab temperatures) to file for the checkpoint: one record per face of the level, in one global order, written by the I/O rank.
The file holds one text line, IBSEBFaces 1 <nface> <n_layers> <nx> <ny> <nz> (the format version, the level's face count, the slab layers per face and the domain size in cells), then in binary a marker word (0x0102030405060708 as a 64-bit integer, so a file from a machine with another byte order is refused), the nface keys as 64-bit integers in ascending order, then the nface x (2 + n_layers) values as doubles: a face's skin temperature, its sensible flux (read as the previous step's by the convective velocity scale) and its slab layers from the skin inward. The key of a face is ((i ny + j) nz + k) 6 + 2 dir + (side > 0) with (i, j, k) counted from the domain's low corner, so it names the face whatever the rank count. The values are doubles whatever amrex::Real is, so a single-precision run reads a double-precision checkpoint and the other way round. The file costs 8 (3 + n_layers) bytes per face beyond its header line and marker, which is the data itself: the cell field it replaces covered the face-owning cells with whole boxes and was about eleven times larger on the FaceStorage skyscraper (erf-model/ERF#4019).
Every rank copies its faces to the host and sorts them by key; the I/O rank gathers the records, orders them and writes the file. Collective: every rank must call it.
One record per face, gathered on the I/O rank and written in key order: the header line, the sorted keys, then the values record by record. Every rank sorts its own faces first so the gathered runs are ordered; the I/O rank then merges them by sorting an index over all the records.

| amrex::Gpu::DeviceVector<amrex::Real> IBFaceSet::d_albedo |
Referenced by compute_shortwave(), compute_shortwave_two_stream(), and dump_faces().
| amrex::Gpu::DeviceVector<amrex::Real> IBFaceSet::d_area |
Face area [m2].
Referenced by add_heat_flux_to_source(), dump_faces(), and report().
| amrex::Gpu::DeviceVector<int> IBFaceSet::d_bid |
Building id (1-based)
Referenced by dump_faces(), and report().
| amrex::Gpu::DeviceVector<int> IBFaceSet::d_dir |
Face direction: 0 x, 1 y, 2 z.
Referenced by compute_shortwave(), compute_shortwave_two_stream(), dump_faces(), read_state(), and write_state().
| amrex::Gpu::DeviceVector<amrex::Real> IBFaceSet::d_emis |
Optical properties of the face.
Referenced by dump_faces().
| amrex::Gpu::DeviceVector<amrex::Real> IBFaceSet::d_f_bldg |
View fractions, sum to 1.
Referenced by dump_faces().
| amrex::Gpu::DeviceVector<amrex::Real> IBFaceSet::d_f_ground |
Referenced by compute_shortwave(), compute_shortwave_two_stream(), and dump_faces().
| amrex::Gpu::DeviceVector<amrex::Real> IBFaceSet::d_f_sky |
Referenced by compute_shortwave(), compute_shortwave_two_stream(), and dump_faces().
| amrex::Gpu::DeviceVector<amrex::Real> IBFaceSet::d_G |
Referenced by dump_faces(), and report().
| amrex::Gpu::DeviceVector<amrex::Real> IBFaceSet::d_H |
Referenced by add_heat_flux_to_source(), dump_faces(), read_state(), report(), and write_state().
| amrex::Gpu::DeviceVector<amrex::Real> IBFaceSet::d_H_coeff |
H = H_coeff (theta_skin - theta_air) [W/m2/K].
Referenced by dump_faces().
| amrex::Gpu::DeviceVector<amrex::Real> IBFaceSet::d_hbld |
Height of the face's building column [m].
Referenced by dump_faces().
| amrex::Gpu::DeviceVector<int> IBFaceSet::d_i |
| amrex::Gpu::DeviceVector<int> IBFaceSet::d_j |
| amrex::Gpu::DeviceVector<int> IBFaceSet::d_k |
Fluid cell of the face.
Referenced by add_heat_flux_to_source(), compute_shortwave_two_stream(), dump_faces(), read_state(), scatter_diagnostics(), scatter_field(), and write_state().
| amrex::Gpu::DeviceVector<amrex::Real> IBFaceSet::d_kth |
Referenced by dump_faces().
| amrex::Gpu::DeviceVector<amrex::Real> IBFaceSet::d_LE |
Referenced by dump_faces().
| amrex::Gpu::DeviceVector<amrex::Real> IBFaceSet::d_LW_down_in |
Incoming longwave on the face (sky, ground and walls)
Referenced by dump_faces().
| amrex::Gpu::DeviceVector<amrex::Real> IBFaceSet::d_LW_ext |
Incoming longwave from sky and ground only [W/m2].
Referenced by dump_faces().
| amrex::Gpu::DeviceVector<amrex::Real> IBFaceSet::d_LW_net |
Referenced by dump_faces(), and report().
| amrex::Gpu::DeviceVector<int> IBFaceSet::d_mat |
Material id (0 = uniform inputs)
Referenced by dump_faces().
| amrex::Gpu::DeviceVector<int> IBFaceSet::d_niter |
Newton iterations of the last solve.
Referenced by dump_faces().
| amrex::Gpu::DeviceVector<amrex::Real> IBFaceSet::d_olen |
Obukhov length used [m] (1e30 when neutral)
Referenced by dump_faces().
| amrex::Gpu::DeviceVector<amrex::Real> IBFaceSet::d_Q_ext |
External incident flux [W/m2], e.g. fire radiation.
Referenced by dump_faces(), and report().
| amrex::Gpu::DeviceVector<amrex::Real> IBFaceSet::d_resid |
|balance| after the solve [W/m2]
Referenced by dump_faces(), and report().
| amrex::Gpu::DeviceVector<amrex::Real> IBFaceSet::d_rho |
Density of the fluid cell [kg/m3].
Referenced by dump_faces().
| amrex::Gpu::DeviceVector<amrex::Real> IBFaceSet::d_rhocp |
Referenced by dump_faces().
| amrex::Gpu::DeviceVector<amrex::Real> IBFaceSet::d_shadow |
1 when the ray to the sun hits a building, else 0
Referenced by compute_shortwave(), compute_shortwave_two_stream(), dump_faces(), and report().
| amrex::Gpu::DeviceVector<int> IBFaceSet::d_side |
Solid neighbour at -1 (low) or +1 (high) side.
Referenced by compute_shortwave(), compute_shortwave_two_stream(), dump_faces(), read_state(), and write_state().
| amrex::Gpu::DeviceVector<amrex::Real> IBFaceSet::d_SW_abs |
Referenced by compute_shortwave(), compute_shortwave_two_stream(), dump_faces(), and report().
| amrex::Gpu::DeviceVector<amrex::Real> IBFaceSet::d_SW_diffuse_in |
Sky and ground-reflected diffuse incident.
Referenced by compute_shortwave(), compute_shortwave_two_stream(), and dump_faces().
| amrex::Gpu::DeviceVector<amrex::Real> IBFaceSet::d_SW_direct_in |
Direct beam incident on the face.
Referenced by compute_shortwave(), compute_shortwave_two_stream(), and dump_faces().
| amrex::Gpu::DeviceVector<amrex::Real> IBFaceSet::d_T_air |
Air temperature of the fluid cell.
Referenced by dump_faces().
| amrex::Gpu::DeviceVector<amrex::Real> IBFaceSet::d_T_skin |
Skin temperature [K].
Referenced by dump_faces(), read_state(), report(), scatter_diagnostics(), and write_state().
| amrex::Gpu::DeviceVector<amrex::Real> IBFaceSet::d_T_slab |
Slab layers [K], face-major: [face * n_layers + layer].
Referenced by dump_faces(), read_state(), and write_state().
| amrex::Gpu::DeviceVector<amrex::Real> IBFaceSet::d_theta_air |
Potential temperature of the fluid cell [K].
Referenced by dump_faces().
| amrex::Gpu::DeviceVector<amrex::Real> IBFaceSet::d_thick |
Slab conductivity [W/m/K], heat capacity [J/m3/K], thickness [m].
Referenced by dump_faces().
| amrex::Gpu::DeviceVector<amrex::Real> IBFaceSet::d_U_tan |
Tangential wind speed at the fluid cell [m/s].
Referenced by dump_faces().
| amrex::Gpu::DeviceVector<amrex::Real> IBFaceSet::d_ustar |
Friction velocity of the wall function [m/s].
Referenced by dump_faces().
| amrex::Gpu::DeviceVector<amrex::Real> IBFaceSet::d_w_star |
Convective velocity scale of the step [m/s].
Referenced by dump_faces(), and report().
| amrex::Gpu::DeviceVector<amrex::Real> IBFaceSet::d_xf |
Referenced by compute_shortwave(), compute_shortwave_two_stream(), and dump_faces().
| amrex::Gpu::DeviceVector<amrex::Real> IBFaceSet::d_yf |
Referenced by compute_shortwave(), compute_shortwave_two_stream(), and dump_faces().
| amrex::Gpu::DeviceVector<amrex::Real> IBFaceSet::d_z_i |
Depth in w* [m]: mixed layer above a roof, building height for a wall.
Referenced by dump_faces().
| amrex::Gpu::DeviceVector<amrex::Real> IBFaceSet::d_zf |
Face centre [m].
Referenced by compute_shortwave(), compute_shortwave_two_stream(), and dump_faces().
|
private |
Total face area [m2].
Referenced by print_debug_summary(), and report().
|
private |
Face area per building [m2].
Referenced by print_debug_summary(), and report().
|
private |
Referenced by print_debug_summary().
|
private |
Referenced by print_debug_summary().
|
private |
Referenced by print_debug_summary().
|
private |
Referenced by print_debug_summary().
|
private |
Referenced by print_debug_summary().
|
private |
Faces per building.
Referenced by print_debug_summary(), and report().
|
private |
Tallest column the ray map holds [m] (the levels below included after add_outside_occluders())
| amrex::iMultiFab IBFaceSet::m_col_valid |
Referenced by print_debug_summary().
|
private |
Number of per-step updates timed.
Referenced by add_cost(), and report().
|
private |
Wall-clock seconds spent in the per-step update on this rank.
Referenced by add_cost(), and report().
|
private |
Low corner of the level's domain.
Referenced by compute_shortwave_two_stream(), read_state(), and write_state().
|
private |
Cell sizes [m].
|
private |
See fab_start()
Referenced by add_heat_flux_to_source(), compute_shortwave_two_stream(), fab_start(), print_debug_summary(), scatter_diagnostics(), and scatter_field().
|
private |
Geometry of the level.
Referenced by map_buildings_to_level0().
| amrex::IntVect IBFaceSet::m_halo {AMREX_D_DECL(0, 0, 0)} |
Halo of the patch in cells.
Referenced by ray_halo().
|
private |
Wall-clock seconds of build() and compute_view_fractions()
Referenced by report(), and set_init_cost().
|
private |
Referenced by map_buildings_to_level0(), print_debug_summary(), and release_labels().
|
private |
AMR level, for reports.
Referenced by compute_shortwave(), compute_shortwave_two_stream(), print_debug_summary(), read_state(), report(), and write_state().
| bool IBFaceSet::m_map_spans_domain = false |
Every rank's patch spans the domain.
Referenced by ray_map_spans_domain().
| int IBFaceSet::m_max_steps = 0 |
Columns a walk is followed for: the halo's reach in x plus y, before the domain cap.
|
private |
Buildings of the level (global)
Referenced by map_buildings_to_level0(), n_buildings(), print_debug_summary(), and report().
|
private |
Faces owned by this rank.
Referenced by compute_shortwave(), compute_shortwave_two_stream(), dump_faces(), n_faces(), print_debug_summary(), read_state(), report(), and write_state().
|
private |
Faces per direction.
Referenced by compute_shortwave_two_stream(), print_debug_summary(), read_state(), and report().
|
private |
Referenced by read_state(), and write_state().
|
private |
Referenced by read_state(), and write_state().
|
private |
Cells of the domain in x, y and z.
Referenced by read_state(), and write_state().
|
private |
Copy of the inputs.
Referenced by compute_shortwave(), compute_shortwave_two_stream(), n_layers(), print_debug_summary(), read_state(), report(), and write_state().
| amrex::Box IBFaceSet::m_patch_box |
This rank's patch (empty without boxes)
Referenced by print_debug_summary().
|
private |
|
private |
Periodicity in x and y.
|
private |
State component of rho qv, -1 without a moisture model.
Referenced by add_heat_flux_to_source().
| amrex::iMultiFab IBFaceSet::m_ray_patch |
|
private |
Referenced by compute_shortwave(), compute_shortwave_two_stream(), report(), and sun().
|
private |
Referenced by building_level0(), map_buildings_to_level0(), and report().
|
private |
Highest interface a face samples, over all ranks (-1: no faces)
Referenced by has_faces(), and top_sample_interface().
|
private |
Referenced by compute_shortwave(), and set_two_stream_sun().
| bool IBFaceSet::m_wrap_x = false |
| bool IBFaceSet::m_wrap_y = false |
The patch spans the periodic domain in x / y.
|
private |
|
private |
Domain origin [m].
|
private |
Ground height [m] (flat, the domain bottom)