:py:mod:`wolfgpu.glsimulation` ============================== .. py:module:: wolfgpu.glsimulation .. autoapi-nested-parse:: Author: HECE - University of Liege, Stéphane Champailler, Pierre Archambeau Date: 2024 Copyright (c) 2024 University of Liege. All rights reserved. This script and its content are protected by copyright law. Unauthorized copying or distribution of this file, via any medium, is strictly prohibited. Module Contents --------------- .. py:data:: FINISH :value: False .. py:data:: TIME_SAMPLING_RESOLUTION :value: 100 .. py:data:: DEFAULT_TILE_SIZE :value: 16 .. py:data:: STRIPES_ON_NAP :value: True .. py:data:: WET_TILES_DETECT_THREAD_WIDTH :value: 4 .. py:data:: GLOBALS_STRUCT_PACK_FORMAT :value: 'ddfLLLLLLL' .. py:data:: MAXIMUM_TIME_STEP :value: 1.0 .. py:data:: MESH_WITHOUT_INFILTRATION .. py:data:: ALPHA_VALUE_NDX :value: 0 .. py:data:: ALPHA_FLAGS_NDX :value: 1 .. py:data:: PARTS_QUADS :value: 1 .. py:data:: PARTS_STRIPES :value: 2 .. py:data:: MEM_TRACKING .. py:data:: MEM_TRACKING :value: False .. py:data:: _root_dir .. py:data:: _perf_counters .. py:function:: time_it(msg: str = None) -> Iterator[None] .. py:data:: _gl_perf_counters .. py:data:: _timers .. py:function:: time_it_gl(msg: str = None) -> Iterator[None] .. py:data:: _query_id .. py:function:: test_query_timer() .. py:function:: test_query_timer_end() .. py:data:: _gl_queries_full .. py:function:: time_it_full(msg: str = None) -> Iterator[None] .. py:function:: finish_timings() .. py:data:: _perf_counters_full .. py:function:: finish_timings_full() .. py:function:: gl_timings_results(figname) .. py:function:: gl_timings_results_full() .. py:function:: log_mem_used(msg=None) .. py:class:: TileOptimisation Bases: :py:obj:`enum.Enum` .. autoapi-inheritance-diagram:: wolfgpu.glsimulation.TileOptimisation :parts: 1 :private-bases: Generic enumeration. Derive from this class to define new enumerations. .. py:attribute:: COMPUTE_SHADER :value: 1 .. py:attribute:: REGULAR_SHADER :value: 2 .. py:data:: SHADER_PATH .. py:function:: make_quad_fast(xmin, xmax, ymin, ymax) .. py:function:: round_to_tile(x, round_func, tsize: int) .. py:function:: shrink_array_by_two(a) Cut array in 2. A 5x5 array will be cut to a 3x3 (notiece the rounding) .. py:function:: divide_shape(shape) .. py:function:: integer_div(a, b) .. py:function:: find_active_tiles(a, tile_size=DEFAULT_TILE_SIZE) .. py:function:: isPowerOfTwo(x) .. py:function:: find_stripes(a, rw, rh, tile_w, tile_h, with_dilatation=True) Find stripes on a. Elements of a different than zero are the ones taken into account. There's one stripe per line of the array ! Please note that the stripes coordinates will be in NDC (normalized device coordinate, see OpenGL) over the array (that is, they're in [-1,+1] regardless of the size of the array) .. py:function:: find_non_empty_tiles_on_nap(nap: wolfgpu.gl_utils.np.ndarray, n: int) Tiles on NAP are used to guide the first level of computation, that is at the maximum detail level. After that level, one uses stripes which will be dynamically adjusted to water coverage. Tiles on NAP are not meant to change over the course of the simulation. .. py:class:: GLSimulationGlobalState(simulation_time, previous_step_simulation_time, time_step, active_infiltration_line, nb_dryup_iterations, nb_active_tiles, status_code, total_active_tiles, infiltration_zones, simulation_step, step_times) .. py:property:: nb_active_tiles .. py:attribute:: simulation_step :type: int Simulation current step. .. py:class:: GLSimulation(width, height, ponderation_runge_kutta: float = 0.3, dx: float = 1.0, dy: float = 1.0, courant: float = 0.1, froude_max: float = 10.0, time_step_strategy=TimeStepStrategy.OPTIMIZED_TIME_STEP, time_step: float = 1.0, max_steps=SimulationDuration.from_seconds(10), report_frequency=SimulationDuration.from_steps(10), basefilename: str = 'simul', tile_size=DEFAULT_TILE_SIZE, shader_log_path: wolfgpu.gl_utils.Path = None, tile_packing_mode: wolfgpu.tile_packer.TilePackingMode = TilePackingMode.REGULAR, optimized_indirection: bool = False) OpenGL simulation. Can be initialized from scractch, with SimpleSimulation or PrevWOLF2D CPU model. This class can be used in a runner, which will call the simulation step method at each frame. The simulation step method will update the simulation state and draw the simulation on the screen. .. py:property:: froude_bc_tolerance :type: float Get the Froude BC tolerance. .. py:property:: infiltration_interpolation :type: wolfgpu.simple_simulation.InfiltrationInterpolation Get the infiltration interpolation mode. .. py:property:: nbx Get the width of the simulation domain. Useful for interoperability with wolfhece package. .. py:property:: nby Get the height of the simulation domain. Useful for interoperability with wolfhece package. .. py:property:: debugging_mode :type: bool Get the debugging mode. .. py:property:: tile_size Get the tile size. .. py:property:: optimize_tile_indirection .. py:property:: total_number_of_dry_up_outer_loops .. py:method:: set_params(width, height, ponderation_runge_kutta: float = 0.3, dx: float = 1.0, dy: float = 1.0, courant: float = 0.1, froude_max: float = 10.0, time_step_strategy=TimeStepStrategy.OPTIMIZED_TIME_STEP, time_step: float = None, simulation_duration=SimulationDuration.from_seconds(10), report_frequency=SimulationDuration.from_steps(10), basefilename: str = 'simul', tile_size=DEFAULT_TILE_SIZE, infiltration_interpolation: wolfgpu.simple_simulation.InfiltrationInterpolation = InfiltrationInterpolation.NONE, tile_packing_mode: wolfgpu.tile_packer.TilePackingMode = TilePackingMode.REGULAR, optimized_indirection=False, track_flows_at_borders=False) .. py:method:: set_track_flows_at_borders(v: bool) Track fluxes at borders. This can be used to properly compute discharge across sections without recalculation of these fluxes from cell-centered values/unknowns. .. py:method:: force_max_step_size(s: float) Prevents the max step size computation. :param s: Maximum step size [s]. Pass None to re-enable the computation. Used in test/debug. .. py:method:: set_ensure_positive_height(b: bool) Enable or disable positive height enforcment. Used in debugging/testing .. py:method:: set_g(g: float = 9.81) Set gravity. :param g: gravity in m/s^2 .. py:method:: set_froude_limit(l: float) :param l: Froude max [-]. If None, then we turn off froude limitation. .. py:method:: set_froude_bc_tolerance(l: float = 1.0) Set the tolerance for the Froude number at the boundaries. If toleranceis 1.0, then the boundary condition impose the minimum of the water height computed based on the Froude number and the water height inside the computed domain. If tolerance is greater than 1.0, then the water height inside the domain is multiplied by the tolerance before applying the minimum operator. It could be useful if the water height inside the domain is too low and the regime is (near) supercritical that is not theoretically correct if we want to impose a BC at this position. In subcritical regime, usually, it is not a problem. :param l: tolerance >= 1.0 .. py:method:: set_fixed_time_step(d: float) Set a fixed time step. :param d: time step in seconds. .. py:method:: set_report_frequency(d: wolfgpu.simple_simulation.SimulationDuration) Set the report frequency in seconds or iterations. :type d: SimulationDuration. .. py:method:: set_simulation_duration(d: wolfgpu.simple_simulation.SimulationDuration) Set the simulation duration in seconds or iterations. :type d: SimulationDuration. .. py:method:: set_courant(c: float) Set the Courant number. :param c: Courant number [-]. :type c: float .. py:method:: set_euler_ponderation() Force Euler temporal scheme. Disable Runge Kutta. .. py:method:: set_rk_ponderation(p: float) Set the predictor's ponderation of the Runge Kutta 2x scheme. A RK22 scheme is obtained by setting p=0.5. A RK21 scheme is obtained by setting p=0.3. For compatibility with previous WOLF2D CPU model, we accept p > 1.0 (like 3.). In this case, the runner will correct the value and will apply the RK21 scheme with a ponderation of 0.3. :param p: ponderation [0,1]. :type p: float .. py:method:: set_infiltration_interpolation(lerp: wolfgpu.simple_simulation.InfiltrationInterpolation) Set the infiltration interpolation mode (stepwise or linear interpolation). :param lerp: interpolation mode. :type lerp: InfiltrationInterpolation .. py:method:: set_debug(dbg: bool) Record more data in results and activate debug textures. :attention: Make sure to call this before everything else. .. py:method:: set_tiles_packing_mode(mode: wolfgpu.tile_packer.TilePackingMode) Set the tiles packing mode (TRANSPARENT or REGULAR). Transparent mode will not pack the tiles in a regular grid but will use the tiles as they are. This is useful for debugging purposes or small models. :attention: This mode has **no impact** on the simulation results. Some unit tests are performed o ensure that the simulation results are the same in both modes. :param mode: packing mode. :type mode: TilePackingMode .. py:method:: set_tile_size(tile_size: int) Set the tile size. :param tile_size: tile size in number of cells (must be a power of 2). :type tile_size: int .. py:method:: set_optim_geom_shaders(enable) FIXME: document this routine ?? .. py:method:: set_total_number_of_dry_up_outer_loops(n) Configure the number of desired iterations to solve all or some of the dry ups. :param n: Number of iterations: * n == 0 means no dry up (only Euler/RK) * n > 0 means a *fixed* number of dry up iterations * None means as many dry up iterations as needed to solve all dry ups :type n: None or int. .. py:method:: set_no_dry(dummy) DEPRECATED !!! .. py:method:: emergency_save() .. py:method:: tile_packer() -> wolfgpu.tile_packer.TilePacker .. py:method:: dry_up_disabled() .. py:method:: _load_shaders() Load the shaders on the GPU. .. py:method:: compute_time_step_for_tiles_phase1(current_quantity) Phase 1 of computing the minimum time step for the simulation. It consists of computing one minimum for each tile (the second phase will compute the minium across tiles). :param current_quantity: The quantity index for which we compute the time step. :type current_quantity: int The current_quantity can be 0 or 1. It's the index of the quantity in the quantity textures. The minimum time step is computed for each tile and will be stored in the tiles_mins texture. .. py:method:: compute_time_step_for_tiles_phase2() Phase 2: reduce the matrix of minimums. No need to pass argument while the Phase 1 has already set the minimums in the tiles_mins texture. .. py:method:: compute_max_step_size2() .. py:method:: drop_gl_resources() Delete all the OpenGL resources. .. py:method:: reset_size(width: int, height: int) Reset the size of the simulation. :attention: Used in tests .. py:method:: complete_textures() After having set several data textures, call this to upload blank texture replacement for those you didn't set. and to recompute the framebuffers and create additional textures necessary to the computation. We are using some routines from gl_utils.py like: - upload_blank_texture_to_gpu - upload_np_array_to_gpu - create_frame_buffer_for_computation .. py:method:: _create_debugging_textures() Create textures for debugging purposes. Even if we used Framebuffers for debugging, we now use textures because it is more easy to download them to the CPU. .. py:method:: _gen_single_quad() #FIXME DOC ? .. py:method:: _has_good_shape(a: wolfgpu.gl_utils.np.ndarray) .. py:method:: set_buffers(max_step_size=None, strong_bc_array=None, strong_bc_values_array=None, quantity_arrays=None, bathymetry_array=None, manning_array=None, active_meshes_array=None, weak_bc_array=None, bc_cells_array=None, infiltration_zones_array=None, infiltration_timings=None) .. py:method:: _clear_global_variables_buffer(sim_time, time_step) .. py:method:: reset_globals(sim_time, time_step, step_num, h, qx, qy) :param time_step: the duration of the time step (in case you have a fixed time step) :param step_num: The step number of the next computed simulation step. .. py:method:: compute_derivative_with_dry_up_and_euler(current_quantity_tex_ndx: int, euler_base_quantity_tex_ndx: int, quantity_out_tex_ndx: int, current_alpha_tex_ndx=0, ignore_alpha=False) .. py:method:: compute_derivative_with_dry_up_and_rk(current_quantity_tex_ndx: int, predictor_quantity_tex_ndx: int, quantity_out_tex_ndx: int, current_alpha_tex_ndx=0, ignore_alpha=False) .. py:method:: detect_wet_tiles2(current_quantity: int) Detect wet tiles FIXME we also call them active but that a misnomer because active also means NAP-active... .. py:method:: _handle_dry_up_iterations(program) .. py:method:: simulation_step(source_quantity: int) Perform a full simulation step (with all substeps: euler, RK,...) :param source_quantity: is 0 or 1 and tells in which of the ping/pong textures we'll *read* information. Consequently, we'll *write* into `1 - source_quantity`. :type source_quantity: int .. py:method:: _tiles_ndc_dims() .. py:method:: filter_low_water(current_quantity_tex_ndx: int, euler_base_quantity_tex_ndx: int, quantity_out_tex_ndx: int, current_alpha_tex_ndx=0, ignore_alpha=False) .. py:method:: _draw_active_tiles(program, uniforms: dict, textures: dict, viewport=None) Draw the active tiles .. py:method:: plot_progress(current_quantity, zoom=1.0, mean=0.5, flip=True, gl_window_viewport=(0, 0, 100, 100)) .. py:method:: active_infiltration_line(t: float) -> int Compute the active infiltration event number (or line in the array) at time t. The event number is one based. Returns 0 if none is active. .. py:method:: _infiltrations_timings_as_gpu_array(nb_cells_per_zone, infiltrations_chronology: wolfgpu.simple_simulation.InfiltrationChronology) .. py:method:: read_euler_step_result(tex=2) Returns a 3D array (q, qu, qv) .. py:method:: read_debug_texture(tex=0) .. py:method:: read_infiltration_map() .. py:method:: has_infiltration_chronology() -> bool .. py:method:: read_infiltration_chronology() .. py:method:: read_flows_on_borders(which: int) Read flows on borders. Each cell of the returned arrays contains: (q_left, q_right, q_top, q_bottom). Used only while debugging :param which: 0 for Euler, 1 for Runge Kutta. .. py:method:: read_rhs() Read RHS at Euler step or RK step (make sure you know which one is valid when). Each cell of the returned arrays contains: (q_left, q_right, q_top, q_bottom). Used only while debugging .. py:method:: read_quantity_result(current_quantity) -> wolfgpu.gl_utils.np.array Returns the matrix of quantities (h,qx,qy), unpacked. Used for debugging. Prefer the ResultStore. :param current_quantity: is 0,1 for the flip flop textures and 2 for the intermediate euler resul (if one uses Runge-Kutta). .. py:method:: _read_full_quantity_result(current_quantity) -> wolfgpu.gl_utils.np.array Returns the matrix of quantities (h,qx,qy, UNSPECIFIED), unpacked. :param current_quantity: is 0,1 for the flip flop textures and 2 for the intermediate euler resul (if one uses Runge-Kutta). .. py:method:: read_tile_packed_quantity_result(current_quantity) Returns the matrix of quantities (h,qx,qy), "tile-packed". .. py:method:: read_bathymetry() Returns the current bathymetry, "tile-_un_packed". .. py:method:: read_alpha(current_quantity) Returns the matrix of alpha-correction (dry ups), "tile-_un_packed". .. py:method:: read_tile_packed_alpha(current_quantity) Returns the matrix of alpha-correction (dry ups), "tile-packed". .. py:method:: read_active_cells_map() Read active cells map. NOTE ! Be ware that this map is "packed" (as in tile packing) .. py:method:: read_tile_min_step_size() The last computed minimum step size. This is only valid after the first phase of the computation of the time steps (the second phase reuse the texture for a reduction). .. py:method:: read_weak_bcs() .. py:method:: read_bcs_descriptions() -> wolfgpu.gl_utils.np.ndarray Read the boundary conditions descriptions from the texture boundary_cond_cells_tex. .. py:method:: read_global_state() -> GLSimulationGlobalState Read the global state variables of the simulation, as reported by the shaders in the GPU. Be aware that this implies reading information from the GPU which usually leads to a huge drop in performance (up to 50% !!!). :return: simulation_time, time_step, active_infiltration_line, nb_dryup_iterations, nb_active_tiles, status_code .. py:method:: plot_progress(current_quantity, zoom=1.0, mean=0.5, flip=True, gl_window_viewport=(0, 0, 100, 100)) .. py:method:: _infiltrations_timings_as_gpu_array(nb_cells_per_zone, infiltrations_chronology: wolfgpu.simple_simulation.InfiltrationChronology) .. py:function:: set_border(array, value) .. py:function:: swimming_pool_with_hole_in_water() .. py:function:: convert_wolf_rk_ponderation(wolf2d: wolfhece.mesh2d.wolf2dprev.prev_sim2D) Convert the ponderation value from prev_sim2D to the one used in the GLSimulation. .. py:function:: get_epsilon(wolf2d: wolfhece.mesh2d.wolf2dprev.prev_sim2D) Get the epsilon value used in the GLSimulation. Based on the spatial resolution of the simulation, we take the minimum of dx and dy to the power of 4. The result is then compared to 0.000_001 and the minimum of the two values is returned. .. py:function:: get_report_frequency(m: wolfhece.mesh2d.wolf2dprev.prev_sim2D) -> wolfgpu.simple_simulation.SimulationDuration .. py:function:: plot_evolution_of_simulation_base(sim: wolfgpu.simple_simulation.SimpleSimulation, rs: wolfgpu.results_store.ResultsStore) .. py:function:: plot_evolution_of_simulation(path_to_model: wolfgpu.gl_utils.Path, path_to_results_store: wolfgpu.gl_utils.Path)