From 17fbf0617d95e8ac40d35e7107b7cdcb7883e937 Mon Sep 17 00:00:00 2001 From: Maryshca <kuzmichova.maria@ya.ru> Date: Thu, 1 Aug 2024 10:59:00 +0300 Subject: [PATCH] v0 --- __pycache__/dearpygui.cpython-311.pyc | Bin 1299 -> 0 bytes __pycache__/dpg_gui_styles.cpython-311.pyc | Bin 3467 -> 0 bytes config-parser/parser-cli.exe | Bin 218964 -> 218964 bytes config.txt | 1226 ++++++++++---------- config_manager.py | 58 +- config_my.txt | 680 ----------- configparsed.txt | 310 ----- dpg_gui_styles.py | 2 +- dpg_gui_tabs.py | 122 +- dpg_gui_windows.py | 137 --- icon.ico | Bin 0 -> 172941 bytes 11 files changed, 716 insertions(+), 1819 deletions(-) delete mode 100644 __pycache__/dearpygui.cpython-311.pyc delete mode 100644 __pycache__/dpg_gui_styles.cpython-311.pyc delete mode 100644 config_my.txt delete mode 100644 configparsed.txt delete mode 100644 dpg_gui_windows.py create mode 100644 icon.ico diff --git a/__pycache__/dearpygui.cpython-311.pyc b/__pycache__/dearpygui.cpython-311.pyc deleted file mode 100644 index 3ffc01fc82928ad4bb9532d76ca322d277dcf84f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1299 zcmZ3^%ge>Uz`)Qax-#uHBLl-@5C?|Ypp4IJ7#SF*Go&!2Fy=7iGDa~mGB7cuGG#GC z<r$VSFfgo!aTuVoEHHr-rWEEBmNl%)m>C#W!}UN_vBFictzlor$iT3g5hh{^GYRGn zh7=A|6;LzSVLDPc(anIW;DD>(O5t9^vy6#>VKoy>4623`#!ul*;Y;CPBY^JS6h;t4 z*PF+!%wWh+%u>!&!5qm@&dA6R$-oG6IXG-V=3)&YZjcNJW0mCr$$&6cSzeF~2&2oU zFa|Sd3cdtM`Bm{amll`g=PHC`mgJ;nMldljWa=<7FlaL0Vl4p)-C`}zOex8@#g>tp znVwNn#pha)m|KvOst}%;my%zu$#{!3Cow5Cr;5iTH76%uN1;5wC@19>OK@UY>Mge7 zlA_GK^eX<q(#+&+g`}eV@;rsK{0dE`B2bLo;!R0SODxSPi7!jcDNVh_nwFEFSd#9x z?epI&6&LMag5p_|8LYGj6!y0`a}z5dYBl+838$nc78O*cmuBk0S+_V5Oy-n=^jmz% zMX8A;sqxAAc_pb8CAavY{Ibl{@`C)Ll3Q%$V1L}=NK8qI2P@$Mv64zlO7in=@qyTx zc?G2<5IF%5zc?o|CABCX?ATlU#i=Ew1@Q=Ld5bgh%j4nZ^B0#S7L_2$^QWX1mlWk! z!kn~{;WH>Eeu=wS#pEO=#iW;J#=uR}E2#X%VUwGmQks)$S0u;4zyJ!9;uJ;(h7Zh) zjEpxJ6fdBn2Mj_D%vTtME;5K*VGy~%Aaa927$hJ(LvI7~4(AID4i_05t}r-UU~qWA z%HI&&5_LgL?E<U%MOO7Itm+>aSQxz+A><7ffd=Omp9yjoSro3YC|qDsxWOXS;N0Rj zL+k>J0+OIugYy*@u^AB;Ox-T9xL;&(zrx~vfyMm>iv&nQVn+Ff)B}YVSUfMXcwS-g zyujl5ffHd1#IBEEd%u85hzNf2$B!R474R@HihzB5kwNqdgXjeY(HjhcAOXRP48m6! sgfB1%!@>kf1tgH*0vEs<i-i~%7<M_bJMl6f;$?9XWIrUr=p@Jv0I)qp=Kufz diff --git a/__pycache__/dpg_gui_styles.cpython-311.pyc b/__pycache__/dpg_gui_styles.cpython-311.pyc deleted file mode 100644 index ea53eb3543091e296ae5e391615f415e06bb4b2e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3467 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 DQz9#n diff --git a/config-parser/parser-cli.exe b/config-parser/parser-cli.exe index 24af2e40907862e1c80186593d25c5e10edb24fc..55c8e34fa0a08e91616caab205c747882ed83a71 100644 GIT binary patch delta 28 kcmcbzj`zws-U*$I)f2n?8Q(YFYQ4qSdW&i6E#|5)0La}9i~s-t delta 28 kcmcbzj`zws-U*$I*%Q0`8SgjVYQ4qSdW&i6E#|5)0LIM?YybcN diff --git a/config.txt b/config.txt index 29f214f..ccd18ce 100644 --- a/config.txt +++ b/config.txt @@ -9,68 +9,66 @@ domain # domain setup in [meters] # x - streamwise, y - spanwise, z - wall-normal directions # - x = 0.0; y = 0.0; z = 0.0; # point of origin - length = 400.0; width = 200.0; height = 80.0; # domain length(x), width(y) and height(z) + x = 0.0; y = 0.0; z = 0.0; # point of origin + length = 400.0; width = 200.0; height = 80.0; # domain length(x), width(y) and height(z) } # ----------------------------------------------------------------------------- time { - begin = 0.0; - end = 50.0 * 3600.0; # start and end time of integration [s] + begin = 0.0; + end = 50.0 * 3600.0; # start and end time of integration [s] - dt = 0.2; # time step [s] + dt = 0.2; # time step [s] - # use_calendar = false; # optional, default = false - calendar - { - mode = "local"; - # mode = "local" - local time - # mode = "local-UTC" - local UTC time - # mode = "set" - prescribed time & date as - # [year, month, day, hour, min, sec, UTC_offset] values + # use_calendar = false; # optional, default = false + calendar + { + mode = "local"; + # mode = "local" - local time + # mode = "local-UTC" - local UTC time + # mode = "set" - prescribed time & date as + # [year, month, day, hour, min, sec, UTC_offset] values - year = 2020; - month = 9; - day = 1; - hour = 12; - min = 0; - sec = 0.0; - UTC_offset = 3; - } + year = 2020; + month = 9; + day = 1; + hour = 12; + min = 0; + sec = 0.0; + UTC_offset = 3; + } } # ----------------------------------------------------------------------------- grid { - type = "uniform"; # grid type = "uniform" || - # "stretched" || "stretched-up" || - # "z-coord-ascii" + type = "uniform"; # type = "uniform" || "stretched" || "stretched-up" || "z-coord-ascii" - filename = "z-coord.txt"; # argument for type = "z-coord-ascii" + filename = "z-coord.txt"; # argument for type = "z-coord-ascii" - cx = 80; cy = 40; cz = 16; # number of cells in each direction + cx = 80; cy = 40; cz = 16; # number of cells in each direction - ksi_z = 1.2; # near-wall grid stretching parameter + ksi_z = 1.2; # near-wall grid stretching parameter - adaptive { - # mode = false; # enable adaptive grid [optional, default = false] + adaptive { + # mode = false; # enable adaptive grid [optional, default = false] - beta = 0.3; # relaxation time scale [<= 1] + beta = 0.3; # relaxation time scale [<= 1] - dz_min = 0.25 * (domain.height / grid.cz); # min grid step - dz_max = 4.0 * (domain.height / grid.cz); # max grid step + dz_min = 0.25 * (domain.height / grid.cz); # min grid step + dz_max = 4.0 * (domain.height / grid.cz); # max grid step - # --- adaptation parameters - TKE_threshold_coeff = 0.1; # threshold coeff. to define hbl - hbl_max_coeff = 1.1; # boundary layer height multiplier - C_smooth_coeff = 5.0; # number of cells in smoothing region + # --- adaptation parameters + TKE_threshold_coeff = 0.1; # threshold coeff. to define hbl + hbl_max_coeff = 1.1; # boundary layer height multiplier + C_smooth_coeff = 5.0; # number of cells in smoothing region - # --- begin & end time of adaptation [optional, default: all integration period] - # begin = time.begin; end = time.end; + # --- begin & end time of adaptation [optional, default: all integration period] + # begin = time.begin; end = time.end; - nskip = 1; # adaptation once in nskip iterations, each iteration := 1 - } + nskip = 1; # adaptation once in nskip iterations, each iteration := 1 + } } # ----------------------------------------------------------------------------- @@ -80,24 +78,24 @@ mpi_setup # MPI-process distribution # in 'mpirun -np [N]' [N] overrides config specs if differs # - dimx = 2; dimy = 2; dimz = 1; + dimx = 2; dimy = 2; dimz = 1; } # ----------------------------------------------------------------------------- phys -{ - f = 0.0; # coriolis frequency [1/s] +{ + f = 0.0; # coriolis frequency [1/s] - nu = 1.25 * 0.00001; # kinematic viscosity [m^2/s] - xi = (1.0 / 0.7) * nu; # thermal diffusivity [m^2/s] - - rho_ref = 1.25; # reference density of air [kg/m^3] + nu = 1.25 * 0.00001; # kinematic viscosity [m^2/s] + xi = (1.0 / 0.7) * nu; # thermal diffusivity [m^2/s] + + rho_ref = 1.25; # reference density of air [kg/m^3] - g = 9.81; # gravitational acceleration [m/s^2] - Theta_ref = 288.15; # reference temperature [K] + g = 9.81; # gravitational acceleration [m/s^2] + Theta_ref = 288.15; # reference temperature [K] - # --- no buoyancy - beta = 0.0; # = g * thermal expansion coefficient = g / Theta_ref [m/(K*s^2)] + # --- no buoyancy + beta = 0.0; # = g * thermal expansion coefficient = g / Theta_ref [m/(K*s^2)] } # ----------------------------------------------------------------------------- @@ -105,71 +103,71 @@ phys # default defs. depend on model configuration state_def { - # Theta_p = false; - # Tabs = false; + # Theta_p = false; + # Tabs = false; - # Rho = false; - # Rho_ideal = false; + # Rho = false; + # Rho_ideal = false; - # Exner_pz = false; - # Pressure_ref_pz = false; + # Exner_pz = false; + # Pressure_ref_pz = false; - # Qliquid = false; - # Qsolid = false; - # Qvapor = false; + # Qliquid = false; + # Qsolid = false; + # Qvapor = false; - # Qvs_water = false; Pvs_water = false; - # Qvs_ice = false; Pvs_ice = false; + # Qvs_water = false; Pvs_water = false; + # Qvs_ice = false; Pvs_ice = false; } # ----------------------------------------------------------------------------- topography { - mode = "hand"; # topography def. mode - # mode = "hand" -- define only 'patches' in configuration file - # mode = "ascii-mask" -- read height map from file + mode = "hand"; # topography def. mode + # mode = "hand" -- define only 'patches' in configuration file + # mode = "ascii-mask" -- read height map from file - # --- using file height map parameters - # mode = "ascii-mask"; - # filename = "map-ex.txt"; # filename path - # xmin = domain.x; # map -x coordinates in computation domain - # xmax = domain.x + domain.length; - # ymin = domain.y; # map -y coordinates in computation domain - # ymax = domain.y + domain.width; - # height_scale = 1.0; # scale height factor + # --- using file height map parameters + # mode = "ascii-mask"; + # filename = "map-ex.txt"; # filename path + # xmin = domain.x; # map -x coordinates in computation domain + # xmax = domain.x + domain.length; + # ymin = domain.y; # map -y coordinates in computation domain + # ymax = domain.y + domain.width; + # height_scale = 1.0; # scale height factor - npatch = 1; # number of patches - patch_1 { - type = "box"; # patch type: "box" || "hill" - - xmin = 15.0; xmax = 35.0; # patch dimensions - ymin = 10.0; ymax = 90.0; - height = 20.0; + npatch = 1; # number of patches + patch_1 { + type = "box"; # patch type: "box" || "hill" + + xmin = 15.0; xmax = 35.0; # patch dimensions + ymin = 10.0; ymax = 90.0; + height = 20.0; - xperiod = 50.0; # optional periodicity in -x - yperiod = 100.0; # optional periodicity in -y - } + xperiod = 50.0; # optional periodicity in -x + yperiod = 100.0; # optional periodicity in -y + } } # ----------------------------------------------------------------------------- geo_wind { # NOTE: skipped if mode not set -# forcing priority: [t,z], [t], [const] +# forcing priority: [t,z], [t], [const] - # --- geostrophic wind components - U = 0.0; V = 0.0; + # --- geostrophic wind components + U = 0.0; V = 0.0; } # ----------------------------------------------------------------------------- external_pressure_grad { # NOTE: skipped if mode not set -# forcing priority: [t,z], [t], [const] +# forcing priority: [t,z], [t], [const] - # --- pressure gradient components [optional] - dPdx = -0.0004; # [Pa/m] - # dPdy = 0.0; # [Pa/m] + # --- pressure gradient components [optional] + dPdx = -0.0004; # [Pa/m] + # dPdy = 0.0; # [Pa/m] } # ----------------------------------------------------------------------------- @@ -195,163 +193,163 @@ rayleigh_friction surface { - Theta { - mode = "const"; + Theta { + mode = "const"; - # --- fixed surface temperature - value = 288.15; # initial surface temperature [K] - } - Qhum { - # --- predefined mode [land surface model] - mode = "lsm"; - } + # --- fixed surface temperature + value = 288.15; # initial surface temperature [K] + } + Qhum { + # --- predefined mode [land surface model] + mode = "lsm"; + } - z0_m = 0.1; # aerodynamic roughness [m] - z0_h = 0.1; # heat roughness [m] + z0_m = 0.1; # aerodynamic roughness [m] + z0_h = 0.1; # heat roughness [m] - kappa = 0.4; # von Karman constant - Pr_t_0 = 1.0; # turbulent Prandt number (neutral) + kappa = 0.4; # von Karman constant + Pr_t_0 = 1.0; # turbulent Prandt number (neutral) - # --- stability function coefficients - Cm = 4.8; - Ch = 7.8; + # --- stability function coefficients + Cm = 4.8; + Ch = 7.8; - alpha_m = 16.0; - alpha_h = 16.0; + alpha_m = 16.0; + alpha_h = 16.0; - # --- latent heat flux alpha/beta model - lhflux_alpha = 1.0; - lhflux_beta = 0.025; + # --- latent heat flux alpha/beta model + lhflux_alpha = 1.0; + lhflux_beta = 0.025; } # ----------------------------------------------------------------------------- initial_conditions { - # optional [U], [V] - # if not set initial profiles are set to match geostrophic wind + # optional [U], [V] + # if not set initial profiles are set to match geostrophic wind - U { - # mode = "half-channel"; - # bulk = 6.0; - } + U { + # mode = "half-channel"; + # bulk = 6.0; + } - Theta { - # --- predefined mode - mode = "const"; + Theta { + # --- predefined mode + mode = "const"; - surface_value = 288.15; # initial boundary layer temperature [K] - height = 0.0; # boundary layer height [m] - grad_z = 0.0; # humidity gradient above boundary layer [kg/(kg*m)] - } + surface_value = 288.15; # initial boundary layer temperature [K] + height = 0.0; # boundary layer height [m] + grad_z = 0.0; # humidity gradient above boundary layer [kg/(kg*m)] + } - Qhum { - # --- predefined mode - mode = "mixed-layer"; + Qhum { + # --- predefined mode + mode = "mixed-layer"; - surface_value = 0.0025; # initial boundary layer humidity [kg/kg] - height = 0.0; # boundary layer height [m] - grad_z = 0.0; # humidity gradient above boundary layer [kg/(kg*m)] - } + surface_value = 0.0025; # initial boundary layer humidity [kg/kg] + height = 0.0; # boundary layer height [m] + grad_z = 0.0; # humidity gradient above boundary layer [kg/(kg*m)] + } } # ----------------------------------------------------------------------------- damping { - is_enabled = false; + is_enabled = false; - # use_avgxy_ref = false; # damp to -xy average profile [optional] + # use_avgxy_ref = false; # damp to -xy average profile [optional] - f = 0.2; # damping frequency [1/s], = 0.2 (WRF model) + f = 0.2; # damping frequency [1/s], = 0.2 (WRF model) - # --- damping layer [z1, z2] - z1 = domain.z + 0.75 * domain.height; # [m] - z2 = domain.z + domain.height; # [m] + # --- damping layer [z1, z2] + z1 = domain.z + 0.75 * domain.height; # [m] + z2 = domain.z + domain.height; # [m] } # ----------------------------------------------------------------------------- les { - is_dynamic_momentum = true; - is_dynamic_scalar = true; + is_dynamic_momentum = true; + is_dynamic_scalar = true; - is_ssm_mixed_momentum = false; - is_ssm_mixed_scalar = false; + is_ssm_mixed_momentum = false; + is_ssm_mixed_scalar = false; - is_amd_model = false; # use AMD subgrid model - # dynamic, ssm keys not supported, have to be := false + is_amd_model = false; # use AMD subgrid model + # dynamic, ssm keys not supported, have to be := false - # --- SSM model params - C_ssm_momentum = 1.0; - C_ssm_scalar = 1.0; + # --- SSM model params + C_ssm_momentum = 1.0; + C_ssm_scalar = 1.0; - # --- static LES model params - C_smag = 0.08; # GABLS-1 fit = 0.08 - # Lilly = 0.17 - Prandtl_sgs = 0.7; # subgrid scale Prandtl [0.4, 1.0] + # --- static LES model params + C_smag = 0.08; # GABLS-1 fit = 0.08 + # Lilly = 0.17 + Prandtl_sgs = 0.7; # subgrid scale Prandtl [0.4, 1.0] - # --- dynamic LES model params - dynamic { - # --- dynamic coefficient = (C_{s} * delta_{g})^2 clipping - C_smag_max = 0.25; - Prandtl_sgs_min = 0.4; + # --- dynamic LES model params + dynamic { + # --- dynamic coefficient = (C_{s} * delta_{g})^2 clipping + C_smag_max = 0.25; + Prandtl_sgs_min = 0.4; - alpha = 1.73; # test-to-base filter width ratio + alpha = 1.73; # test-to-base filter width ratio - avg_mode = "lagrange"; # "none", "plane", "filter", "lagrange" + avg_mode = "lagrange"; # "none", "plane", "filter", "lagrange" - nskip = 3; - use_transport = false; + nskip = 3; + use_transport = false; - C_T_lagrange_momentum = 1.5; - C_T_lagrange_scalar = 3.0; - } + C_T_lagrange_momentum = 1.5; + C_T_lagrange_scalar = 3.0; + } - base_filter_reset = false; - test_filter_reset = false; - clip_filter_reset = false; + base_filter_reset = false; + test_filter_reset = false; + clip_filter_reset = false; } # ----------------------------------------------------------------------------- passive_tracers { - # num = 2; # number of tracers, skipped if not defined + # num = 2; # number of tracers, skipped if not defined - # --- each tracer field defines diffusivity & surface values - tracer_1 { - diffusivity = phys.xi; + # --- each tracer field defines diffusivity & surface values + tracer_1 { + diffusivity = phys.xi; - surface { - flux = -0.01; + surface { + flux = -0.01; - # --- setting localized source, all surface if not defined - xmin = 180.0; xmax = 220.0; - ymin = 180.0; ymax = 220.0; + # --- setting localized source, all surface if not defined + xmin = 180.0; xmax = 220.0; + ymin = 180.0; ymax = 220.0; - # --- active in [begin, end], [time.begin, time.end] if not defined - begin = 7.0 * 3600.0; - # end = time.end; - } - } + # --- active in [begin, end], [time.begin, time.end] if not defined + begin = 7.0 * 3600.0; + # end = time.end; + } + } - tracer_2 { - # name = "tracer[2]"; # optional tracer name + tracer_2 { + # name = "tracer[2]"; # optional tracer name - diffusivity = phys.xi; + diffusivity = phys.xi; - # --- setting 'life-time' using decay frequency [1/s] [optional] - # f_decay = 1.0 / 600.0; + # --- setting 'life-time' using decay frequency [1/s] [optional] + # f_decay = 1.0 / 600.0; - surface { - flux = -0.02; + surface { + flux = -0.02; - # --- active in [begin, end], [time.begin, time.end] if not defined - begin = 7.0 * 3600.0; - # end = time.end; - } - } + # --- active in [begin, end], [time.begin, time.end] if not defined + begin = 7.0 * 3600.0; + # end = time.end; + } + } } # ----------------------------------------------------------------------------- @@ -359,48 +357,48 @@ passive_tracers # used only if INCLUDE_PARTICLES is defined, see [model-defines.h] ptcl { - is_passive_transport = false; # passive particles flag - - # --- particle parameters for all sources - density = 1000.0; # particle density [kg/m^3] - diameter = 0.000001; # particle diameter [m] + is_passive_transport = false; # passive particles flag + + # --- particle parameters for all sources + density = 1000.0; # particle density [kg/m^3] + diameter = 0.000001; # particle diameter [m] - g = -9.81; # gravity acceleration [m/s^2] + g = -9.81; # gravity acceleration [m/s^2] - # f_decay = 1.0 / 100.0; # optional decay constant [1/s] - # half-life = ln(2) / f + # f_decay = 1.0 / 100.0; # optional decay constant [1/s] + # half-life = ln(2) / f - # --- number of sources - nsources = 1; + # --- number of sources + nsources = 1; - source_1 { - n = 524288 * 8; # number of particles to release - begin = 5.0 * 3600.0; # release time - end = time.end; # instant release if not defined + source_1 { + n = 524288 * 8; # number of particles to release + begin = 5.0 * 3600.0; # release time + end = time.end; # instant release if not defined - # --- setting flux [lower priority than 'n' -- number of particles] - # both begin & end must be specified -- not instant source - # flux = 10.0; - # flux_direction = "X"; + # --- setting flux [lower priority than 'n' -- number of particles] + # both begin & end must be specified -- not instant source + # flux = 10.0; + # flux_direction = "X"; - # --- source volume - xmin = domain.x + 50.0 - 10.0; xmax = domain.x + 50.0 + 10.0; - ymin = domain.y; ymax = domain.y + domain.width; - zmin = domain.z; zmax = domain.z + 5.0; - } + # --- source volume + xmin = domain.x + 50.0 - 10.0; xmax = domain.x + 50.0 + 10.0; + ymin = domain.y; ymax = domain.y + domain.width; + zmin = domain.z; zmax = domain.z + 5.0; + } - # --- number of sinks [optional] - nsinks = 1; + # --- number of sinks [optional] + nsinks = 1; - sink_1 { - # --- optional, default mode = "inside" - mode = "outside"; # "inside" || "outside" + sink_1 { + # --- optional, default mode = "inside" + mode = "outside"; # "inside" || "outside" - # --- define volume - xmin = domain.x; xmax = domain.x + domain.length; - ymin = domain.y - 0.5 * domain.width; ymax = domain.y + 1.5 * domain.width; - zmin = domain.z + 0.01; zmax = domain.z + domain.height; - } + # --- define volume + xmin = domain.x; xmax = domain.x + domain.length; + ymin = domain.y - 0.5 * domain.width; ymax = domain.y + 1.5 * domain.width; + zmin = domain.z + 0.01; zmax = domain.z + domain.height; + } } # ----------------------------------------------------------------------------- @@ -408,41 +406,41 @@ ptcl # used only if INCLUDE_PARTICLES_TRACKING is defined, see [model-defines.h] ptcl_track { - is_passive_transport = ptcl.is_passive_transport; - - # --- particle parameters for all sources - density = ptcl.density; # particle density [kg/m^3] - diameter = ptcl.diameter; # particle diameter [m] + is_passive_transport = ptcl.is_passive_transport; + + # --- particle parameters for all sources + density = ptcl.density; # particle density [kg/m^3] + diameter = ptcl.diameter; # particle diameter [m] - g = ptcl.g; # gravity acceleration [m/s^2] + g = ptcl.g; # gravity acceleration [m/s^2] - # f_decay = ptcl.f_decay; # optional decay constant [1/s] - # half-life = ln(2) / f + # f_decay = ptcl.f_decay; # optional decay constant [1/s] + # half-life = ln(2) / f - group_max_size = 256; # max number of particles per group - max_memory = 10 * 1024 * 1024; # max memory in bytes for keeping trajectories in memory + group_max_size = 256; # max number of particles per group + max_memory = 10 * 1024 * 1024; # max memory in bytes for keeping trajectories in memory - # --- number of sources - nsources = 1; + # --- number of sources + nsources = 1; - source_1 - { - n = 128; # number of particles to release - begin = 8.0 * 3600.0; # release time + source_1 + { + n = 128; # number of particles to release + begin = 8.0 * 3600.0; # release time - # --- setting flux [lower priority than 'n' -- number of particles] - # both begin & end must be specified -- not instant source - # flux = 100.0; - # flux_direction = "Z"; + # --- setting flux [lower priority than 'n' -- number of particles] + # both begin & end must be specified -- not instant source + # flux = 100.0; + # flux_direction = "Z"; - # --- source volume - xmin = domain.x + 0.4 * domain.length; xmax = domain.x + 0.6 * domain.length; - ymin = domain.y + 0.4 * domain.width; ymax = domain.y + 0.6 * domain.width; - zmin = domain.z; zmax = domain.z + 0.1 * domain.height; - } + # --- source volume + xmin = domain.x + 0.4 * domain.length; xmax = domain.x + 0.6 * domain.length; + ymin = domain.y + 0.4 * domain.width; ymax = domain.y + 0.6 * domain.width; + zmin = domain.z; zmax = domain.z + 0.1 * domain.height; + } - # --- number of sinks [optional] - nsinks = 0; + # --- number of sinks [optional] + nsinks = 0; } # ----------------------------------------------------------------------------- @@ -450,34 +448,34 @@ ptcl_track # used only if INCLUDE_CANOPY_DRAG is defined, see [model-defines.h] canopy { - Cd = 0.15; - drag_type = "non-linear"; # || "linearized" || "mean" + Cd = 0.15; + drag_type = "non-linear"; # || "linearized" || "mean" - num = 0; - patch_1 { - type = "sharp"; # || "fancy" || "obs" + num = 0; + patch_1 { + type = "sharp"; # || "fancy" || "obs" - # --- patch volume - xmin = domain.x; xmax = domain.x + domain.length; - ymin = domain.y; ymax = domain.y + domain.width; - zmin = domain.z; zmax = domain.z + 50.0; + # --- patch volume + xmin = domain.x; xmax = domain.x + domain.length; + ymin = domain.y; ymax = domain.y + domain.width; + zmin = domain.z; zmax = domain.z + 50.0; - # --- make patch 'periodic' in -x and/or -y directions - # single patch if not defined - # xperiod = 1.0; - # yperiod = 1.0; + # --- make patch 'periodic' in -x and/or -y directions + # single patch if not defined + # xperiod = 1.0; + # yperiod = 1.0; - LAI = 1.0; - # --- set zm - height of max(LAD) for type = "obs": - # zm = zmin + 0.8 * (zmax - zmin); + LAI = 1.0; + # --- set zm - height of max(LAD) for type = "obs": + # zm = zmin + 0.8 * (zmax - zmin); - # --- OR: set a file - # type = "sharp-map"; - # filename = "map-ex.txt"; + # --- OR: set a file + # type = "sharp-map"; + # filename = "map-ex.txt"; - # switch_ij_order = false; # [optional, default = false] - # normalize_height = 1.0; # [optional, default = 1.0] - } + # switch_ij_order = false; # [optional, default = false] + # normalize_height = 1.0; # [optional, default = 1.0] + } } # ----------------------------------------------------------------------------- @@ -486,24 +484,24 @@ poisson # # Poisson equation solver setup # - # use_cg_solver = false; # use CG as base solver [optional, default = BiCGstab] + # use_cg_solver = false; # use CG as base solver [optional, default = BiCGstab] - retol = 0.0001; abstol = 0.00001; # relative and absolute tolerance - miniters = 1; maxiters = 100; # minimum and maximum number of iterations + retol = 0.0001; abstol = 0.00001; # relative and absolute tolerance + miniters = 1; maxiters = 100; # minimum and maximum number of iterations - piters = 1; # number of preconditioner (multigrid) iterations + piters = 1; # number of preconditioner (multigrid) iterations - multigrid - { - ngrid = 5; # number of grids in multigrid sequence (= [0] - auto definition) + multigrid + { + ngrid = 5; # number of grids in multigrid sequence (= [0] - auto definition) - down_iters = 2; # number of smoother iterations on fine->coarse traverse - up_iters = 3; # number of smoother iterations on coarse->fine traverse - direct_iters = 5; # number of smoother iterations on coarsest grid + down_iters = 2; # number of smoother iterations on fine->coarse traverse + up_iters = 3; # number of smoother iterations on coarse->fine traverse + direct_iters = 5; # number of smoother iterations on coarsest grid - smooth_up_omega = 1.84; # relaxation value on coarse->fine traverse - smooth_up_omega_fine = 1.64; # relaxation value on reaching finest grid - } + smooth_up_omega = 1.84; # relaxation value on coarse->fine traverse + smooth_up_omega_fine = 1.64; # relaxation value on reaching finest grid + } } # ----------------------------------------------------------------------------- @@ -511,220 +509,220 @@ output { # NOTE: netcdf output is enabled only if INCLUDE_NETCDF is defined in [nse-sys.h] - DIR = MAIN_DIR + "output/"; # output directory - make_unique_DIR = true; # make output directory unique for each run - - convert_dsq_to_tecplot = true; # convert series .dsq output to .plt [tecplot] format - # *: on model completion only - # convert_dsq_to_netcdf = false; # convert series .dsq output to .nc [netcdf] format - # *: on model completion only - - num = 1; # number of output units - - unit_1 - { - SUBDIR = ""; # unit sub-directory + DIR = MAIN_DIR + "output/"; # output directory + make_unique_DIR = true; # make output directory unique for each run + + convert_dsq_to_tecplot = true; # convert series .dsq output to .plt [tecplot] format + # *: on model completion only + # convert_dsq_to_netcdf = false; # convert series .dsq output to .nc [netcdf] format + # *: on model completion only + + num = 1; # number of output units + + unit_1 + { + SUBDIR = ""; # unit sub-directory - begin = 1.0 * 3600.0; # start time [s] for writing output - dt = 1.0 * 3600.0; # time step [s] for writing output + begin = 1.0 * 3600.0; # start time [s] for writing output + dt = 1.0 * 3600.0; # time step [s] for writing output - # --- output subdomain [optional, applicable in 3D output only] - xmin = domain.x; xmax = domain.x + domain.length; # -x output domain setup - ymin = domain.y; ymax = domain.y + domain.width; # -y output domain setup - zmin = domain.z; zmax = domain.z + domain.height; # -z output domain setup + # --- output subdomain [optional, applicable in 3D output only] + xmin = domain.x; xmax = domain.x + domain.length; # -x output domain setup + ymin = domain.y; ymax = domain.y + domain.width; # -y output domain setup + zmin = domain.z; zmax = domain.z + domain.height; # -z output domain setup - # --- output controls [default, if not defined, value is 'false'] - cntrl_avgxy_plt = true; # 1D -xy averaged .plt fields - cntrl_avgxy_netcdf = false; # 1D -xy averaged netcdf fields + # --- output controls [default, if not defined, value is 'false'] + cntrl_avgxy_plt = true; # 1D -xy averaged .plt fields + cntrl_avgxy_netcdf = false; # 1D -xy averaged netcdf fields - cntrl_3d_plt = true; # 3D .plt fields - cntrl_3d_bin = false; # 3D .nsx fields - cntrl_3d_netcdf = false; # 3D netcdf fields + cntrl_3d_plt = true; # 3D .plt fields + cntrl_3d_bin = false; # 3D .nsx fields + cntrl_3d_netcdf = false; # 3D netcdf fields - cntrl_geometry_3d_plt = false; # geometry 3D .plt fields - cntrl_geometry_3d_netcdf = false; # geometry 3D netcdf fields + cntrl_geometry_3d_plt = false; # geometry 3D .plt fields + cntrl_geometry_3d_netcdf = false; # geometry 3D netcdf fields - cntrl_topography_plt = true; # topography .plt fields - cntrl_topography_netcdf = false; # topography netcdf fields + cntrl_topography_plt = true; # topography .plt fields + cntrl_topography_netcdf = false; # topography netcdf fields - cntrl_2d_plt = false; # 2D .plt fields - cntrl_2d_netcdf = false; # 2D netcdf fields + cntrl_2d_plt = false; # 2D .plt fields + cntrl_2d_netcdf = false; # 2D netcdf fields - cntrl_surface_plt = true; # surface .plt fields - cntrl_surface_netcdf = false; # surface netcdf fields + cntrl_surface_plt = true; # surface .plt fields + cntrl_surface_netcdf = false; # surface netcdf fields - cntrl_grid_plt = false; # grid .plt data - cntrl_grid_netcdf = false; # grid netcdf data + cntrl_grid_plt = false; # grid .plt data + cntrl_grid_netcdf = false; # grid netcdf data - cntrl_meteo_avgxy_plt = false; # 1D -xy averaged meteo forcing .plt fields - cntrl_meteo_all_plt = false; # all meteo forcing .plt fields + cntrl_meteo_avgxy_plt = false; # 1D -xy averaged meteo forcing .plt fields + cntrl_meteo_all_plt = false; # all meteo forcing .plt fields - # --- output keys for filtered fields - cntrl_filtered_3d_plt = false; - # filter { kxmin = 0; kxmax = 0; kymin = 0; kymax = 5; is_remove_mean = true; } + # --- output keys for filtered fields + cntrl_filtered_3d_plt = false; + # filter { kxmin = 0; kxmax = 0; kymin = 0; kymax = 5; is_remove_mean = true; } - # --- spectrum output - spectrum - { - # --- controls - x_cntrl = true; - y_cntrl = true; - xy_cntrl = true; + # --- spectrum output + spectrum + { + # --- controls + x_cntrl = true; + y_cntrl = true; + xy_cntrl = true; - # np = 2; # number of z planes, skipped if not defined - z_1 = 50.0; - z_2 = 100.0; + # np = 2; # number of z planes, skipped if not defined + z_1 = 50.0; + z_2 = 100.0; - # --- additional options for 1d & 2d spectrum, default all = true if not defined - # is_remove_mean_1d = true; - # is_centered_fft_1d = true; + # --- additional options for 1d & 2d spectrum, default all = true if not defined + # is_remove_mean_1d = true; + # is_centered_fft_1d = true; - # is_remove_mean_2d = true; - # is_centered_fft_2d = true; - # is_log10_2d = true; - } + # is_remove_mean_2d = true; + # is_centered_fft_2d = true; + # is_log10_2d = true; + } - # --- particles & trajectories output - # used only if INCLUDE_PARTICLES is defined - cntrl_ptcl_bin = false; # particles binary output - cntrl_ptcl_plt = true; # particles .plt output - cntrl_ptcl_coords_plt = false; # particles coordinates .plt output - # used only if INCLUDE_PARTICLES_TRACKING is defined - cntrl_ptcl_traj_bin = false; # particles trajectories binary output - cntrl_ptcl_traj_plt = false; # particles trajectories .plt output + # --- particles & trajectories output + # used only if INCLUDE_PARTICLES is defined + cntrl_ptcl_bin = false; # particles binary output + cntrl_ptcl_plt = true; # particles .plt output + cntrl_ptcl_coords_plt = false; # particles coordinates .plt output + # used only if INCLUDE_PARTICLES_TRACKING is defined + cntrl_ptcl_traj_bin = false; # particles trajectories binary output + cntrl_ptcl_traj_plt = false; # particles trajectories .plt output - # --- profiles [= 0 if not defined] - x_profile_num = 0; - y_profile_num = 0; - z_profile_num = 0; - # --- e.g.: - x_profile_1 { y = domain.y + 0.5 * domain.width; z = domain.z + 0.5 * domain.height; } + # --- profiles [= 0 if not defined] + x_profile_num = 0; + y_profile_num = 0; + z_profile_num = 0; + # --- e.g.: + x_profile_1 { y = domain.y + 0.5 * domain.width; z = domain.z + 0.5 * domain.height; } - # --- slices [ = 0 if not defined] - xy_slice_num = 0; - xz_slice_num = 0; - yz_slice_num = 0; - # --- e.g.: - xy_slice_1 { z = domain.z + 0.5 * domain.height; } - } + # --- slices [ = 0 if not defined] + xy_slice_num = 0; + xz_slice_num = 0; + yz_slice_num = 0; + # --- e.g.: + xy_slice_1 { z = domain.z + 0.5 * domain.height; } + } - screen { - begin = time.begin; # start time [s] of onscreen output + screen { + begin = time.begin; # start time [s] of onscreen output - # nskip = 360; # output once in nskip iterations, each iteration := 1 - dt = 0.05 * 3600.0; # output time step [s], --higher-- priority than 'nskip' + # nskip = 360; # output once in nskip iterations, each iteration := 1 + dt = 0.05 * 3600.0; # output time step [s], --higher-- priority than 'nskip' - # --- screen controls [optional, default = true] - # cntrl_status = true; - # cntrl_progress_bar = true; - - # --- screen controls [optional, default = false] - # cntrl_terminal_mode = false; - } + # --- screen controls [optional, default = true] + # cntrl_status = true; + # cntrl_progress_bar = true; + + # --- screen controls [optional, default = false] + # cntrl_terminal_mode = false; + } } # ----------------------------------------------------------------------------- checkup { - # --- additional checkups [InF, NaN values etc.] - begin = 0.0; # start time of checks + # --- additional checkups [InF, NaN values etc.] + begin = 0.0; # start time of checks - nskip = 3600; # check once in nskip iterations, each iteration := 1 - # dt = 1.0 * 3600.0; # check time step, --higher-- priority than 'nskip' + nskip = 3600; # check once in nskip iterations, each iteration := 1 + # dt = 1.0 * 3600.0; # check time step, --higher-- priority than 'nskip' } # ----------------------------------------------------------------------------- dump { - DIR = MAIN_DIR + "dump/"; # dump directory + DIR = MAIN_DIR + "dump/"; # dump directory - begin = 10.0 * 3600.0; # start time [s] for writing model dump - dt = 10.0 * 3600.0; # time step [s] for writing model dump + begin = 10.0 * 3600.0; # start time [s] for writing model dump + dt = 10.0 * 3600.0; # time step [s] for writing model dump } # ----------------------------------------------------------------------------- startup { - DIR = MAIN_DIR + "init/"; # initial conditions directory + DIR = MAIN_DIR + "init/"; # initial conditions directory } # ----------------------------------------------------------------------------- series { - begin = 60.0; # start time [s] + begin = 60.0; # start time [s] - # nskip = 2; # calculate once in nskip iterations, each iteration := 1 - dt = 1.0; # time step [s], --higher-- priority than 'nskip' + # nskip = 2; # calculate once in nskip iterations, each iteration := 1 + dt = 1.0; # time step [s], --higher-- priority than 'nskip' - # --- point flow measurements - point_set - { - # mode = "define"; # optional point set mode - # = "define" [default] || "grid-xy" + # --- point flow measurements + point_set + { + # mode = "define"; # optional point set mode + # = "define" [default] || "grid-xy" - # np = 3; # number of points, skipped if not defined - point_1 { x = domain.x + 0.5 * domain.length; y = domain.y + 0.5 * domain.width; z = 25.0; } - point_2 { x = domain.x + 0.5 * domain.length; y = domain.y + 0.5 * domain.width; z = 50.0; } - point_3 { x = domain.x + 0.5 * domain.length; y = domain.y + 0.5 * domain.width; z = 100.0; } + # np = 3; # number of points, skipped if not defined + point_1 { x = domain.x + 0.5 * domain.length; y = domain.y + 0.5 * domain.width; z = 25.0; } + point_2 { x = domain.x + 0.5 * domain.length; y = domain.y + 0.5 * domain.width; z = 50.0; } + point_3 { x = domain.x + 0.5 * domain.length; y = domain.y + 0.5 * domain.width; z = 100.0; } - # --- OR: set point set grid on z=const planes - # mode = "grid-xy"; + # --- OR: set point set grid on z=const planes + # mode = "grid-xy"; - # --- domain - # x = domain.x; y = domain.y; - # length = domain.length; width = domain.width; + # --- domain + # x = domain.x; y = domain.y; + # length = domain.length; width = domain.width; - # --- grid dimensions, number of edges - # nx = 7; ny = 5; - # --- number of z=const planes - # nz = 3; - # z_1 = 25.0; - # z_2 = 50.0; - # z_3 = 100.0; - } + # --- grid dimensions, number of edges + # nx = 7; ny = 5; + # --- number of z=const planes + # nz = 3; + # z_1 = 25.0; + # z_2 = 50.0; + # z_3 = 100.0; + } - # --- [xy] averaged energy at fixed 'z' - energy_avgxy_set - { - # np = 2; # number of z planes, skipped if not defined - z_1 = 50.0; - z_2 = 100.0; - } + # --- [xy] averaged energy at fixed 'z' + energy_avgxy_set + { + # np = 2; # number of z planes, skipped if not defined + z_1 = 50.0; + z_2 = 100.0; + } - # --- [xy] averaged fluxes at fixed 'z' - flux_avgxy_set - { - # np = 2; # number of z planes, skipped if not defined - z_1 = 50.0; - z_2 = 100.0; - } + # --- [xy] averaged fluxes at fixed 'z' + flux_avgxy_set + { + # np = 2; # number of z planes, skipped if not defined + z_1 = 50.0; + z_2 = 100.0; + } - # --- additional parameters - # --- TKE hbl def. [optional] - # TKE_hbl_threshold_stable = 0.3; - # TKE_hbl_threshold_unstable = 0.1; + # --- additional parameters + # --- TKE hbl def. [optional] + # TKE_hbl_threshold_stable = 0.3; + # TKE_hbl_threshold_unstable = 0.1; - # --- max length to hold data in memory [optional] - # max_mem_length = 100 * 1024; + # --- max length to hold data in memory [optional] + # max_mem_length = 100 * 1024; } # ----------------------------------------------------------------------------- spectrum_series { - begin = time.begin; # start time - - nskip = 1; # calculate once in nskip iterations, each iteration := 1 - # dt = 1.0; # time step, --higher-- priority than 'nskip' + begin = time.begin; # start time + + nskip = 1; # calculate once in nskip iterations, each iteration := 1 + # dt = 1.0; # time step, --higher-- priority than 'nskip' - # num = 3; # number of series, skipped if not defined + # num = 3; # number of series, skipped if not defined - # --- wavevenumbers in: - kxmax <= kx <= kmax, 0 <= ky <= kymax - unit_1 { zp = domain.z + 0.3 * domain.height; kxmax = 3; kymax = 3; } - unit_2 { zp = domain.z + 0.2 * domain.height; kxmax = 3; kymax = 3; } - unit_3 { zp = domain.z + 0.1 * domain.height; kxmax = 3; kymax = 3; } + # --- wavevenumbers in: - kxmax <= kx <= kmax, 0 <= ky <= kymax + unit_1 { zp = domain.z + 0.3 * domain.height; kxmax = 3; kymax = 3; } + unit_2 { zp = domain.z + 0.2 * domain.height; kxmax = 3; kymax = 3; } + unit_3 { zp = domain.z + 0.1 * domain.height; kxmax = 3; kymax = 3; } - # --- max length to hold data in memory [optional] - # max_mem_length = 100 * 1024; + # --- max length to hold data in memory [optional] + # max_mem_length = 100 * 1024; } # ----------------------------------------------------------------------------- @@ -732,248 +730,248 @@ time_scan { # NOTE: dump is not supported for time scans - begin = 60.0; # scan start time [s] + begin = 60.0; # scan start time [s] - # nskip = 1000; # calculate once in nksip iterations, each iteration := 1 - dt = 60.0; # scan time step [s], --higher-- priority than 'nskip' + # nskip = 1000; # calculate once in nksip iterations, each iteration := 1 + dt = 60.0; # scan time step [s], --higher-- priority than 'nskip' - # --- optionally set output variables + # --- optionally set output variables - cntrl_grid = false; # all keys, optional, default = all 'false' - cntrl_grid { - # dz = true; + cntrl_grid = false; # all keys, optional, default = all 'false' + cntrl_grid { + # dz = true; - # --- cell center & edge coordinates - # pz = true; - # ez = true; + # --- cell center & edge coordinates + # pz = true; + # ez = true; - # --- only in adaptive grid mode - # monitor_function = true; - } + # --- only in adaptive grid mode + # monitor_function = true; + } - cntrl_avgxy = true; # all keys, optional, default = all 'false' - cntrl_avgxy { - # U = true; - # V = true; - # W = true; + cntrl_avgxy = true; # all keys, optional, default = all 'false' + cntrl_avgxy { + # U = true; + # V = true; + # W = true; - # Theta = true; - # Theta_p = true; - # Tabs = true; + # Theta = true; + # Theta_p = true; + # Tabs = true; - # Q = true; - # Qvapor = true; + # Q = true; + # Qvapor = true; - # UW_flux = true; - # VW_flux = true; - # TW_flux = true; - # QW_flux = true; + # UW_flux = true; + # VW_flux = true; + # TW_flux = true; + # QW_flux = true; - # U_variance = true; - # V_variance = true; - # W_variance = true; - # Theta_variance = true; - # Q_variance = true; - } + # U_variance = true; + # V_variance = true; + # W_variance = true; + # Theta_variance = true; + # Q_variance = true; + } - cntrl_z_profile = false; # all keys, optional, default = all 'false' - cntrl_z_profile { - # U = true; - # V = true; - # W = true; + cntrl_z_profile = false; # all keys, optional, default = all 'false' + cntrl_z_profile { + # U = true; + # V = true; + # W = true; - # Theta = true; - # Theta_p = true; - # Tabs = true; + # Theta = true; + # Theta_p = true; + # Tabs = true; - # Q = true; - # Qvapor = true; - } - - z_profile_num = 0; - z_profile_1 { x = domain.x + 0.5 * domain.length; y = domain.y + 0.5 * domain.width; } + # Q = true; + # Qvapor = true; + } + + z_profile_num = 0; + z_profile_1 { x = domain.x + 0.5 * domain.length; y = domain.y + 0.5 * domain.width; } } # ----------------------------------------------------------------------------- stats { - num = 2; + num = 2; - unit_1 { - begin = time.end - 4.0 * 3600.0; # start time for averaging - end = time.end; # end time for averaging, to \infty if not defined + unit_1 { + begin = time.end - 4.0 * 3600.0; # start time for averaging + end = time.end; # end time for averaging, to \infty if not defined - nskip = 10; - axis = "XYZ"; - type = "energy-eq"; + nskip = 10; + axis = "XYZ"; + type = "energy-eq"; - output.SUBDIR = "stat_end/"; - dump.SUBDIR = "stat_end/"; + output.SUBDIR = "stat_end/"; + dump.SUBDIR = "stat_end/"; - # --- regular mode [optional] -- shifts accumulation window - # is_regular = false; + # --- regular mode [optional] -- shifts accumulation window + # is_regular = false; - # --- ensemble mode [optional] -- ensemble averaging - # is_ensemble = false; - } - unit_2 { - begin = time.end - 8.0 * 3600.0; # start time for averaging - end = time.end - 4.0 * 3600.0; # end time for averaging, to \infty if not defined + # --- ensemble mode [optional] -- ensemble averaging + # is_ensemble = false; + } + unit_2 { + begin = time.end - 8.0 * 3600.0; # start time for averaging + end = time.end - 4.0 * 3600.0; # end time for averaging, to \infty if not defined - nskip = 10; - axis = "XYZ"; - type = "energy-eq"; + nskip = 10; + axis = "XYZ"; + type = "energy-eq"; - output.SUBDIR = "stat_end-1/"; - dump.SUBDIR = "stat_end-1"; + output.SUBDIR = "stat_end-1/"; + dump.SUBDIR = "stat_end-1"; - # --- regular mode [optional] -- shifts accumulation window - # is_regular = false; + # --- regular mode [optional] -- shifts accumulation window + # is_regular = false; - # --- ensemble mode [optional] -- ensemble averaging - # is_ensemble = false; - } + # --- ensemble mode [optional] -- ensemble averaging + # is_ensemble = false; + } } # ----------------------------------------------------------------------------- pdf { - # num = 1; + # num = 1; - unit_1 { - begin = 7.5 * 3600.0; - end = 9.0 * 3600.0; - dt = 1.0; + unit_1 { + begin = 7.5 * 3600.0; + end = 9.0 * 3600.0; + dt = 1.0; - zp = domain.z + 0.25 * domain.height; + zp = domain.z + 0.25 * domain.height; - output.SUBDIR = "pdf/"; - dump.SUBDIR = "pdf/"; + output.SUBDIR = "pdf/"; + dump.SUBDIR = "pdf/"; - cntrl_default = true; - nbins_default = 256; + cntrl_default = true; + nbins_default = 256; - # --- reset options: [begin, reset_time] -- find histogram parameters - # if not defined set min-max range for each variable in controls - reset_time = 8.0 * 3600.0; - reset_safety = 0.25; # relative to min-max found - # e.g.: min' = min - reset_safety * (max - min) + # --- reset options: [begin, reset_time] -- find histogram parameters + # if not defined set min-max range for each variable in controls + reset_time = 8.0 * 3600.0; + reset_safety = 0.25; # relative to min-max found + # e.g.: min' = min - reset_safety * (max - min) - # --- regular mode [optional] -- shifts accumulation window - # is_regular = false; + # --- regular mode [optional] -- shifts accumulation window + # is_regular = false; - # --- change default control using keys - # cntrl { - # U = true; V = true; W = true; Pressure = true; - # U_grad_x = true; U_grad_y = true; U_grad_z = true; - # V_grad_x = true; V_grad_y = true; V_grad_z = true; - # W_grad_x = true; W_grad_y = true; W_grad_z = true; - # Suv = true; Suw = true; Svw = true; # strain-tensor - # Omega_uv = true; Omega_uw = true; Omega_vw = true; # vorticity-tensor - # Theta = true; - # Theta_grad_x = true; Theta_grad_y = true; Theta_grad_z = true; - # Q = true; - # Q_grad_x = true; Q_grad_y = true; Q_grad_z = true; + # --- change default control using keys + # cntrl { + # U = true; V = true; W = true; Pressure = true; + # U_grad_x = true; U_grad_y = true; U_grad_z = true; + # V_grad_x = true; V_grad_y = true; V_grad_z = true; + # W_grad_x = true; W_grad_y = true; W_grad_z = true; + # Suv = true; Suw = true; Svw = true; # strain-tensor + # Omega_uv = true; Omega_uw = true; Omega_vw = true; # vorticity-tensor + # Theta = true; + # Theta_grad_x = true; Theta_grad_y = true; Theta_grad_z = true; + # Q = true; + # Q_grad_x = true; Q_grad_y = true; Q_grad_z = true; - # --- tracers 'C' correspond to passive_tracers {} def. [use index in: 1...passive_tracers.num] - # C1 = true; - # C1_grad_x = true; C1_grad_y = true; C1_grad_z = true; - # C2 = true; - # - # } + # --- tracers 'C' correspond to passive_tracers {} def. [use index in: 1...passive_tracers.num] + # C1 = true; + # C1_grad_x = true; C1_grad_y = true; C1_grad_z = true; + # C2 = true; + # + # } - # --- setting min-max for any variable - # this has to be defined if 'reset_time' is skipped, e.g.: - # U { min = -1.0; max = 1.0; } + # --- setting min-max for any variable + # this has to be defined if 'reset_time' is skipped, e.g.: + # U { min = -1.0; max = 1.0; } - # --- setting number of bins for any variable, e.g.: - # U { nbins = 512; } - } + # --- setting number of bins for any variable, e.g.: + # U { nbins = 512; } + } } # ----------------------------------------------------------------------------- joint_pdf { - # num = 1; + # num = 1; - unit_1 { - begin = 7.5 * 3600.0; - end = 9.0 * 3600.0; - dt = 1.0; + unit_1 { + begin = 7.5 * 3600.0; + end = 9.0 * 3600.0; + dt = 1.0; - zp = domain.z + 0.25 * domain.height; + zp = domain.z + 0.25 * domain.height; - output.SUBDIR = "joint-pdf/"; - dump.SUBDIR = "joint-pdf/"; + output.SUBDIR = "joint-pdf/"; + dump.SUBDIR = "joint-pdf/"; - cntrl_default = true; - nxbins_default = 256; - nybins_default = 256; + cntrl_default = true; + nxbins_default = 256; + nybins_default = 256; - # --- reset options: [begin, reset_time] -- find histogram parameters - # if not defined set min-max range for each variable in controls - reset_time = 8.0 * 3600.0; - reset_safety = 0.25; # relative to min-max found - # e.g.: min' = min - reset_safety * (max - min) + # --- reset options: [begin, reset_time] -- find histogram parameters + # if not defined set min-max range for each variable in controls + reset_time = 8.0 * 3600.0; + reset_safety = 0.25; # relative to min-max found + # e.g.: min' = min - reset_safety * (max - min) - # --- regular mode [optional] -- shifts accumulation window - # is_regular = false; + # --- regular mode [optional] -- shifts accumulation window + # is_regular = false; - # --- change default control using keys - # cntrl { - # UV = true; UW = true; VW = true; - # PSuu = true; PSvv = true; PSww = true; - # PSuv = true; PSuw = true; PSvw = true; - # TU = true; TV = true; TW = true; - # QU = true; QV = true; QW = true; - # QT = true; + # --- change default control using keys + # cntrl { + # UV = true; UW = true; VW = true; + # PSuu = true; PSvv = true; PSww = true; + # PSuv = true; PSuw = true; PSvw = true; + # TU = true; TV = true; TW = true; + # QU = true; QV = true; QW = true; + # QT = true; - # --- tracers 'C' correspond to passive_tracers {} def. [use index in: 1...passive_tracers.num] - # C1U = true; C1V = true; C1W = true; - # C1T = true; C1Q = true; - # --- tracer/tracer joint pdf, using strict upper diagonal notation, e.g.: - # C1C2 = true; C1C3 = true; C2C3 = true; - # - # } + # --- tracers 'C' correspond to passive_tracers {} def. [use index in: 1...passive_tracers.num] + # C1U = true; C1V = true; C1W = true; + # C1T = true; C1Q = true; + # --- tracer/tracer joint pdf, using strict upper diagonal notation, e.g.: + # C1C2 = true; C1C3 = true; C2C3 = true; + # + # } - # --- setting min-max for any variable - # this has to be defined if 'reset_time' is skipped, e.g.: - # UV { xmin = -1.0; xmax = 1.0; ymin = - 1.0; ymax = 1.0; } + # --- setting min-max for any variable + # this has to be defined if 'reset_time' is skipped, e.g.: + # UV { xmin = -1.0; xmax = 1.0; ymin = - 1.0; ymax = 1.0; } - # --- setting number of bins for any variable, e.g.: - # UV { nxbins = 512; nybins = 512; } - } + # --- setting number of bins for any variable, e.g.: + # UV { nxbins = 512; nybins = 512; } + } } # ----------------------------------------------------------------------------- runtime_filter { - # begin = 600.0; # set a regular filter - # dt = 600.0; + # begin = 600.0; # set a regular filter + # dt = 600.0; - mark = 600.0; # OR: apply filter at time = mark only - # mark has --higher-- priority than regular mode + mark = 600.0; # OR: apply filter at time = mark only + # mark has --higher-- priority than regular mode - # num = 0; # number of filters applied, output = sum of all units - # u = u_f[1] + u_f[2] + ... - # --- skipped if not defined + # num = 0; # number of filters applied, output = sum of all units + # u = u_f[1] + u_f[2] + ... + # --- skipped if not defined - unit_1 { - # --- keep some rolls - mode = "include"; - is_remove_mean = false; + unit_1 { + # --- keep some rolls + mode = "include"; + is_remove_mean = false; - kxmin = 0; kxmax = 0; - kymin = 0; kymax = 5; - } + kxmin = 0; kxmax = 0; + kymin = 0; kymax = 5; + } - unit_2 { - # --- add small scale disturbances - mode = "exclude"; # adding (u - u_f) - is_remove_mean = false; + unit_2 { + # --- add small scale disturbances + mode = "exclude"; # adding (u - u_f) + is_remove_mean = false; - kxmin = 0; kxmax = 10; - kymin = 0; kymax = 10; - } + kxmin = 0; kxmax = 10; + kymin = 0; kymax = 10; + } } # ----------------------------------------------------------------------------- diff --git a/config_manager.py b/config_manager.py index ba5a454..567d99f 100644 --- a/config_manager.py +++ b/config_manager.py @@ -2,32 +2,43 @@ import re import subprocess class ConfigManager: - def __init__(self, file_path, func): - self.file_path = file_path + def __init__(self, func): + self.file_path = "" self.get_value_func = func + self.lines = [] + self.config_data = {} + + def is_initialized(self): + return self.file_path != "" + def init(self, file_path): + self.lines = [] self.config_data = {} - self.parse_config() + self.file_path = file_path - def parse_config(self): output = subprocess.run(["config-parser/parser-cli", self.file_path], capture_output=True, text=True) for line in output.stdout.split("\n"): match = re.match(r" > (\w+) '(.*)' = *(.*)", line) if match: - value_type, path, value = match.groups() + self.lines.append(match.groups()) + + def construct_dict(self): + if self.config_data: + return - nss = path.split(".") + for value_type, path, value in self.lines: + nss = path.split(".") - cur_ns = self.config_data + cur_ns = self.config_data - for ns in nss[:-1]: - if ns not in cur_ns: - cur_ns[ns] = {} + for ns in nss[:-1]: + if ns not in cur_ns: + cur_ns[ns] = {} - cur_ns = cur_ns[ns] + cur_ns = cur_ns[ns] - cur_ns[nss[-1]] = (path, value_type) + cur_ns[nss[-1]] = (path, value_type) def get_value_str(self, path, value_type): value = self.get_value_func(path, value_type) @@ -40,6 +51,13 @@ class ConfigManager: return '0.0' elif value_type == 'BOOLEAN': return 'false' + else: + if value_type == 'STRING': + return f'"{value}"' + elif value_type == 'BOOLEAN': + return str(value).lower() + elif value_type == 'DOUBLE': + return "{:.7f}".format(value) return str(value) def write_namespace(self, file, ns, ns_name, indent): @@ -54,9 +72,11 @@ class ConfigManager: file.write(" " * indent + "}\n") file.write("\n") - def save_config(self, file_path=None): - if not file_path: - file_path = self.file_path + def save(self): + self.save_as(self.file_path) + + def save_as(self, file_path): + self.construct_dict() indent = 0 with open(file_path, "w", encoding="utf-8") as file: @@ -66,8 +86,6 @@ class ConfigManager: else: file.write(f"{key} = {self.get_value_str(*self.config_data[key])};\n") -file_path = "config.txt" - -cfg_manager = ConfigManager(file_path, lambda p, t: t[0]) - -cfg_manager.save_config("config_my.txt") \ No newline at end of file +# file_path = "config.txt" +# cfg_manager = ConfigManager(file_path, lambda p, t: t[0]) +# cfg_manager.save_config("config_my.txt") \ No newline at end of file diff --git a/config_my.txt b/config_my.txt deleted file mode 100644 index c4c5bd2..0000000 --- a/config_my.txt +++ /dev/null @@ -1,680 +0,0 @@ -MAIN_DIR = S; - -domain -{ - x = D; - y = D; - z = D; - length = D; - width = D; - height = D; -} - - -time -{ - begin = D; - end = D; - dt = D; - - calendar - { - mode = S; - year = I; - month = I; - day = I; - hour = I; - min = I; - sec = D; - UTC_offset = I; - } - -} - - -grid -{ - type = S; - filename = S; - cx = I; - cy = I; - cz = I; - ksi_z = D; - - adaptive - { - beta = D; - dz_min = D; - dz_max = D; - TKE_threshold_coeff = D; - hbl_max_coeff = D; - C_smooth_coeff = D; - nskip = I; - } - -} - - -mpi_setup -{ - dimx = I; - dimy = I; - dimz = I; -} - - -phys -{ - f = D; - nu = D; - xi = D; - rho_ref = D; - g = D; - Theta_ref = D; - beta = D; -} - - -topography -{ - mode = S; - npatch = I; - - patch_1 - { - type = S; - xmin = D; - xmax = D; - ymin = D; - ymax = D; - height = D; - xperiod = D; - yperiod = D; - } - -} - - -geo_wind -{ - U = D; - V = D; -} - - -external_pressure_grad -{ - dPdx = D; -} - - -surface -{ - - Theta - { - mode = S; - value = D; - } - - - Qhum - { - mode = S; - } - - z0_m = D; - z0_h = D; - kappa = D; - Pr_t_0 = D; - Cm = D; - Ch = D; - alpha_m = D; - alpha_h = D; - lhflux_alpha = D; - lhflux_beta = D; -} - - -initial_conditions -{ - - Theta - { - mode = S; - surface_value = D; - height = D; - grad_z = D; - } - - - Qhum - { - mode = S; - surface_value = D; - height = D; - grad_z = D; - } - -} - - -damping -{ - is_enabled = B; - f = D; - z1 = D; - z2 = D; -} - - -les -{ - is_dynamic_momentum = B; - is_dynamic_scalar = B; - is_ssm_mixed_momentum = B; - is_ssm_mixed_scalar = B; - is_amd_model = B; - C_ssm_momentum = D; - C_ssm_scalar = D; - C_smag = D; - Prandtl_sgs = D; - - dynamic - { - C_smag_max = D; - Prandtl_sgs_min = D; - alpha = D; - avg_mode = S; - nskip = I; - use_transport = B; - C_T_lagrange_momentum = D; - C_T_lagrange_scalar = D; - } - - base_filter_reset = B; - test_filter_reset = B; - clip_filter_reset = B; -} - - -passive_tracers -{ - - tracer_1 - { - diffusivity = D; - - surface - { - flux = D; - xmin = D; - xmax = D; - ymin = D; - ymax = D; - begin = D; - } - - } - - - tracer_2 - { - diffusivity = D; - - surface - { - flux = D; - begin = D; - } - - } - -} - - -ptcl -{ - is_passive_transport = B; - density = D; - diameter = D; - g = D; - nsources = I; - - source_1 - { - n = I; - begin = D; - end = D; - xmin = D; - xmax = D; - ymin = D; - ymax = D; - zmin = D; - zmax = D; - } - - nsinks = I; - - sink_1 - { - mode = S; - xmin = D; - xmax = D; - ymin = D; - ymax = D; - zmin = D; - zmax = D; - } - -} - - -ptcl_track -{ - is_passive_transport = B; - density = D; - diameter = D; - g = D; - group_max_size = I; - max_memory = I; - nsources = I; - - source_1 - { - n = I; - begin = D; - xmin = D; - xmax = D; - ymin = D; - ymax = D; - zmin = D; - zmax = D; - } - - nsinks = I; -} - - -canopy -{ - Cd = D; - drag_type = S; - num = I; - - patch_1 - { - type = S; - xmin = D; - xmax = D; - ymin = D; - ymax = D; - zmin = D; - zmax = D; - LAI = D; - } - -} - - -poisson -{ - retol = D; - abstol = D; - miniters = I; - maxiters = I; - piters = I; - - multigrid - { - ngrid = I; - down_iters = I; - up_iters = I; - direct_iters = I; - smooth_up_omega = D; - smooth_up_omega_fine = D; - } - -} - - -output -{ - DIR = S; - make_unique_DIR = B; - convert_dsq_to_tecplot = B; - num = I; - - unit_1 - { - SUBDIR = S; - begin = D; - dt = D; - xmin = D; - xmax = D; - ymin = D; - ymax = D; - zmin = D; - zmax = D; - cntrl_avgxy_plt = B; - cntrl_avgxy_netcdf = B; - cntrl_3d_plt = B; - cntrl_3d_bin = B; - cntrl_3d_netcdf = B; - cntrl_geometry_3d_plt = B; - cntrl_geometry_3d_netcdf = B; - cntrl_topography_plt = B; - cntrl_topography_netcdf = B; - cntrl_2d_plt = B; - cntrl_2d_netcdf = B; - cntrl_surface_plt = B; - cntrl_surface_netcdf = B; - cntrl_grid_plt = B; - cntrl_grid_netcdf = B; - cntrl_meteo_avgxy_plt = B; - cntrl_meteo_all_plt = B; - cntrl_filtered_3d_plt = B; - - spectrum - { - x_cntrl = B; - y_cntrl = B; - xy_cntrl = B; - z_1 = D; - z_2 = D; - } - - cntrl_ptcl_bin = B; - cntrl_ptcl_plt = B; - cntrl_ptcl_coords_plt = B; - cntrl_ptcl_traj_bin = B; - cntrl_ptcl_traj_plt = B; - x_profile_num = I; - y_profile_num = I; - z_profile_num = I; - - x_profile_1 - { - y = D; - z = D; - } - - xy_slice_num = I; - xz_slice_num = I; - yz_slice_num = I; - - xy_slice_1 - { - z = D; - } - - } - - - screen - { - begin = D; - dt = D; - } - -} - - -checkup -{ - begin = D; - nskip = I; -} - - -dump -{ - DIR = S; - begin = D; - dt = D; -} - - -startup -{ - DIR = S; -} - - -series -{ - begin = D; - dt = D; - - point_set - { - - point_1 - { - x = D; - y = D; - z = D; - } - - - point_2 - { - x = D; - y = D; - z = D; - } - - - point_3 - { - x = D; - y = D; - z = D; - } - - } - - - energy_avgxy_set - { - z_1 = D; - z_2 = D; - } - - - flux_avgxy_set - { - z_1 = D; - z_2 = D; - } - -} - - -spectrum_series -{ - begin = D; - nskip = I; - - unit_1 - { - zp = D; - kxmax = I; - kymax = I; - } - - - unit_2 - { - zp = D; - kxmax = I; - kymax = I; - } - - - unit_3 - { - zp = D; - kxmax = I; - kymax = I; - } - -} - - -time_scan -{ - begin = D; - dt = D; - cntrl_grid = B; - cntrl_avgxy = B; - cntrl_z_profile = B; - z_profile_num = I; - - z_profile_1 - { - x = D; - y = D; - } - -} - - -stats -{ - num = I; - - unit_1 - { - begin = D; - end = D; - nskip = I; - axis = S; - type = S; - - output - { - SUBDIR = S; - } - - - dump - { - SUBDIR = S; - } - - } - - - unit_2 - { - begin = D; - end = D; - nskip = I; - axis = S; - type = S; - - output - { - SUBDIR = S; - } - - - dump - { - SUBDIR = S; - } - - } - -} - - -pdf -{ - - unit_1 - { - begin = D; - end = D; - dt = D; - zp = D; - - output - { - SUBDIR = S; - } - - - dump - { - SUBDIR = S; - } - - cntrl_default = B; - nbins_default = I; - reset_time = D; - reset_safety = D; - } - -} - - -joint_pdf -{ - - unit_1 - { - begin = D; - end = D; - dt = D; - zp = D; - - output - { - SUBDIR = S; - } - - - dump - { - SUBDIR = S; - } - - cntrl_default = B; - nxbins_default = I; - nybins_default = I; - reset_time = D; - reset_safety = D; - } - -} - - -runtime_filter -{ - mark = D; - - unit_1 - { - mode = S; - is_remove_mean = B; - kxmin = I; - kxmax = I; - kymin = I; - kymax = I; - } - - - unit_2 - { - mode = S; - is_remove_mean = B; - kxmin = I; - kxmax = I; - kymin = I; - kymax = I; - } - -} - diff --git a/configparsed.txt b/configparsed.txt deleted file mode 100644 index 4d0f6ef..0000000 --- a/configparsed.txt +++ /dev/null @@ -1,310 +0,0 @@ - > STRING 'MAIN_DIR' = - > DOUBLE 'domain.x' = 0.000000 - > DOUBLE 'domain.y' = 0.000000 - > DOUBLE 'domain.z' = 0.000000 - > DOUBLE 'domain.length' = 400.000000 - > DOUBLE 'domain.width' = 200.000000 - > DOUBLE 'domain.height' = 80.000000 - > DOUBLE 'time.begin' = 0.000000 - > DOUBLE 'time.end' = 180000.000000 - > DOUBLE 'time.dt' = 0.200000 - > STRING 'time.calendar.mode' = local - > INT 'time.calendar.year' = 2020 - > INT 'time.calendar.month' = 9 - > INT 'time.calendar.day' = 1 - > INT 'time.calendar.hour' = 12 - > INT 'time.calendar.min' = 0 - > DOUBLE 'time.calendar.sec' = 0.000000 - > INT 'time.calendar.UTC_offset' = 3 - > STRING 'grid.type' = uniform - > STRING 'grid.filename' = z-coord.txt - > INT 'grid.cx' = 80 - > INT 'grid.cy' = 40 - > INT 'grid.cz' = 16 - > DOUBLE 'grid.ksi_z' = 1.200000 - > DOUBLE 'grid.adaptive.beta' = 0.300000 - > DOUBLE 'grid.adaptive.dz_min' = 1.250000 - > DOUBLE 'grid.adaptive.dz_max' = 20.000000 - > DOUBLE 'grid.adaptive.TKE_threshold_coeff' = 0.100000 - > DOUBLE 'grid.adaptive.hbl_max_coeff' = 1.100000 - > DOUBLE 'grid.adaptive.C_smooth_coeff' = 5.000000 - > INT 'grid.adaptive.nskip' = 1 - > INT 'mpi_setup.dimx' = 2 - > INT 'mpi_setup.dimy' = 2 - > INT 'mpi_setup.dimz' = 1 - > DOUBLE 'phys.f' = 0.000000 - > DOUBLE 'phys.nu' = 0.000013 - > DOUBLE 'phys.xi' = 0.000018 - > DOUBLE 'phys.rho_ref' = 1.250000 - > DOUBLE 'phys.g' = 9.810000 - > DOUBLE 'phys.Theta_ref' = 288.150000 - > DOUBLE 'phys.beta' = 0.000000 - > STRING 'topography.mode' = hand - > INT 'topography.npatch' = 1 - > STRING 'topography.patch_1.type' = box - > DOUBLE 'topography.patch_1.xmin' = 15.000000 - > DOUBLE 'topography.patch_1.xmax' = 35.000000 - > DOUBLE 'topography.patch_1.ymin' = 10.000000 - > DOUBLE 'topography.patch_1.ymax' = 90.000000 - > DOUBLE 'topography.patch_1.height' = 20.000000 - > DOUBLE 'topography.patch_1.xperiod' = 50.000000 - > DOUBLE 'topography.patch_1.yperiod' = 100.000000 - > DOUBLE 'geo_wind.U' = 0.000000 - > DOUBLE 'geo_wind.V' = 0.000000 - > DOUBLE 'external_pressure_grad.dPdx' = -0.000400 - > STRING 'surface.Theta.mode' = const - > DOUBLE 'surface.Theta.value' = 288.150000 - > STRING 'surface.Qhum.mode' = lsm - > DOUBLE 'surface.z0_m' = 0.100000 - > DOUBLE 'surface.z0_h' = 0.100000 - > DOUBLE 'surface.kappa' = 0.400000 - > DOUBLE 'surface.Pr_t_0' = 1.000000 - > DOUBLE 'surface.Cm' = 4.800000 - > DOUBLE 'surface.Ch' = 7.800000 - > DOUBLE 'surface.alpha_m' = 16.000000 - > DOUBLE 'surface.alpha_h' = 16.000000 - > DOUBLE 'surface.lhflux_alpha' = 1.000000 - > DOUBLE 'surface.lhflux_beta' = 0.025000 - > STRING 'initial_conditions.Theta.mode' = const - > DOUBLE 'initial_conditions.Theta.surface_value' = 288.150000 - > DOUBLE 'initial_conditions.Theta.height' = 0.000000 - > DOUBLE 'initial_conditions.Theta.grad_z' = 0.000000 - > STRING 'initial_conditions.Qhum.mode' = mixed-layer - > DOUBLE 'initial_conditions.Qhum.surface_value' = 0.002500 - > DOUBLE 'initial_conditions.Qhum.height' = 0.000000 - > DOUBLE 'initial_conditions.Qhum.grad_z' = 0.000000 - > BOOLEAN 'damping.is_enabled' = false - > DOUBLE 'damping.f' = 0.200000 - > DOUBLE 'damping.z1' = 60.000000 - > DOUBLE 'damping.z2' = 80.000000 - > BOOLEAN 'les.is_dynamic_momentum' = true - > BOOLEAN 'les.is_dynamic_scalar' = true - > BOOLEAN 'les.is_ssm_mixed_momentum' = false - > BOOLEAN 'les.is_ssm_mixed_scalar' = false - > BOOLEAN 'les.is_amd_model' = false - > DOUBLE 'les.C_ssm_momentum' = 1.000000 - > DOUBLE 'les.C_ssm_scalar' = 1.000000 - > DOUBLE 'les.C_smag' = 0.080000 - > DOUBLE 'les.Prandtl_sgs' = 0.700000 - > DOUBLE 'les.dynamic.C_smag_max' = 0.250000 - > DOUBLE 'les.dynamic.Prandtl_sgs_min' = 0.400000 - > DOUBLE 'les.dynamic.alpha' = 1.730000 - > STRING 'les.dynamic.avg_mode' = lagrange - > INT 'les.dynamic.nskip' = 3 - > BOOLEAN 'les.dynamic.use_transport' = false - > DOUBLE 'les.dynamic.C_T_lagrange_momentum' = 1.500000 - > DOUBLE 'les.dynamic.C_T_lagrange_scalar' = 3.000000 - > BOOLEAN 'les.base_filter_reset' = false - > BOOLEAN 'les.test_filter_reset' = false - > BOOLEAN 'les.clip_filter_reset' = false - > DOUBLE 'passive_tracers.tracer_1.diffusivity' = 0.000018 - > DOUBLE 'passive_tracers.tracer_1.surface.flux' = -0.010000 - > DOUBLE 'passive_tracers.tracer_1.surface.xmin' = 180.000000 - > DOUBLE 'passive_tracers.tracer_1.surface.xmax' = 220.000000 - > DOUBLE 'passive_tracers.tracer_1.surface.ymin' = 180.000000 - > DOUBLE 'passive_tracers.tracer_1.surface.ymax' = 220.000000 - > DOUBLE 'passive_tracers.tracer_1.surface.begin' = 25200.000000 - > DOUBLE 'passive_tracers.tracer_2.diffusivity' = 0.000018 - > DOUBLE 'passive_tracers.tracer_2.surface.flux' = -0.020000 - > DOUBLE 'passive_tracers.tracer_2.surface.begin' = 25200.000000 - > BOOLEAN 'ptcl.is_passive_transport' = false - > DOUBLE 'ptcl.density' = 1000.000000 - > DOUBLE 'ptcl.diameter' = 0.000001 - > DOUBLE 'ptcl.g' = -9.810000 - > INT 'ptcl.nsources' = 1 - > INT 'ptcl.source_1.n' = 4194304 - > DOUBLE 'ptcl.source_1.begin' = 18000.000000 - > DOUBLE 'ptcl.source_1.end' = 180000.000000 - > DOUBLE 'ptcl.source_1.xmin' = 40.000000 - > DOUBLE 'ptcl.source_1.xmax' = 60.000000 - > DOUBLE 'ptcl.source_1.ymin' = 0.000000 - > DOUBLE 'ptcl.source_1.ymax' = 200.000000 - > DOUBLE 'ptcl.source_1.zmin' = 0.000000 - > DOUBLE 'ptcl.source_1.zmax' = 5.000000 - > INT 'ptcl.nsinks' = 1 - > STRING 'ptcl.sink_1.mode' = outside - > DOUBLE 'ptcl.sink_1.xmin' = 0.000000 - > DOUBLE 'ptcl.sink_1.xmax' = 400.000000 - > DOUBLE 'ptcl.sink_1.ymin' = -100.000000 - > DOUBLE 'ptcl.sink_1.ymax' = 300.000000 - > DOUBLE 'ptcl.sink_1.zmin' = 0.010000 - > DOUBLE 'ptcl.sink_1.zmax' = 80.000000 - > BOOLEAN 'ptcl_track.is_passive_transport' = false - > DOUBLE 'ptcl_track.density' = 1000.000000 - > DOUBLE 'ptcl_track.diameter' = 0.000001 - > DOUBLE 'ptcl_track.g' = -9.810000 - > INT 'ptcl_track.group_max_size' = 256 - > INT 'ptcl_track.max_memory' = 10485760 - > INT 'ptcl_track.nsources' = 1 - > INT 'ptcl_track.source_1.n' = 128 - > DOUBLE 'ptcl_track.source_1.begin' = 28800.000000 - > DOUBLE 'ptcl_track.source_1.xmin' = 160.000000 - > DOUBLE 'ptcl_track.source_1.xmax' = 240.000000 - > DOUBLE 'ptcl_track.source_1.ymin' = 80.000000 - > DOUBLE 'ptcl_track.source_1.ymax' = 120.000000 - > DOUBLE 'ptcl_track.source_1.zmin' = 0.000000 - > DOUBLE 'ptcl_track.source_1.zmax' = 8.000000 - > INT 'ptcl_track.nsinks' = 0 - > DOUBLE 'canopy.Cd' = 0.150000 - > STRING 'canopy.drag_type' = non-linear - > INT 'canopy.num' = 0 - > STRING 'canopy.patch_1.type' = sharp - > DOUBLE 'canopy.patch_1.xmin' = 0.000000 - > DOUBLE 'canopy.patch_1.xmax' = 400.000000 - > DOUBLE 'canopy.patch_1.ymin' = 0.000000 - > DOUBLE 'canopy.patch_1.ymax' = 200.000000 - > DOUBLE 'canopy.patch_1.zmin' = 0.000000 - > DOUBLE 'canopy.patch_1.zmax' = 50.000000 - > DOUBLE 'canopy.patch_1.LAI' = 1.000000 - > DOUBLE 'poisson.retol' = 0.000100 - > DOUBLE 'poisson.abstol' = 0.000010 - > INT 'poisson.miniters' = 1 - > INT 'poisson.maxiters' = 100 - > INT 'poisson.piters' = 1 - > INT 'poisson.multigrid.ngrid' = 5 - > INT 'poisson.multigrid.down_iters' = 2 - > INT 'poisson.multigrid.up_iters' = 3 - > INT 'poisson.multigrid.direct_iters' = 5 - > DOUBLE 'poisson.multigrid.smooth_up_omega' = 1.840000 - > DOUBLE 'poisson.multigrid.smooth_up_omega_fine' = 1.640000 - > STRING 'output.DIR' = output/ - > BOOLEAN 'output.make_unique_DIR' = true - > BOOLEAN 'output.convert_dsq_to_tecplot' = true - > INT 'output.num' = 1 - > STRING 'output.unit_1.SUBDIR' = - > DOUBLE 'output.unit_1.begin' = 3600.000000 - > DOUBLE 'output.unit_1.dt' = 3600.000000 - > DOUBLE 'output.unit_1.xmin' = 0.000000 - > DOUBLE 'output.unit_1.xmax' = 400.000000 - > DOUBLE 'output.unit_1.ymin' = 0.000000 - > DOUBLE 'output.unit_1.ymax' = 200.000000 - > DOUBLE 'output.unit_1.zmin' = 0.000000 - > DOUBLE 'output.unit_1.zmax' = 80.000000 - > BOOLEAN 'output.unit_1.cntrl_avgxy_plt' = true - > BOOLEAN 'output.unit_1.cntrl_avgxy_netcdf' = false - > BOOLEAN 'output.unit_1.cntrl_3d_plt' = true - > BOOLEAN 'output.unit_1.cntrl_3d_bin' = false - > BOOLEAN 'output.unit_1.cntrl_3d_netcdf' = false - > BOOLEAN 'output.unit_1.cntrl_geometry_3d_plt' = false - > BOOLEAN 'output.unit_1.cntrl_geometry_3d_netcdf' = false - > BOOLEAN 'output.unit_1.cntrl_topography_plt' = true - > BOOLEAN 'output.unit_1.cntrl_topography_netcdf' = false - > BOOLEAN 'output.unit_1.cntrl_2d_plt' = false - > BOOLEAN 'output.unit_1.cntrl_2d_netcdf' = false - > BOOLEAN 'output.unit_1.cntrl_surface_plt' = true - > BOOLEAN 'output.unit_1.cntrl_surface_netcdf' = false - > BOOLEAN 'output.unit_1.cntrl_grid_plt' = false - > BOOLEAN 'output.unit_1.cntrl_grid_netcdf' = false - > BOOLEAN 'output.unit_1.cntrl_meteo_avgxy_plt' = false - > BOOLEAN 'output.unit_1.cntrl_meteo_all_plt' = false - > BOOLEAN 'output.unit_1.cntrl_filtered_3d_plt' = false - > BOOLEAN 'output.unit_1.spectrum.x_cntrl' = true - > BOOLEAN 'output.unit_1.spectrum.y_cntrl' = true - > BOOLEAN 'output.unit_1.spectrum.xy_cntrl' = true - > DOUBLE 'output.unit_1.spectrum.z_1' = 50.000000 - > DOUBLE 'output.unit_1.spectrum.z_2' = 100.000000 - > BOOLEAN 'output.unit_1.cntrl_ptcl_bin' = false - > BOOLEAN 'output.unit_1.cntrl_ptcl_plt' = true - > BOOLEAN 'output.unit_1.cntrl_ptcl_coords_plt' = false - > BOOLEAN 'output.unit_1.cntrl_ptcl_traj_bin' = false - > BOOLEAN 'output.unit_1.cntrl_ptcl_traj_plt' = false - > INT 'output.unit_1.x_profile_num' = 0 - > INT 'output.unit_1.y_profile_num' = 0 - > INT 'output.unit_1.z_profile_num' = 0 - > DOUBLE 'output.unit_1.x_profile_1.y' = 100.000000 - > DOUBLE 'output.unit_1.x_profile_1.z' = 40.000000 - > INT 'output.unit_1.xy_slice_num' = 0 - > INT 'output.unit_1.xz_slice_num' = 0 - > INT 'output.unit_1.yz_slice_num' = 0 - > DOUBLE 'output.unit_1.xy_slice_1.z' = 40.000000 - > DOUBLE 'output.screen.begin' = 0.000000 - > DOUBLE 'output.screen.dt' = 180.000000 - > DOUBLE 'checkup.begin' = 0.000000 - > INT 'checkup.nskip' = 3600 - > STRING 'dump.DIR' = dump/ - > DOUBLE 'dump.begin' = 36000.000000 - > DOUBLE 'dump.dt' = 36000.000000 - > STRING 'startup.DIR' = init/ - > DOUBLE 'series.begin' = 60.000000 - > DOUBLE 'series.dt' = 1.000000 - > DOUBLE 'series.point_set.point_1.x' = 200.000000 - > DOUBLE 'series.point_set.point_1.y' = 100.000000 - > DOUBLE 'series.point_set.point_1.z' = 25.000000 - > DOUBLE 'series.point_set.point_2.x' = 200.000000 - > DOUBLE 'series.point_set.point_2.y' = 100.000000 - > DOUBLE 'series.point_set.point_2.z' = 50.000000 - > DOUBLE 'series.point_set.point_3.x' = 200.000000 - > DOUBLE 'series.point_set.point_3.y' = 100.000000 - > DOUBLE 'series.point_set.point_3.z' = 100.000000 - > DOUBLE 'series.energy_avgxy_set.z_1' = 50.000000 - > DOUBLE 'series.energy_avgxy_set.z_2' = 100.000000 - > DOUBLE 'series.flux_avgxy_set.z_1' = 50.000000 - > DOUBLE 'series.flux_avgxy_set.z_2' = 100.000000 - > DOUBLE 'spectrum_series.begin' = 0.000000 - > INT 'spectrum_series.nskip' = 1 - > DOUBLE 'spectrum_series.unit_1.zp' = 24.000000 - > INT 'spectrum_series.unit_1.kxmax' = 3 - > INT 'spectrum_series.unit_1.kymax' = 3 - > DOUBLE 'spectrum_series.unit_2.zp' = 16.000000 - > INT 'spectrum_series.unit_2.kxmax' = 3 - > INT 'spectrum_series.unit_2.kymax' = 3 - > DOUBLE 'spectrum_series.unit_3.zp' = 8.000000 - > INT 'spectrum_series.unit_3.kxmax' = 3 - > INT 'spectrum_series.unit_3.kymax' = 3 - > DOUBLE 'time_scan.begin' = 60.000000 - > DOUBLE 'time_scan.dt' = 60.000000 - > BOOLEAN 'time_scan.cntrl_grid' = false - > BOOLEAN 'time_scan.cntrl_avgxy' = true - > BOOLEAN 'time_scan.cntrl_z_profile' = false - > INT 'time_scan.z_profile_num' = 0 - > DOUBLE 'time_scan.z_profile_1.x' = 200.000000 - > DOUBLE 'time_scan.z_profile_1.y' = 100.000000 - > INT 'stats.num' = 2 - > DOUBLE 'stats.unit_1.begin' = 165600.000000 - > DOUBLE 'stats.unit_1.end' = 180000.000000 - > INT 'stats.unit_1.nskip' = 10 - > STRING 'stats.unit_1.axis' = XYZ - > STRING 'stats.unit_1.type' = energy-eq - > STRING 'stats.unit_1.output.SUBDIR' = stat_end/ - > STRING 'stats.unit_1.dump.SUBDIR' = stat_end/ - > DOUBLE 'stats.unit_2.begin' = 151200.000000 - > DOUBLE 'stats.unit_2.end' = 165600.000000 - > INT 'stats.unit_2.nskip' = 10 - > STRING 'stats.unit_2.axis' = XYZ - > STRING 'stats.unit_2.type' = energy-eq - > STRING 'stats.unit_2.output.SUBDIR' = stat_end-1/ - > STRING 'stats.unit_2.dump.SUBDIR' = stat_end-1 - > DOUBLE 'pdf.unit_1.begin' = 27000.000000 - > DOUBLE 'pdf.unit_1.end' = 32400.000000 - > DOUBLE 'pdf.unit_1.dt' = 1.000000 - > DOUBLE 'pdf.unit_1.zp' = 20.000000 - > STRING 'pdf.unit_1.output.SUBDIR' = pdf/ - > STRING 'pdf.unit_1.dump.SUBDIR' = pdf/ - > BOOLEAN 'pdf.unit_1.cntrl_default' = true - > INT 'pdf.unit_1.nbins_default' = 256 - > DOUBLE 'pdf.unit_1.reset_time' = 28800.000000 - > DOUBLE 'pdf.unit_1.reset_safety' = 0.250000 - > DOUBLE 'joint_pdf.unit_1.begin' = 27000.000000 - > DOUBLE 'joint_pdf.unit_1.end' = 32400.000000 - > DOUBLE 'joint_pdf.unit_1.dt' = 1.000000 - > DOUBLE 'joint_pdf.unit_1.zp' = 20.000000 - > STRING 'joint_pdf.unit_1.output.SUBDIR' = joint-pdf/ - > STRING 'joint_pdf.unit_1.dump.SUBDIR' = joint-pdf/ - > BOOLEAN 'joint_pdf.unit_1.cntrl_default' = true - > INT 'joint_pdf.unit_1.nxbins_default' = 256 - > INT 'joint_pdf.unit_1.nybins_default' = 256 - > DOUBLE 'joint_pdf.unit_1.reset_time' = 28800.000000 - > DOUBLE 'joint_pdf.unit_1.reset_safety' = 0.250000 - > DOUBLE 'runtime_filter.mark' = 600.000000 - > STRING 'runtime_filter.unit_1.mode' = include - > BOOLEAN 'runtime_filter.unit_1.is_remove_mean' = false - > INT 'runtime_filter.unit_1.kxmin' = 0 - > INT 'runtime_filter.unit_1.kxmax' = 0 - > INT 'runtime_filter.unit_1.kymin' = 0 - > INT 'runtime_filter.unit_1.kymax' = 5 - > STRING 'runtime_filter.unit_2.mode' = exclude - > BOOLEAN 'runtime_filter.unit_2.is_remove_mean' = false - > INT 'runtime_filter.unit_2.kxmin' = 0 - > INT 'runtime_filter.unit_2.kxmax' = 10 - > INT 'runtime_filter.unit_2.kymin' = 0 - > INT 'runtime_filter.unit_2.kymax' = 10 \ No newline at end of file diff --git a/dpg_gui_styles.py b/dpg_gui_styles.py index eadb9d9..c449d18 100644 --- a/dpg_gui_styles.py +++ b/dpg_gui_styles.py @@ -4,7 +4,7 @@ FONT_PATH = "D:\\fonts\\Montserrat\\static\\Montserrat-Medium.ttf" ACCENT_COLOR = (0, 119, 200, 100) ROUNDING = 10 SPACE = 10 -INDENT = 30 +INDENT = 40 class GuiStyle: def __init__(self): diff --git a/dpg_gui_tabs.py b/dpg_gui_tabs.py index 18b081f..8c77121 100644 --- a/dpg_gui_tabs.py +++ b/dpg_gui_tabs.py @@ -10,107 +10,115 @@ class ConfigEditor: def __init__(self): dpg.create_context() - self.construct_main_window() - self.styles = GuiStyle() - # self.cfg_manager = ConfigManager() + self.cfg_manager = ConfigManager(self.get_value) + + self.construct_main_window() dpg.bind_font(self.styles.montserrat_font) dpg.bind_theme(self.styles.main_theme) - self.config_data = [] - - dpg.create_viewport(title='config file editor', width=800, height=600) + dpg.create_viewport(title='config file editor', width=800, height=600, small_icon='icon.ico') dpg.setup_dearpygui() dpg.show_viewport() dpg.set_primary_window("main", True) - def open_file(self, sender, app_data, user_data): + def manage_file(self, sender, app_data, user_data): file_path = app_data['file_path_name'] - if file_path: - for line in open(file_path, 'r', encoding='utf-8'): - match = re.match(r" > (\w+) '([\w.]+)' = (.*)", line) - if match: - self.config_data.append(match.groups()) - self.construct_config_window(file_path) + if user_data == "open": + if self.cfg_manager.is_initialized(): + dpg.delete_item(self.cfg_manager.file_path) + if dpg.does_alias_exist(self.cfg_manager.file_path): + dpg.remove_alias(self.cfg_manager.file_path) + for _, path, _ in self.cfg_manager.lines: + namespaces = path.split('.') + for i in range(len(namespaces)): + path = '.'.join(namespaces[:i+1]) + if dpg.does_alias_exist(path): + dpg.remove_alias(path) + + self.cfg_manager.init(file_path) + self.construct_config_window() + elif user_data == "save_as": + self.cfg_manager.save_as(file_path) + + def set_file_path(self, sender, app_data, user_data): + file_path = app_data['file_path_name'] + dpg.set_value(user_data, file_path) - def check_tabview(self, root): - for uuid in dpg.get_item_children(root, 1): - if dpg.get_item_type(uuid) == "mvAppItemType::mvTabBar": - return True, uuid - return False, None + def get_value(self, path, value_type): + return dpg.get_value(path) + + def open_file_dialog(self, sender, app_data, user_data): + dpg.show_item("file_dialog") + dpg.set_item_user_data("file_dialog", user_data) + + def open_folder_dialog(self, sender, app_data, user_data): + dpg.show_item("folder_dialog") + dpg.set_item_user_data("folder_dialog", user_data) def construct_main_window(self): - with dpg.window(label="config file editor", width=800, height=600, tag="main"): + with dpg.window(label="config file editor", width=800, height=600, tag="main", menubar=True, no_resize=False, no_close=False, no_move=False, no_collapse=False): with dpg.menu_bar(): with dpg.menu(label="file"): - dpg.add_menu_item(label="open config file", callback=lambda _: dpg.show_item("file_dialog"), tag="open_file_btn") + dpg.add_menu_item(label="open", callback=self.open_file_dialog, tag="open_btn", user_data="open") + dpg.add_menu_item(label="save", callback=self.cfg_manager.save, tag="save_btn") + dpg.add_menu_item(label="save as", callback=self.open_file_dialog, tag="save_as_btn", user_data="save_as") with dpg.menu(label="view"): dpg.add_menu_item(label="use default theme", check=True, callback=lambda _, v: dpg.bind_theme(None if v else self.styles.main_theme), default_value=False) dpg.add_menu_item(label="use default font", check=True, callback=lambda _, v: dpg.bind_font(None if v else self.styles.montserrat_font), default_value=False) dpg.add_menu_item(label="show theme editor", callback=dpg.show_style_editor) - with dpg.file_dialog(directory_selector=False, show=False, callback=self.open_file, tag="file_dialog", width=500, height=400): + with dpg.menu(label="settings"): + dpg.add_menu_item(label="auto save [not impl]", check=True, callback=lambda: print("TODO"), default_value=False) + + with dpg.file_dialog(directory_selector=False, show=False, callback=self.manage_file, tag="file_dialog", width=500, height=400): dpg.add_file_extension(".txt", color=(0, 255, 0, 255)) dpg.add_file_extension(".*", color=(255, 255, 255, 255)) - def construct_config_window(self, filename): - for var_type, full_path, value in self.config_data: - namespaces = full_path.split('.') - root = "main" - for level in range(len(namespaces) - 1): - path = '.'.join(namespaces[:level+1]) - - if not dpg.does_item_exist(path): - dpg.add_collapsing_header(label=namespaces[level], parent=root, tag=path, indent=INDENT) - - root = path + with dpg.file_dialog(directory_selector=True, show=False, callback=self.set_file_path, tag="folder_dialog", width=500, height=400): + dpg.add_file_extension(".*", color=(255, 255, 255, 255)) - self.create_widget('.'.join(namespaces[:-1]), namespaces[-1], value, var_type) + def construct_config_window(self): + dpg.add_collapsing_header(label=self.cfg_manager.file_path, parent="main", tag=self.cfg_manager.file_path, indent=0, default_open=True) - def construct_config_window_tabs(self, filename): - for var_type, full_path, value in self.config_data: + for var_type, full_path, value in self.cfg_manager.lines: namespaces = full_path.split('.') - root = "main" + parent = self.cfg_manager.file_path for level in range(len(namespaces) - 1): path = '.'.join(namespaces[:level+1]) - tab_bar_exists, tab_bar_uuid = self.check_tabview(root) - - if not tab_bar_exists: - tab_bar_uuid = dpg.add_tab_bar(parent=root, tag=f"{path}_tb") - if not dpg.does_item_exist(path): - dpg.add_tab(label=namespaces[level], parent=tab_bar_uuid, tag=f"{path}_tab") - dpg.add_child_window(parent=f"{path}_tab", tag=path, border=True, autosize_x=True, autosize_y=True) + dpg.add_collapsing_header(label=namespaces[level], parent=parent, tag=path, indent=INDENT) - root = path + parent = path self.create_widget('.'.join(namespaces[:-1]), namespaces[-1], value, var_type) def create_widget(self, path, key, value, value_type): - parent = path - - with dpg.group(horizontal=True, parent=parent): + if path: + parent = path + tag = f"{path}.{key}" + else: + parent = self.cfg_manager.file_path + tag = key + + with dpg.group(horizontal=True, parent=parent, indent=INDENT): dpg.add_text(key) if value_type == 'BOOLEAN': - dpg.add_checkbox(default_value=(value.lower() == "true")) + dpg.add_checkbox(default_value=(value.lower() == "true"), tag=tag) elif value_type == 'DOUBLE': - dpg.add_input_float(default_value=float(value)) + dpg.add_input_double(default_value=float(value), tag=tag, format="%.10f") elif value_type == 'INT': - dpg.add_input_int(default_value=int(value)) + dpg.add_input_int(default_value=int(value), tag=tag) elif "dir" in key.lower(): - dpg.add_input_text(default_value=value, tag=f"{path}.{key}") - dpg.add_button(label="...", callback=lambda s, a, u: self.file_dialog(f"{path}.{key}")) + dpg.add_input_text(default_value=value, tag=tag) + dpg.add_button(label="...", callback=self.open_folder_dialog, user_data=tag) else: - dpg.add_input_text(default_value=value) - - def file_dialog(self, var_tag): - with dpg.file_dialog(directory_selector=True, show=True, callback=lambda s, a, u: dpg.set_value(var_tag, a['file_path_name'])): - dpg.add_file_extension(".*", color=(255, 255, 255, 255)) + dpg.add_input_text(default_value=value, tag=tag) def run(self): dpg.start_dearpygui() diff --git a/dpg_gui_windows.py b/dpg_gui_windows.py deleted file mode 100644 index fb2fc99..0000000 --- a/dpg_gui_windows.py +++ /dev/null @@ -1,137 +0,0 @@ -import dearpygui.dearpygui as dpg -import re -import ctypes - -ctypes.windll.shcore.SetProcessDpiAwareness(1) - -FONT_PATH = "D:\\fonts\\Montserrat\\static\\Montserrat-Medium.ttf" - -class ConfigEditor: - def __init__(self): - self.config_data = {} - - dpg.create_context() - - with dpg.window(label="Config File Editor", width=800, height=600, tag="main"): - dpg.add_button(label="Open Config File", callback=self.open_file_dialog) - - with dpg.file_dialog(directory_selector=False, show=False, callback=self.open_file, tag="file_dialog", width=700 ,height=400): - dpg.add_file_extension(".txt", color=(0, 255, 0, 255)) - dpg.add_file_extension(".*", color=(255, 255, 255, 255)) - - with dpg.font_registry(): - default_font = dpg.add_font(FONT_PATH, 30) - second_font = dpg.add_font(FONT_PATH, 15) - - dpg.bind_font(default_font) - - with dpg.theme() as global_theme: - with dpg.theme_component(dpg.mvAll): - dpg.add_theme_color(dpg.mvThemeCol_Separator, (255, 0, 0), category=dpg.mvThemeCat_Core) - dpg.add_theme_style(dpg.mvStyleVar_ChildRounding, 5, category=dpg.mvThemeCat_Core) - dpg.add_theme_style(dpg.mvStyleVar_ItemSpacing, 10, 10, category=dpg.mvThemeCat_Core) - dpg.add_theme_style(dpg.mvStyleVar_ItemInnerSpacing, 10, 10, category=dpg.mvThemeCat_Core) - dpg.add_theme_style(dpg.mvStyleVar_WindowPadding, 10, 10, category=dpg.mvThemeCat_Core) - dpg.add_theme_style(dpg.mvStyleVar_FramePadding, 10, 10, category=dpg.mvThemeCat_Core) - - - with dpg.theme() as self.tab_theme: - with dpg.theme_component(dpg.mvAll): - # dpg.add_theme_color(dpg.mvThemeCol_ChildBg, (255, 0, 255), category=dpg.mvThemeCat_Core) - dpg.add_theme_style(dpg.mvStyleVar_ChildBorderSize, 3, category=dpg.mvThemeCat_Core) - - # with dpg.theme_component(dpg.mvInputInt): - # dpg.add_theme_color(dpg.mvThemeCol_FrameBg, (100, 150, 100), category=dpg.mvThemeCat_Core) - # dpg.add_theme_style(dpg.mvStyleVar_FrameRounding, 5, category=dpg.mvThemeCat_Core) - dpg.bind_theme(global_theme) - - dpg.show_style_editor() - # dpg.set_global_font_scale(2.0) - - dpg.create_viewport(title='Config File Editor', width=800, height=600) - dpg.setup_dearpygui() - dpg.show_viewport() - dpg.set_primary_window("main", True) - - self.tabs = {} - self.rows = {} - - def open_file_dialog(self): - dpg.show_item("file_dialog") - - def open_file(self, sender, app_data, user_data): - file_path = app_data['file_path_name'] - if file_path: - self.parse_config(file_path) - - def check_tabview(self, root): - for uuid in dpg.get_item_children(root, 1): - if dpg.get_item_type(uuid) == "mvAppItemType::mvTabBar": - return True, uuid - return False, None - - def parse_config(self, filename): - for widget in dpg.get_item_children("main", 1): - dpg.delete_item(widget) - - with open(filename, 'r', encoding='utf-8') as file: - lines = file.readlines() - - output = ''.join(lines) - lines = output.splitlines() - - for line in lines: - match = re.match(r" > (\w+) '([\w.]+)' = (.*)", line) - if match: - var_type, full_path, value = match.groups() - namespaces = full_path.split('.') - root = "main" - for level in range(len(namespaces) - 1): - path = '.'.join(namespaces[:level+1]) - - # tab_bar_exists, tab_bar_uuid = self.check_tabview(root) - - # if not tab_bar_exists: - # tab_bar_uuid = dpg.add_tab_bar(parent=root, tag=f"{path}_tb") - # dpg.add_separator(parent=root) - - print(path) - - if not dpg.does_item_exist(path): - print("here") - # dpg.add_tab(label=namespaces[level], parent=tab_bar_uuid, tag=f"{path}_tab") - dpg.add_child_window(parent=root, tag=path, height=300, border=True, menubar=True, autosize_x=True) - dpg.add_menu_bar(parent=path, tag=f"{path}_menu") - dpg.add_menu(label=namespaces[level], parent=f"{path}_menu") - dpg.bind_item_theme(path, self.tab_theme) - - root = path - - self.create_widget('.'.join(namespaces[:-1]), namespaces[-1], value, var_type) - - def create_widget(self, path, key, value, value_type): - parent = path - - with dpg.group(horizontal=True, parent=parent): - dpg.add_text(key) - if value_type == 'BOOLEAN': - dpg.add_checkbox(default_value=(value.lower() == "true")) - elif value.replace(".", "", 1).isdigit(): - dpg.add_input_float(default_value=float(value)) - elif "dir" in key.lower(): - dpg.add_input_text(default_value=value, tag=f"{path}.{key}") - dpg.add_button(label="...", callback=lambda s, a, u: self.file_dialog(f"{path}.{key}")) - else: - dpg.add_input_text(default_value=value) - - def file_dialog(self, var_tag): - with dpg.file_dialog(directory_selector=False, show=True, callback=lambda s, a, u: dpg.set_value(var_tag, a['file_path_name'])): - dpg.add_file_extension(".*", color=(255, 255, 255, 255)) - - def run(self): - dpg.start_dearpygui() - dpg.destroy_context() - -if __name__ == "__main__": - app = ConfigEditor() - app.run() diff --git a/icon.ico b/icon.ico new file mode 100644 index 0000000000000000000000000000000000000000..53f6e779b0a47924601020ed0792a7a66154128a GIT binary patch literal 172941 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 a(+}7g7>LIF3=9wC85kbegVq2rFaQ8lvxlny literal 0 HcmV?d00001 -- GitLab