ERF
Energy Research and Forecasting: An Atmospheric Modeling Code
ERF_IBFaceSet.H
Go to the documentation of this file.
1 #ifndef ERF_IB_FACE_SET_H
2 #define ERF_IB_FACE_SET_H
3 
4 #include <AMReX_MultiFab.H>
5 #include <AMReX_BoxArray.H>
6 #include <AMReX_DistributionMapping.H>
7 #include <AMReX_Geometry.H>
8 #include <AMReX_GpuContainers.H>
9 #include <cmath>
10 #include <vector>
11 #include "ERF_IBSEBParams.H"
12 #include "ERF_IBSEBMaterials.H"
14 
15 /**
16  * \file ERF_IBFaceSet.H
17  * \brief Compact list of the wall faces of resolved buildings on one AMR level.
18  *
19  * **What a face is.** The immersed forcing marks every cell of a level as
20  * fluid or solid through the cell-centred blanking ``terrain_blanking``
21  * (one minus the embedded-boundary volume fraction, so 0 in the air and 1
22  * inside a building). A wall face is the cell face between a fluid cell
23  * (blanking below 0.5) and a solid cell (blanking at or above 0.5). Walls
24  * are x or y faces, roofs are z faces with the fluid above the solid.
25  *
26  * **Face convention.** A face is identified by its *fluid* cell ``(i, j, k)``,
27  * its direction ``dir`` (0 = x, 1 = y, 2 = z) and its ``side`` (-1 when the
28  * solid neighbour is at ``i-1`` / ``j-1`` / ``k-1``, +1 when it is at
29  * ``i+1`` / ``j+1`` / ``k+1``). The outward unit normal of the wall, pointing
30  * into the fluid, is therefore ``-side`` along ``dir``. The fluid cell is where
31  * every atmospheric input of the balance (wind, temperature, humidity,
32  * radiation) is read and where the wall's heat flux is deposited.
33  *
34  * **Ownership and layout.** Each face is stored exactly once, on the rank
35  * that owns its fluid cell, so the per-step update of the balance is a kernel
36  * over this rank's faces with no communication; only the reports reduce
37  * across ranks. The faces are a struct of device arrays (one
38  * ``amrex::Gpu::DeviceVector`` per quantity, all indexed by the face number)
39  * and are stored contiguously per local fab in MFIter order:
40  * ``fab_start()[mfi.LocalIndex()]`` to ``fab_start()[mfi.LocalIndex()+1]``
41  * are the faces whose fluid cell is in that fab, which is what lets a kernel
42  * scatter into that fab's arrays without a search.
43  *
44  * **Building ids.** The solid columns of the blanking (any solid cell in the
45  * column) are labelled by 4-connectivity in the horizontal and numbered in
46  * scan order over ``(i, j)``, identically on every rank from a reduced column
47  * mask; a face carries the id of the column of its solid neighbour. Ids are
48  * 1-based, 0 is never assigned.
49  *
50  * **Output.** The list is never written directly. scatter_diagnostics() puts
51  * the number of faces and their mean skin temperature into cell-centred
52  * fields for the plotfile; save_state() / load_state() move the skin
53  * temperature, the sensible flux and the slab temperatures through a
54  * cell-centred field with one slot per face of a cell (see state_ncomp())
55  * for the checkpoint. On restart the list is rebuilt from the blanking and
56  * refilled from that field, so a restart does not depend on the rank count
57  * or on the order the faces were found in.
58  *
59  * **Per-step order.** build() detects and stores the faces and
60  * compute_view_fractions() fills ``d_f_sky`` / ``d_f_ground`` / ``d_f_bldg``
61  * once at initialisation; every step then runs compute_shortwave(),
62  * compute_longwave(), compute_sensible() and, with ``erf.ibseb.prognostic``,
63  * solve_balance(), which finds the skin temperature closing the balance,
64  * advances the slab with it and rewrites the fluxes at the solution; without
65  * it compute_ground() advances the slab under the fixed skin. ``d_Q_ext`` is
66  * the hook through which an external incident flux (a fire's radiation)
67  * enters without the balance knowing its source: whoever owns it writes the
68  * array before solve_balance() runs.
69  */
70 class IBFaceSet
71 {
72 public:
73  /**
74  * Construct an empty face set for one level; build() fills it.
75  * @param params Inputs of the balance (copied; the set never reads ParmParse).
76  * @param lev AMR level the set belongs to, for reports only.
77  */
78  IBFaceSet (const IBSEBParams& params, int lev) : m_params(params), m_lev(lev) {}
79 
80  /**
81  * Detect this rank's faces from the cell-centred blanking and allocate
82  * every per-face array.
83  *
84  * Runs on the host once at initialisation: the blanking is copied fab by
85  * fab (a pinned copy on GPU builds), the valid cells are scanned, and the
86  * arrays are uploaded to the device at the end. Must be called after the
87  * blanking has been built and its ghost cells filled, since the solid
88  * neighbour of a fluid cell on a box edge lives in a ghost cell. Stops
89  * when a solid cell outside the level's grids neighbours a cell of the
90  * level, fluid or solid: a building across the edge of a refined level.
91  *
92  * @param blanking Cell-centred blanking of the level (needs at least one
93  * ghost cell, filled).
94  * @param geom Geometry of the level: cell sizes for the face areas,
95  * domain and periodicity for the neighbour tests.
96  */
97  void build (const amrex::MultiFab& blanking, const amrex::Geometry& geom);
98 
99  /**
100  * Add the buildings this refined level does not hold to the column map of
101  * its ray cast, from the map of the level below.
102  *
103  * build() takes the map from the level's own cells, so on a refined level
104  * that covers part of the domain the rays of the shortwave and the view
105  * fractions would pass through every building outside it. Every column of
106  * the coarser map whose top cell this level's grids do not cover
107  * (ERF::ibseb_check_refined_levels() has made sure a building is wholly
108  * inside or wholly outside) is copied onto the ratio x ratio columns of
109  * this level beneath it, at the same height, and the map grows to the
110  * bounding box of both. Only the ray cast reads the result: the building
111  * ids, the face heights of the wall function and the reports keep the
112  * level's own buildings. Call after build() and before
113  * compute_view_fractions(); the coarser set must have had its own call
114  * already, so buildings outside several levels pass down the hierarchy.
115  *
116  * @param coarser Face set of the level below.
117  * @param ratio Refinement ratio from the level below to this one.
118  * @param grids_crse This level's grids coarsened by ``ratio``.
119  */
120  void add_outside_occluders (const IBFaceSet& coarser, const amrex::IntVect& ratio,
121  const amrex::BoxArray& grids_crse);
122 
123  /**
124  * Give the sun of the next compute_shortwave() with
125  * ``erf.ibseb.sun_mode = two_stream``: the two-stream radiation's
126  * declination and hour angle at that time, its site latitude and its
127  * top-of-atmosphere irradiance (the date's distance factor included).
128  * ERF::ibseb_set_two_stream_sun() calls it before every call; the call
129  * uses it up, so a shortwave without a fresh sun stops rather than reusing
130  * an old one.
131  */
132  void set_two_stream_sun (amrex::Real declination, amrex::Real hour_angle,
133  amrex::Real latitude_deg, amrex::Real toa_irradiance)
134  {
135  m_ts_sun = {true, declination, hour_angle, latitude_deg, toa_irradiance};
136  }
137 
138  /**
139  * Number this refined level's buildings as level 0 numbers them.
140  *
141  * Each level labels its buildings from its own cells, so the ids of a
142  * refined level differ from level 0's wherever the levels see different
143  * buildings: a building outside the refined level, or two that level 0
144  * merges into one. Inputs that go by building (erf.ibseb.material_by_building)
145  * and the report's ``building_level0`` column use level 0's numbering, so
146  * every building of this level is looked up in the labels of the level
147  * below, and through that level's own map in level 0's: each of its
148  * columns votes with the id under it and the majority wins. A building
149  * only this level resolves maps to 0 (the default material), with a
150  * warning.
151  * Call after build() of both levels; the level below keeps its labels until
152  * release_labels().
153  *
154  * @param coarser Face set of the level below, already mapped.
155  * @param ratio Refinement ratio from the level below to this one.
156  */
157  void map_buildings_to_level0 (const IBFaceSet& coarser, const amrex::IntVect& ratio);
158 
159  /** Level 0's number for building ``b`` of this level (1-based; 0 for one only this level resolves). */
160  int building_level0 (int b) const { return m_to_lev0.at(b); }
161 
162  /** Free the column labels once the level above has been mapped (map_buildings_to_level0()). */
163  void release_labels () { std::vector<int>().swap(m_lab); }
164 
165  /** Number of faces owned by this rank (not the global count; see report()). */
166  int n_faces () const { return m_nface; }
167  /** Number of buildings of the level, the same on every rank. */
168  int n_buildings () const { return m_nbld; }
169  /** Conduction layers per face, from ``erf.ibseb.n_slab_layers``. */
170  int n_layers () const { return m_params.n_slab_layers; }
171 
172  /**
173  * Number of components of the checkpoint state field.
174  *
175  * The field carries n_slots() slots of ``2 + n_layers()`` values per cell:
176  * component ``slot * (2 + n_layers())`` is the skin temperature of that
177  * slot, the next its sensible flux (read as the previous step's by the
178  * convective velocity scale), and the following ``n_layers()`` components
179  * are its slab layers.
180  *
181  * A cell carries one slot per face it owns, numbered in the ``(dir, side)``
182  * order in which build() finds them, so the width is the largest face
183  * count on any one cell of the level rather than the six a cell could hold
184  * in principle. Around ordinary buildings that maximum is two or three (an
185  * outside edge or corner); six needs a one-cell slot. build() rebuilds the
186  * numbering from the same blanking on restart, so the slots line up
187  * whatever the rank count.
188  */
189  int state_ncomp () const { return m_nslots * (2 + n_layers()); }
190 
191  /** Slots per cell of the checkpoint field: the largest face count on a cell of the level. */
192  int n_slots () const { return m_nslots; }
193 
194  /**
195  * Boxes of the checkpoint field: 4 x 4 column blocks clipped to the
196  * k-range that actually owns faces, so the field follows the shell of
197  * face-owning cells rather than the built volume. A block over the
198  * interior of a wide footprint keeps only the layer above the roof, while
199  * a block on a wall still spans its height. Built identically on every
200  * rank by build() from a reduced block k-range map; the same buildings
201  * give the same boxes on restart, whatever the rank count. Empty when the
202  * level has no faces.
203  */
204  const amrex::BoxArray& state_boxarray () const { return m_state_ba; }
205  /** Whether the level has a checkpoint field to write (any faces at all). */
206  bool has_state () const { return !m_state_ba.empty(); }
207  /** A field on state_boxarray() with state_ncomp() components, for the checkpoint. */
208  amrex::MultiFab make_state () const;
209 
210  /**
211  * View fractions: sample a cosine-weighted hemisphere around
212  * every face's outward normal with ``view_n_az x view_n_el`` rays through
213  * the column walk and count where they end: sky, ground or a building.
214  * The three fractions sum to one and are view factors. Called once at
215  * initialisation; the geometry is static.
216  */
217  void compute_view_fractions ();
218 
219  /**
220  * Longwave of the current step. Incoming on a face:
221  * ``f_sky LW_sky + f_ground LW_ground + f_bldg sigma T_skin^4``,
222  * the sky term fixed or gray (``sky_emissivity sigma T_air^4`` with the
223  * air temperature of the face's fluid cell) with the ground term
224  * ``eps_g sigma T_g^4``, or with ``lw_mode = two_stream`` the longwave
225  * down and up at the face's height in the face's column
226  * (``canopy``); the building term is the isothermal-surroundings
227  * approximation. Net: ``eps (LW_in - sigma T_skin^4)``, positive into the face.
228  * @param cons Conserved state of the level, for the air temperature.
229  * @param canopy With ``lw_mode = two_stream``, this step's two-stream view of the
230  * level (ERF_TwoStreamCanopyForcing.H), or an empty one before the
231  * first sweep, when the incoming and net longwave are zero.
232  */
233  void compute_longwave (const amrex::MultiFab& cons, const TwoStreamCanopyView& canopy = TwoStreamCanopyView{});
234 
235  /**
236  * Assign every face its material properties: from the material
237  * library by building id, or the uniform inputs. Called once after
238  * build(); fills d_mat, d_albedo, d_emis, d_k, d_rhocp, d_thick and
239  * initialises the slab layers to the skin temperature.
240  */
241  void assign_materials ();
242 
243  /**
244  * Ground heat flux of the current step: advance every face's
245  * slab by dt with the skin temperature at the top and the interior
246  * temperature at the bottom (implicit, ERF_IBSEBSlab.H) and store the
247  * conduction into the slab, G, positive into the wall.
248  */
249  void compute_ground (amrex::Real dt);
250 
251  /**
252  * Prognostic balance of the current step. Per face: the
253  * slab's linear response to the skin temperature for this step, the
254  * Newton solve of ERF_IBSEBBalance.H with the shortwave, the external
255  * flux, the sky and ground longwave, the frozen wall-function
256  * coefficient and the latent flux, the slab advanced with the solution,
257  * and the fluxes (LW_in, LW_net, H, G) rewritten at the solution. Fills
258  * d_resid (|balance| at the end, non-zero only at a bound or the
259  * iteration cap) and d_niter. Needs compute_shortwave(),
260  * compute_longwave() and compute_sensible() of the same step first.
261  * @param dt Atmospheric time step [s], the slab's step.
262  */
263  void solve_balance (amrex::Real dt);
264 
265  /**
266  * Sensible heat of the current step through a wall function on
267  * every face: the tangential wind of the fluid cell at half a cell from
268  * the wall gives u* with the roughness z0_wall, the skin-to-air
269  * potential-temperature difference gives theta* with z0h_wall, and
270  * H = rho c_p u* theta*, positive out of the face. Neutral, or with the
271  * surface layer's stability functions on roofs when asked. The latent
272  * flux is not modelled and stays zero.
273  *
274  * Beyond neutral: with ``convective_velocity = deardorff`` the
275  * wind is ``sqrt(U_tan^2 + (beta w*)^2)`` with w* from the previous
276  * step's H (zero when H is into the face) and a depth that is the mixed
277  * layer above a roof or the building height for a wall; with
278  * ``stability_correction`` the roofs iterate the similarity functions on
279  * the face's own Obukhov length, seeded from the ground surface layer's
280  * 2D field at the face's column when given.
281  *
282  * Fills d_H, d_ustar, d_U_tan, d_rho, d_theta_air, d_H_coeff (the
283  * coefficient of the skin-to-air potential-temperature difference that
284  * the balance keeps frozen), d_w_star, d_olen and d_z_i; T_air was read
285  * by compute_longwave(), which must run first in a step.
286  * @param cons Conserved state of the level (density, rho theta).
287  * @param xvel, yvel, zvel Face-centred velocities of the level.
288  * @param c_p Specific heat of air [J/kg/K].
289  * @param olen_ground Ground surface layer's Obukhov length (2D field on
290  * the level's box array collapsed to k = 0), or null.
291  * @param pblh_ground Its boundary-layer height field, or null.
292  * @param z_i_bulk Mixed-layer depth of the level from the bulk
293  * Richardson diagnostic or the fixed input [m].
294  */
295  void compute_sensible (const amrex::MultiFab& cons, const amrex::MultiFab& xvel,
296  const amrex::MultiFab& yvel, const amrex::MultiFab& zvel, amrex::Real c_p,
297  const amrex::MultiFab* olen_ground = nullptr,
298  const amrex::MultiFab* pblh_ground = nullptr,
299  amrex::Real z_i_bulk = 0.0);
300 
301  /**
302  * Add the face heat flux to the temperature equation: every face
303  * deposits ``H A / (c_p V Pi)`` into the rho-theta source of its fluid
304  * cell (Pi the Exner function, so the flux heats the cell by H A / (c_p V)
305  * in temperature). Called after the sources are rebuilt at every slow
306  * stage; adds, never overwrites, and uses atomic adds because a corner
307  * cell receives several faces.
308  */
309  void add_heat_flux_to_source (amrex::MultiFab& source, const amrex::MultiFab& cons,
310  const amrex::Geometry& geom, amrex::Real c_p, amrex::Real rdOcp) const;
311 
312  /**
313  * Shortwave of the current step: the sun's position (sun_mode), the
314  * irradiances of the prescribed provider or, with ``radiation =
315  * two_stream``, those of the face's own column at its height (``canopy``),
316  * then per face
317  * the direct beam on the face (zero when the ray toward the sun hits a
318  * building), the diffuse light through the view fractions, and the
319  * absorbed sum.
320  *
321  * Fills d_shadow, d_SW_direct_in, d_SW_diffuse_in and d_SW_abs; stores
322  * the sun vector and irradiances for the reports (with two_stream the
323  * means over all the level's faces of the direct-normal and diffuse
324  * irradiance each takes, written to every row of the level).
325  * @param time Simulation time [s]; with sun_mode = solar it is added to
326  * time_zero_utc_s (with sun_mode = two_stream the sun comes
327  * from set_two_stream_sun()).
328  * @param canopy With ``radiation = two_stream``, this step's two-stream view of
329  * the level (see compute_longwave()), or an empty one before the
330  * first sweep, when every face gets no shortwave.
331  */
333 
334  /**
335  * The highest interface of the level's vertical grid that any of its faces
336  * samples with radiation = two_stream (a roof the bottom of its fluid cell, a
337  * ceiling and a wall the top of its cell too), counted from the domain bottom, over all
338  * ranks; -1 when the level has no faces. The two-stream beam the faces read
339  * holds the interfaces up to there.
340  */
341  int top_sample_interface () const { return m_top_sample; }
342 
343  /** Whether the level has faces on any rank. */
344  bool has_faces () const { return m_top_sample >= 0; }
345 
346  /**
347  * Stop unless the fields of ``canopy`` (this level's two-stream view) lie on
348  * the columns of ``cons``, with the same distribution: the two-stream kernels
349  * read the column of a face from the fabs with the local index of the face's
350  * own fab.
351  */
352  void check_canopy_layout (const amrex::MultiFab& cons, const TwoStreamCanopyView& canopy) const;
353 
354  // The two-stream branches of compute_shortwave() (once the sun is placed) and
355  // compute_longwave(). Public only because a CUDA extended lambda cannot sit in
356  // a private member function; call the two functions above instead.
358  void compute_longwave_two_stream (const amrex::MultiFab& cons, const TwoStreamCanopyView& canopy);
359 
360  /**
361  * Scatter one per-face array into a cell-centred field as the mean over
362  * the faces touching each cell (zero where there are none).
363  */
364  void scatter_field (const amrex::Gpu::DeviceVector<amrex::Real>& v, amrex::MultiFab& out) const;
365 
366  /**
367  * Write every face of this rank to ``<prefix>.rank<N>.csv`` with its
368  * geometry, view fractions, shadow flag, shortwave terms and skin
369  * temperature, for the regression tests and for users who want the raw list.
370  */
371  void dump_faces (const std::string& prefix) const;
372 
373  /**
374  * Scatter the faces into two cell-centred diagnostics for the plotfile.
375  *
376  * @param[out] nfaces Number of wall faces touching each fluid cell (0 away
377  * from buildings; up to 3 at an outside corner, 6 in a
378  * one-cell slot).
379  * @param[out] tskin Mean skin temperature of those faces, 0 where there
380  * are none.
381  *
382  * Both fields must be on the level's box array with no ghost cells. Faces
383  * of one fab are accumulated with atomic adds because a corner cell
384  * receives several faces.
385  */
386  void scatter_diagnostics (amrex::MultiFab& nfaces, amrex::MultiFab& tskin) const;
387 
388  /**
389  * Write the face state (skin temperature, sensible flux and slab
390  * temperatures) into a field from make_state(), for the checkpoint.
391  *
392  * The faces of this rank are written into a transfer field on this
393  * rank's grids cut by the state boxes, which a ParallelCopy moves onto
394  * the state's own distribution. Each face writes its own slot (see
395  * state_ncomp()), so no two faces touch the same component of the same
396  * cell and no atomics are needed; cells without a face in a slot keep
397  * zero there.
398  */
399  void save_state (amrex::MultiFab& state) const;
400 
401  /**
402  * Read the face state (skin, flux, slab) back from a field written by
403  * save_state(), after build() has recreated the list from the blanking:
404  * the reverse ParallelCopy onto the transfer field, then each face reads
405  * its slot. Only the slots that correspond to a face of this list are read.
406  */
407  void load_state (const amrex::MultiFab& state);
408 
409  /**
410  * Print the ``[IBSEB]`` summary line and, when asked, append one row per
411  * building to ``erf.ibseb.csv_file``.
412  *
413  * The summary carries the global face counts per direction, the number of
414  * buildings, the total face area and the range of the skin temperature;
415  * the CSV rows carry per building the face count, the area, the
416  * area-weighted mean fluxes and skin temperature with its range, the
417  * largest balance residual, and the sun the step used, from its start
418  * (zenith, azimuth, direct-normal and diffuse irradiance), on a row
419  * stamped with the time at the end of the step. All numbers are reduced over the
420  * ranks; the file is written by the I/O rank only, with a header only
421  * when the file does not exist yet, so a restarted run appends. Every
422  * level appends to the same file, its rows marked by the level column.
423  * With ``erf.ibseb.dump_faces_file`` the rows come with a face dump,
424  * dump_faces() to ``<prefix>[.levN][.stepNNNNNN].rank<N>.csv``: a refined
425  * level N adds ``.levN`` so it does not overwrite the level below, and
426  * ``erf.ibseb.dump_faces_tag_step`` the step.
427  *
428  * @param time Simulation time [s] written to the rows.
429  * @param step Step number written to the rows.
430  * @param write_csv Whether to append rows, or only print the summary.
431  */
432  void report (amrex::Real time, int step, bool write_csv) const;
433 
434  // ---- Per-face device arrays, indexed by face number ----------------------
435  // Static geometry, set by build():
436  amrex::Gpu::DeviceVector<int> d_i, d_j, d_k; ///< Fluid cell of the face
437  amrex::Gpu::DeviceVector<int> d_dir; ///< Face direction: 0 x, 1 y, 2 z
438  amrex::Gpu::DeviceVector<int> d_side; ///< Solid neighbour at -1 (low) or +1 (high) side
439  amrex::Gpu::DeviceVector<int> d_slot; ///< Slot of the face within its cell's checkpoint record
440  amrex::Gpu::DeviceVector<int> d_bid; ///< Building id (1-based)
441  amrex::Gpu::DeviceVector<int> d_mat; ///< Material id (0 = uniform inputs)
442  amrex::Gpu::DeviceVector<amrex::Real> d_albedo, d_emis;///< Optical properties of the face
443  amrex::Gpu::DeviceVector<amrex::Real> d_kth, d_rhocp, d_thick; ///< Slab conductivity [W/m/K], heat capacity [J/m3/K], thickness [m]
444  amrex::Gpu::DeviceVector<amrex::Real> d_area; ///< Face area [m2]
445  amrex::Gpu::DeviceVector<amrex::Real> d_xf, d_yf, d_zf;///< Face centre [m]
446  // State, advanced by the balance and checkpointed:
447  amrex::Gpu::DeviceVector<amrex::Real> d_T_skin; ///< Skin temperature [K]
448  amrex::Gpu::DeviceVector<amrex::Real> d_T_slab; ///< Slab layers [K], face-major: [face * n_layers + layer]
449  // Static radiative geometry:
450  amrex::Gpu::DeviceVector<amrex::Real> d_f_sky, d_f_ground, d_f_bldg; ///< View fractions, sum to 1
451  // Fluxes of the current step [W/m2]: SW_abs and LW_net positive into the
452  // face, H, LE and G positive out of it:
453  amrex::Gpu::DeviceVector<amrex::Real> d_SW_abs, d_LW_net, d_H, d_LE, d_G;
454  amrex::Gpu::DeviceVector<amrex::Real> d_Q_ext; ///< External incident flux [W/m2], e.g. fire radiation
455  // Shortwave detail, all [W/m2] except the flag:
456  amrex::Gpu::DeviceVector<amrex::Real> d_shadow; ///< 1 when the ray to the sun hits a building, else 0
457  amrex::Gpu::DeviceVector<amrex::Real> d_SW_direct_in; ///< Direct beam incident on the face
458  amrex::Gpu::DeviceVector<amrex::Real> d_SW_diffuse_in; ///< Sky and ground-reflected diffuse incident
459  // Longwave detail [W/m2] and the air temperature read [K]:
460  amrex::Gpu::DeviceVector<amrex::Real> d_LW_down_in; ///< Incoming longwave on the face (sky, ground and walls)
461  amrex::Gpu::DeviceVector<amrex::Real> d_T_air; ///< Air temperature of the fluid cell
462  // Sensible heat detail:
463  amrex::Gpu::DeviceVector<amrex::Real> d_theta_air; ///< Potential temperature of the fluid cell [K]
464  amrex::Gpu::DeviceVector<amrex::Real> d_rho; ///< Density of the fluid cell [kg/m3]
465  amrex::Gpu::DeviceVector<amrex::Real> d_U_tan; ///< Tangential wind speed at the fluid cell [m/s]
466  amrex::Gpu::DeviceVector<amrex::Real> d_ustar; ///< Friction velocity of the wall function [m/s]
467  amrex::Gpu::DeviceVector<amrex::Real> d_H_coeff; ///< H = H_coeff (theta_skin - theta_air) [W/m2/K]
468  // Wall function beyond neutral:
469  amrex::Gpu::DeviceVector<amrex::Real> d_hbld; ///< Height of the face's building column [m]
470  amrex::Gpu::DeviceVector<amrex::Real> d_w_star; ///< Convective velocity scale of the step [m/s]
471  amrex::Gpu::DeviceVector<amrex::Real> d_olen; ///< Obukhov length used [m] (1e30 when neutral)
472  amrex::Gpu::DeviceVector<amrex::Real> d_z_i; ///< Depth in w* [m]: mixed layer above a roof, building height for a wall
473  // Prognostic balance detail:
474  amrex::Gpu::DeviceVector<amrex::Real> d_LW_ext; ///< Incoming longwave from sky and ground only [W/m2]
475  amrex::Gpu::DeviceVector<amrex::Real> d_resid; ///< |balance| after the solve [W/m2]
476  amrex::Gpu::DeviceVector<int> d_niter; ///< Newton iterations of the last solve
477  // Column tops over the bounding box of the built columns (origin
478  // m_col_i0, m_col_j0 in 0-based domain columns, m_col_nx x m_col_ny
479  // values, index (ci - i0) * m_col_ny + (cj - j0)), replicated on every
480  // rank for the ray cast: 4 bytes per built column per rank. Each entry is
481  // the domain-relative k of the highest solid cell of its column, -1 where
482  // the column is fluid; ibseb::column_top() turns it into a height, and
483  // columns outside the box are open ground.
484  amrex::Gpu::DeviceVector<int> d_col_top;
485  int m_col_i0 = 0, m_col_j0 = 0, m_col_nx = 0, m_col_ny = 0;
486 
487  // Checkpoint layout (see state_boxarray()) and the transfer layer of
488  // save_state() / load_state(): this rank's grids cut by the state boxes,
489  // gathered into one global BoxArray owned box by box by the rank whose
490  // grid it came from, with the local grid index each box came from.
491  amrex::BoxArray m_state_ba;
492  amrex::BoxArray m_xfer_ba;
493  amrex::DistributionMapping m_xfer_dm;
494  std::vector<int> m_xfer_src;
495  amrex::Long m_domain_cells = 0; ///< Cells of the level, for the debug summary of the field
496 
497  /// Sun and irradiances of the last compute_shortwave() call, for reports.
498  struct SunState {
499  amrex::Real zenith = 0.0, azimuth = 0.0; ///< [rad]
500  amrex::Real sx = 0.0, sy = 0.0, sz = 1.0; ///< Unit vector toward the sun
501  amrex::Real dni = 0.0; ///< Direct-normal irradiance [W/m2]
502  amrex::Real diffuse_h = 0.0; ///< Diffuse on a horizontal surface [W/m2]
503  };
504  const SunState& sun () const { return m_sun; }
505 
506  /**
507  * Print the ``[IBSEB DEBUG]`` description of the set: the inputs, every
508  * rank's face count and per-fab ranges, the buildings with their footprint
509  * columns and bounding boxes, and the device memory of the arrays.
510  * Called once from build() when ``erf.ibseb.debug`` is set.
511  */
512  void print_debug_summary () const;
513 
514  /** Add the wall-clock time of one per-step update of this rank, for the cost line of report(). */
515  void add_cost (double seconds) { m_cost_s += seconds; ++m_cost_n; }
516  /** Record the wall-clock time of the initialisation (build and view fractions). */
517  void set_init_cost (double seconds) { m_init_cost_s = seconds; }
518 
519  /**
520  * First face of each local fab in MFIter order; size number of fabs + 1.
521  * Faces ``fab_start()[n]`` to ``fab_start()[n+1]-1`` belong to the fab with
522  * local index ``n``, which is what the scatter kernels rely on.
523  */
524  const std::vector<int>& fab_start () const { return m_fab_start; }
525 
526 private:
527  IBSEBParams m_params; ///< Copy of the inputs
528  int m_lev = 0; ///< AMR level, for reports
529  int m_nface = 0; ///< Faces owned by this rank
530  int m_nslots = 0; ///< Slots per cell of the checkpoint field (largest face count on a cell)
531  int m_top_sample = -1; ///< Highest interface a face samples, over all ranks (-1: no faces)
532  int m_nbld = 0; ///< Buildings of the level (global)
533  std::vector<int> m_fab_start; ///< See fab_start()
534 
535  // Static totals over all ranks, computed once in build(); building index 0 unused.
536  std::vector<amrex::Long> m_bld_nface; ///< Faces per building
537  std::vector<amrex::Real> m_bld_area; ///< Face area per building [m2]
538  amrex::Long m_nface_dir[3] = {0, 0, 0}; ///< Faces per direction
539  amrex::Real m_area_total = 0.0; ///< Total face area [m2]
540  // Footprint of each building (global): columns, and bounding box in cell indices.
541  std::vector<amrex::Long> m_bld_ncol;
542  std::vector<int> m_bld_ilo, m_bld_ihi, m_bld_jlo, m_bld_jhi;
543  // Level-0 numbering (map_buildings_to_level0()): the level-0 id of each
544  // building of this level (identity on level 0), and the column labels over
545  // the level's own built bounding box, kept until the level above has been
546  // mapped.
547  std::vector<int> m_to_lev0;
548  std::vector<int> m_lab;
549  int m_lab_i0 = 0, m_lab_j0 = 0, m_lab_nx = 0, m_lab_ny = 0;
550 
551  // Geometry kept for the ray cast and the reports.
552  int m_nx = 0, m_ny = 0; ///< Columns of the domain
553  amrex::IntVect m_dom_lo{AMREX_D_DECL(0, 0, 0)}; ///< Low corner of the level's domain
554  amrex::Real m_x_lo = 0.0, m_y_lo = 0.0; ///< Domain origin [m]
555  amrex::Real m_dx[3] = {0.0, 0.0, 0.0}; ///< Cell sizes [m]
556  bool m_per_x = false, m_per_y = false; ///< Periodicity in x and y
557  amrex::Real m_col_top_max = 0.0; ///< Tallest column [m]
558  amrex::Real m_z_ground = 0.0; ///< Ground height [m] (flat, the domain bottom)
559  amrex::Real m_max_path = 0.0; ///< Ray path cap [m]
561  /// The two-stream sun of the next compute_shortwave() (sun_mode = two_stream).
562  struct TwoStreamSun { bool set = false; amrex::Real decl = 0.0, hour_angle = 0.0, lat_deg = 0.0, S0 = 0.0; };
564  double m_cost_s = 0.0; ///< Wall-clock seconds spent in the per-step update on this rank
565  amrex::Long m_cost_n = 0; ///< Number of per-step updates timed
566  double m_init_cost_s = 0.0; ///< Wall-clock seconds of build() and compute_view_fractions()
567 };
568 
569 #endif
Material library of the building faces.
Inputs of the immersed-boundary surface energy balance (erf.ibseb.*).
const Real rdOcp
Definition: ERF_InitCustomPert_ABL.H:72
amrex::Real Real
Definition: ERF_ShocInterface.H:19
What the two-stream sweep hands the building faces of the immersed-boundary surface energy balance (e...
Definition: ERF_IBFaceSet.H:71
int m_lev
AMR level, for reports.
Definition: ERF_IBFaceSet.H:528
void save_state(amrex::MultiFab &state) const
Definition: ERF_IBFaceSet.cpp:1546
amrex::Gpu::DeviceVector< amrex::Real > d_resid
|balance| after the solve [W/m2]
Definition: ERF_IBFaceSet.H:475
amrex::Gpu::DeviceVector< amrex::Real > d_theta_air
Potential temperature of the fluid cell [K].
Definition: ERF_IBFaceSet.H:463
void dump_faces(const std::string &prefix) const
Definition: ERF_IBFaceSet.cpp:1414
void release_labels()
Definition: ERF_IBFaceSet.H:163
std::vector< int > m_bld_jhi
Definition: ERF_IBFaceSet.H:542
amrex::Gpu::DeviceVector< amrex::Real > d_hbld
Height of the face's building column [m].
Definition: ERF_IBFaceSet.H:469
int state_ncomp() const
Definition: ERF_IBFaceSet.H:189
int m_nslots
Slots per cell of the checkpoint field (largest face count on a cell)
Definition: ERF_IBFaceSet.H:530
int m_ny
Columns of the domain.
Definition: ERF_IBFaceSet.H:552
amrex::Gpu::DeviceVector< amrex::Real > d_shadow
1 when the ray to the sun hits a building, else 0
Definition: ERF_IBFaceSet.H:456
double m_cost_s
Wall-clock seconds spent in the per-step update on this rank.
Definition: ERF_IBFaceSet.H:564
amrex::Gpu::DeviceVector< amrex::Real > d_yf
Definition: ERF_IBFaceSet.H:445
std::vector< int > m_xfer_src
Definition: ERF_IBFaceSet.H:494
amrex::Gpu::DeviceVector< int > d_col_top
Definition: ERF_IBFaceSet.H:484
amrex::Gpu::DeviceVector< amrex::Real > d_thick
Slab conductivity [W/m/K], heat capacity [J/m3/K], thickness [m].
Definition: ERF_IBFaceSet.H:443
amrex::Gpu::DeviceVector< int > d_k
Fluid cell of the face.
Definition: ERF_IBFaceSet.H:436
amrex::Real m_max_path
Ray path cap [m].
Definition: ERF_IBFaceSet.H:559
amrex::Gpu::DeviceVector< amrex::Real > d_H
Definition: ERF_IBFaceSet.H:453
bool has_state() const
Definition: ERF_IBFaceSet.H:206
std::vector< amrex::Long > m_bld_ncol
Definition: ERF_IBFaceSet.H:541
amrex::Gpu::DeviceVector< amrex::Real > d_albedo
Definition: ERF_IBFaceSet.H:442
amrex::Gpu::DeviceVector< amrex::Real > d_SW_abs
Definition: ERF_IBFaceSet.H:453
const std::vector< int > & fab_start() const
Definition: ERF_IBFaceSet.H:524
int building_level0(int b) const
Definition: ERF_IBFaceSet.H:160
amrex::Real m_col_top_max
Tallest column [m].
Definition: ERF_IBFaceSet.H:557
amrex::DistributionMapping m_xfer_dm
Definition: ERF_IBFaceSet.H:493
void compute_longwave_two_stream(const amrex::MultiFab &cons, const TwoStreamCanopyView &canopy)
Definition: ERF_IBFaceSet.cpp:766
amrex::Gpu::DeviceVector< int > d_mat
Material id (0 = uniform inputs)
Definition: ERF_IBFaceSet.H:441
void print_debug_summary() const
Definition: ERF_IBFaceSet.cpp:1472
void compute_view_fractions()
Definition: ERF_IBFaceSet.cpp:661
amrex::Gpu::DeviceVector< amrex::Real > d_LW_ext
Incoming longwave from sky and ground only [W/m2].
Definition: ERF_IBFaceSet.H:474
int m_col_i0
Definition: ERF_IBFaceSet.H:485
const SunState & sun() const
Definition: ERF_IBFaceSet.H:504
IBFaceSet(const IBSEBParams &params, int lev)
Definition: ERF_IBFaceSet.H:78
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)
Definition: ERF_IBFaceSet.cpp:1010
bool m_per_x
Definition: ERF_IBFaceSet.H:556
amrex::Long m_nface_dir[3]
Faces per direction.
Definition: ERF_IBFaceSet.H:538
std::vector< int > m_bld_jlo
Definition: ERF_IBFaceSet.H:542
std::vector< int > m_to_lev0
Definition: ERF_IBFaceSet.H:547
amrex::Gpu::DeviceVector< amrex::Real > d_w_star
Convective velocity scale of the step [m/s].
Definition: ERF_IBFaceSet.H:470
amrex::Gpu::DeviceVector< amrex::Real > d_area
Face area [m2].
Definition: ERF_IBFaceSet.H:444
void compute_shortwave_two_stream(const TwoStreamCanopyView &canopy)
Definition: ERF_IBFaceSet.cpp:1286
amrex::Gpu::DeviceVector< amrex::Real > d_rho
Density of the fluid cell [kg/m3].
Definition: ERF_IBFaceSet.H:464
amrex::Gpu::DeviceVector< amrex::Real > d_T_skin
Skin temperature [K].
Definition: ERF_IBFaceSet.H:447
amrex::Gpu::DeviceVector< amrex::Real > d_LW_net
Definition: ERF_IBFaceSet.H:453
amrex::Gpu::DeviceVector< amrex::Real > d_emis
Optical properties of the face.
Definition: ERF_IBFaceSet.H:442
amrex::Gpu::DeviceVector< amrex::Real > d_z_i
Depth in w* [m]: mixed layer above a roof, building height for a wall.
Definition: ERF_IBFaceSet.H:472
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
Definition: ERF_IBFaceSet.cpp:1132
amrex::BoxArray m_xfer_ba
Definition: ERF_IBFaceSet.H:492
void compute_ground(amrex::Real dt)
Definition: ERF_IBFaceSet.cpp:899
void solve_balance(amrex::Real dt)
Definition: ERF_IBFaceSet.cpp:927
amrex::Gpu::DeviceVector< int > d_side
Solid neighbour at -1 (low) or +1 (high) side.
Definition: ERF_IBFaceSet.H:438
SunState m_sun
Definition: ERF_IBFaceSet.H:560
int m_top_sample
Highest interface a face samples, over all ranks (-1: no faces)
Definition: ERF_IBFaceSet.H:531
std::vector< amrex::Real > m_bld_area
Face area per building [m2].
Definition: ERF_IBFaceSet.H:537
void build(const amrex::MultiFab &blanking, const amrex::Geometry &geom)
Definition: ERF_IBFaceSet.cpp:94
amrex::Gpu::DeviceVector< int > d_niter
Newton iterations of the last solve.
Definition: ERF_IBFaceSet.H:476
amrex::Gpu::DeviceVector< amrex::Real > d_SW_diffuse_in
Sky and ground-reflected diffuse incident.
Definition: ERF_IBFaceSet.H:458
amrex::Gpu::DeviceVector< amrex::Real > d_f_sky
Definition: ERF_IBFaceSet.H:450
amrex::Gpu::DeviceVector< amrex::Real > d_olen
Obukhov length used [m] (1e30 when neutral)
Definition: ERF_IBFaceSet.H:471
amrex::Real m_z_ground
Ground height [m] (flat, the domain bottom)
Definition: ERF_IBFaceSet.H:558
amrex::Gpu::DeviceVector< int > d_dir
Face direction: 0 x, 1 y, 2 z.
Definition: ERF_IBFaceSet.H:437
amrex::Gpu::DeviceVector< amrex::Real > d_f_bldg
View fractions, sum to 1.
Definition: ERF_IBFaceSet.H:450
void check_canopy_layout(const amrex::MultiFab &cons, const TwoStreamCanopyView &canopy) const
Definition: ERF_IBFaceSet.cpp:815
double m_init_cost_s
Wall-clock seconds of build() and compute_view_fractions()
Definition: ERF_IBFaceSet.H:566
bool has_faces() const
Definition: ERF_IBFaceSet.H:344
std::vector< int > m_lab
Definition: ERF_IBFaceSet.H:548
std::vector< int > m_bld_ilo
Definition: ERF_IBFaceSet.H:542
amrex::Gpu::DeviceVector< int > d_slot
Slot of the face within its cell's checkpoint record.
Definition: ERF_IBFaceSet.H:439
amrex::Long m_cost_n
Number of per-step updates timed.
Definition: ERF_IBFaceSet.H:565
TwoStreamSun m_ts_sun
Definition: ERF_IBFaceSet.H:563
void map_buildings_to_level0(const IBFaceSet &coarser, const amrex::IntVect &ratio)
Definition: ERF_IBFaceSet.cpp:607
const amrex::BoxArray & state_boxarray() const
Definition: ERF_IBFaceSet.H:204
amrex::Gpu::DeviceVector< amrex::Real > d_T_slab
Slab layers [K], face-major: [face * n_layers + layer].
Definition: ERF_IBFaceSet.H:448
int m_col_ny
Definition: ERF_IBFaceSet.H:485
int n_layers() const
Definition: ERF_IBFaceSet.H:170
void scatter_diagnostics(amrex::MultiFab &nfaces, amrex::MultiFab &tskin) const
Definition: ERF_IBFaceSet.cpp:1507
amrex::Real m_y_lo
Domain origin [m].
Definition: ERF_IBFaceSet.H:554
amrex::Gpu::DeviceVector< amrex::Real > d_SW_direct_in
Direct beam incident on the face.
Definition: ERF_IBFaceSet.H:457
int n_slots() const
Definition: ERF_IBFaceSet.H:192
void compute_longwave(const amrex::MultiFab &cons, const TwoStreamCanopyView &canopy=TwoStreamCanopyView{})
Definition: ERF_IBFaceSet.cpp:715
void add_cost(double seconds)
Definition: ERF_IBFaceSet.H:515
int n_buildings() const
Definition: ERF_IBFaceSet.H:168
amrex::BoxArray m_state_ba
Definition: ERF_IBFaceSet.H:491
int m_lab_ny
Definition: ERF_IBFaceSet.H:549
void add_outside_occluders(const IBFaceSet &coarser, const amrex::IntVect &ratio, const amrex::BoxArray &grids_crse)
Definition: ERF_IBFaceSet.cpp:525
amrex::Long m_domain_cells
Cells of the level, for the debug summary of the field.
Definition: ERF_IBFaceSet.H:495
amrex::Gpu::DeviceVector< amrex::Real > d_G
Definition: ERF_IBFaceSet.H:453
void scatter_field(const amrex::Gpu::DeviceVector< amrex::Real > &v, amrex::MultiFab &out) const
Definition: ERF_IBFaceSet.cpp:1385
amrex::Gpu::DeviceVector< amrex::Real > d_T_air
Air temperature of the fluid cell.
Definition: ERF_IBFaceSet.H:461
int m_nface
Faces owned by this rank.
Definition: ERF_IBFaceSet.H:529
int top_sample_interface() const
Definition: ERF_IBFaceSet.H:341
amrex::Gpu::DeviceVector< amrex::Real > d_Q_ext
External incident flux [W/m2], e.g. fire radiation.
Definition: ERF_IBFaceSet.H:454
amrex::MultiFab make_state() const
Definition: ERF_IBFaceSet.cpp:1539
amrex::Real m_area_total
Total face area [m2].
Definition: ERF_IBFaceSet.H:539
int n_faces() const
Definition: ERF_IBFaceSet.H:166
int m_lab_nx
Definition: ERF_IBFaceSet.H:549
bool m_per_y
Periodicity in x and y.
Definition: ERF_IBFaceSet.H:556
amrex::Gpu::DeviceVector< amrex::Real > d_f_ground
Definition: ERF_IBFaceSet.H:450
amrex::Gpu::DeviceVector< int > d_j
Definition: ERF_IBFaceSet.H:436
void set_init_cost(double seconds)
Definition: ERF_IBFaceSet.H:517
int m_nx
Definition: ERF_IBFaceSet.H:552
void report(amrex::Real time, int step, bool write_csv) const
Definition: ERF_IBFaceSet.cpp:1631
amrex::Gpu::DeviceVector< int > d_bid
Building id (1-based)
Definition: ERF_IBFaceSet.H:440
amrex::Gpu::DeviceVector< amrex::Real > d_LE
Definition: ERF_IBFaceSet.H:453
void load_state(const amrex::MultiFab &state)
Definition: ERF_IBFaceSet.cpp:1586
std::vector< int > m_fab_start
See fab_start()
Definition: ERF_IBFaceSet.H:533
int m_lab_j0
Definition: ERF_IBFaceSet.H:549
amrex::Gpu::DeviceVector< amrex::Real > d_H_coeff
H = H_coeff (theta_skin - theta_air) [W/m2/K].
Definition: ERF_IBFaceSet.H:467
int m_nbld
Buildings of the level (global)
Definition: ERF_IBFaceSet.H:532
amrex::Real m_dx[3]
Cell sizes [m].
Definition: ERF_IBFaceSet.H:555
void assign_materials()
Definition: ERF_IBFaceSet.cpp:849
amrex::Gpu::DeviceVector< amrex::Real > d_xf
Definition: ERF_IBFaceSet.H:445
void set_two_stream_sun(amrex::Real declination, amrex::Real hour_angle, amrex::Real latitude_deg, amrex::Real toa_irradiance)
Definition: ERF_IBFaceSet.H:132
amrex::Gpu::DeviceVector< amrex::Real > d_zf
Face centre [m].
Definition: ERF_IBFaceSet.H:445
IBSEBParams m_params
Copy of the inputs.
Definition: ERF_IBFaceSet.H:527
void compute_shortwave(amrex::Real time, const TwoStreamCanopyView &canopy=TwoStreamCanopyView{})
Definition: ERF_IBFaceSet.cpp:1176
std::vector< amrex::Long > m_bld_nface
Faces per building.
Definition: ERF_IBFaceSet.H:536
amrex::Gpu::DeviceVector< amrex::Real > d_LW_down_in
Incoming longwave on the face (sky, ground and walls)
Definition: ERF_IBFaceSet.H:460
int m_col_j0
Definition: ERF_IBFaceSet.H:485
amrex::IntVect m_dom_lo
Low corner of the level's domain.
Definition: ERF_IBFaceSet.H:553
std::vector< int > m_bld_ihi
Definition: ERF_IBFaceSet.H:542
amrex::Real m_x_lo
Definition: ERF_IBFaceSet.H:554
amrex::Gpu::DeviceVector< amrex::Real > d_rhocp
Definition: ERF_IBFaceSet.H:443
int m_col_nx
Definition: ERF_IBFaceSet.H:485
amrex::Gpu::DeviceVector< int > d_i
Definition: ERF_IBFaceSet.H:436
amrex::Gpu::DeviceVector< amrex::Real > d_ustar
Friction velocity of the wall function [m/s].
Definition: ERF_IBFaceSet.H:466
amrex::Gpu::DeviceVector< amrex::Real > d_kth
Definition: ERF_IBFaceSet.H:443
amrex::Gpu::DeviceVector< amrex::Real > d_U_tan
Tangential wind speed at the fluid cell [m/s].
Definition: ERF_IBFaceSet.H:465
int m_lab_i0
Definition: ERF_IBFaceSet.H:549
@ xvel
Definition: ERF_IndexDefines.H:218
@ cons
Definition: ERF_IndexDefines.H:217
@ zvel
Definition: ERF_IndexDefines.H:220
@ yvel
Definition: ERF_IndexDefines.H:219
Sun and irradiances of the last compute_shortwave() call, for reports.
Definition: ERF_IBFaceSet.H:498
amrex::Real diffuse_h
Diffuse on a horizontal surface [W/m2].
Definition: ERF_IBFaceSet.H:502
amrex::Real dni
Direct-normal irradiance [W/m2].
Definition: ERF_IBFaceSet.H:501
amrex::Real zenith
Definition: ERF_IBFaceSet.H:499
amrex::Real sy
Definition: ERF_IBFaceSet.H:500
amrex::Real sx
Definition: ERF_IBFaceSet.H:500
amrex::Real azimuth
[rad]
Definition: ERF_IBFaceSet.H:499
amrex::Real sz
Unit vector toward the sun.
Definition: ERF_IBFaceSet.H:500
The two-stream sun of the next compute_shortwave() (sun_mode = two_stream).
Definition: ERF_IBFaceSet.H:562
amrex::Real lat_deg
Definition: ERF_IBFaceSet.H:562
amrex::Real S0
Definition: ERF_IBFaceSet.H:562
amrex::Real decl
Definition: ERF_IBFaceSet.H:562
amrex::Real hour_angle
Definition: ERF_IBFaceSet.H:562
bool set
Definition: ERF_IBFaceSet.H:562
Definition: ERF_IBSEBParams.H:25
int n_slab_layers
Conduction layers per face.
Definition: ERF_IBSEBParams.H:27
The fields a level's faces read for one step: the beam and the cosine of the zenith the sweep of that...
Definition: ERF_TwoStreamCanopyForcing.H:45