Skip to content

Commit ab195fe

Browse files
committed
Merge branch 'main' into add_MARBL_WW_pelayout
2 parents 1e1dcb6 + 7f0bf6d commit ab195fe

8 files changed

Lines changed: 128 additions & 31 deletions

File tree

.github/workflows/general-ci-tests.yml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -133,11 +133,10 @@ jobs:
133133
- uses: actions/checkout@v4
134134

135135
# Run black check
136-
- uses: psf/black@stable
136+
- uses: psf/black@24.1.0
137137
with:
138138
options: "--check --verbose"
139139
src: "./cime_config"
140140

141-
142141

143142

.gitmodules

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
path = MOM6
33
url = https://github.com/NCAR/MOM6.git
44
fxDONOTUSEurl = https://github.com/NCAR/MOM6.git
5-
fxtag = dev/ncar_250128
5+
fxtag = dev/ncar_250411
66
fxrequired = AlwaysRequired
77

88
[submodule "stochastic_physics"]

cime_config/tools/lbe.py

Lines changed: 98 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -83,16 +83,19 @@ def gen_auto_mask_table(
8383
Output directory to write the mask table.
8484
"""
8585

86-
ds_topog = xr.open_dataset(topo_file_path)
87-
ny, nx = ds_topog.mask.shape
88-
8986
ibuf = 2
9087
jbuf = 2
9188
num_masked_blocks = 0
9289

93-
mask = np.zeros((ny + 2 * jbuf, nx + 2 * ibuf))
94-
95-
mask[jbuf : ny + jbuf, ibuf : nx + ibuf] = ds_topog.mask.data
90+
ds_topog = xr.open_dataset(topo_file_path)
91+
if "mask" in ds_topog:
92+
ny, nx = ds_topog.mask.shape
93+
mask = np.zeros((ny + 2 * jbuf, nx + 2 * ibuf))
94+
mask[jbuf : ny + jbuf, ibuf : nx + ibuf] = ds_topog.mask.data
95+
elif "wet" in ds_topog:
96+
ny, nx = ds_topog.wet.shape
97+
mask = np.zeros((ny + 2 * jbuf, nx + 2 * ibuf))
98+
mask[jbuf : ny + jbuf, ibuf : nx + ibuf] = ds_topog.wet.data
9699

97100
# fill in buffer cells
98101
if reentrant_x:
@@ -123,37 +126,98 @@ def gen_auto_mask_table(
123126
# ratio of ocean cells to total number of cells
124127
glob_ocn_frac = mask[jbuf : ny + jbuf, ibuf : nx + ibuf].sum() / (ny * nx)
125128

129+
pfrac = 0.01
130+
max_feasible_p = 0
131+
target_io_pes = args.tiopes
132+
found_feasible_layout = False
133+
126134
# Iteratively check for all possible division counts starting from the upper bound of npes/glob_ocn_frac,
127-
# which is over-optimistic for realistic domains, but may be satisfied with idealized domains.
128-
for p in range(int(np.ceil(npes / glob_ocn_frac)), npes, -1):
129-
130-
# compute the layout for the current division count, p
131-
idiv, jdiv = MOM_define_layout(nx, ny, p)
132-
133-
# don't bother checking this p if the aspect ratio is extreme
134-
r_p = (nx / idiv) / (ny / jdiv)
135-
if r_p * r_extreme < 1.0 or r_extreme < r_p:
136-
continue
137-
138-
# Get the number of masked_blocks for this particular division count
139-
mask_table = determine_land_blocks(mask, nx, ny, idiv, jdiv, ibuf, jbuf)
140-
141-
# If we can eliminate enough blocks to reach the target npes, adopt
142-
# this p (and the associated layout) and terminate the iteration.
143-
num_masked_blocks = len(mask_table)
144-
if p - num_masked_blocks <= npes:
145-
print("Found the optimum layout for auto-masking. Terminating iteration...")
146-
print(f"\t new ndivs: {p}, num_masked_blocks: {p-npes}")
135+
# which is over-optimistic for realistic domains, but may be satisfied with idealized domains. The first encountered
136+
# feasible division count is stored in max_feasible_p. If the target_io_pes is not achievable with this layout,
137+
# the iteration continues until max_feasible_p * (1 - pfrac) is reached or the target_io_pes is satisfiable.
138+
# If not, the target_io_pes is decremented and the iteration is re-done from max_feasible_p to max_feasible_p * (1 - pfrac).
139+
140+
for i in range(target_io_pes, 0, -1):
141+
142+
if found_feasible_layout:
147143
break
148144

145+
if max_feasible_p == 0: # first iteration
146+
p_up = int(np.ceil(npes / glob_ocn_frac))
147+
else:
148+
p_up = max_feasible_p
149+
150+
for p in range(p_up, npes, -1):
151+
152+
# compute the layout for the current division count, p
153+
idiv, jdiv = MOM_define_layout(nx, ny, p)
154+
155+
# don't bother checking this p if the aspect ratio is extreme
156+
ar = (nx / idiv) / (ny / jdiv)
157+
if ar * r_extreme < 1.0 or r_extreme < ar:
158+
continue
159+
160+
# Get the number of masked_blocks for this particular division count
161+
mask_table = determine_land_blocks(mask, nx, ny, idiv, jdiv, ibuf, jbuf)
162+
163+
# If we can eliminate enough blocks to reach the target npes, adopt
164+
# this p (and the associated layout) and terminate the iteration.
165+
num_masked_blocks = len(mask_table)
166+
167+
if p - num_masked_blocks <= npes:
168+
print(
169+
f"ndivs: {p}, masked_blocks: {num_masked_blocks}",
170+
" idiv: ",
171+
idiv,
172+
"jdiv",
173+
jdiv,
174+
)
175+
176+
if max_feasible_p == 0:
177+
print("^^^^^^^^^^^^^^^ first feasible layout ^^^^^^^^^^^^^^^")
178+
max_feasible_p = p
179+
if (idiv * jdiv) % i == 0:
180+
idiv_io, jdiv_io = determine_io_layout(idiv, jdiv, i)
181+
# if the io layout ratio is extreme, skip this layout
182+
ar = (idiv / idiv_io) / (jdiv / jdiv_io)
183+
if ar * r_extreme < 1.0 or r_extreme < ar:
184+
continue
185+
print(f"IO layout: {idiv_io} x {jdiv_io}")
186+
print(
187+
"Found the optimum layout for auto-masking. Terminating iteration."
188+
)
189+
found_feasible_layout = True
190+
break
191+
192+
if p <= max_feasible_p * (1 - pfrac):
193+
break
194+
149195
if num_masked_blocks == 0:
150196
raise RuntimeError(
151197
"Couldn't auto-eliminate any land blocks. Try to increase the number"
152198
)
153199

154200
# Call determine_land_blocks once again, this time to retrieve and write out the mask_table.
155201
mask_table = determine_land_blocks(mask, nx, ny, idiv, jdiv, ibuf, jbuf)
156-
write_auto_mask_file(mask_table, idiv, jdiv, npes, output_dir)
202+
203+
204+
def determine_io_layout(idiv, jdiv, nio):
205+
"""Determines the optimal I/O layout given the number of partitions in x and y direction and the number of I/O PEs."""
206+
min_ratio_diff = float("inf")
207+
best_idiv_io, best_jdiv_io = 1, nio
208+
209+
for f in range(1, nio + 1):
210+
if nio % f == 0:
211+
idiv_io, jdiv_io = f, nio // f
212+
213+
if idiv % idiv_io == 0 and jdiv % jdiv_io == 0:
214+
ratio_diff = abs((idiv_io / jdiv_io) - (idiv / jdiv))
215+
216+
if ratio_diff < min_ratio_diff:
217+
min_ratio_diff = ratio_diff
218+
best_idiv_io, best_jdiv_io = idiv_io, jdiv_io
219+
220+
return best_idiv_io, best_jdiv_io
157221

158222

159223
def write_auto_mask_file(
@@ -209,6 +273,13 @@ def write_auto_mask_file(
209273
required=True,
210274
help="Number of MOM6 PEs (NTASKS_OCN)",
211275
)
276+
parser.add_argument(
277+
"--tiopes",
278+
default=1,
279+
type=int,
280+
required=False,
281+
help="Number of target I/O PEs (NTASKS_IO) (default: 1)",
282+
)
212283
parser.add_argument(
213284
"-rx",
214285
default=False,

param_templates/MOM_input.yaml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3650,6 +3650,15 @@ Global:
36503650
datatype: list
36513651
value:
36523652
$OCN_GRID in ["tx2_3v2", "tx0.25v1"]: True
3653+
TARGET_IO_PES:
3654+
description: |
3655+
When AUTO_MASKTABLE is enabled, target number of IO PEs. If the given target
3656+
number of IO PEs is not achievable, the target number of IO PEs is set to the
3657+
nearest smaller number of PEs that is achievable.
3658+
datatype: integer
3659+
value:
3660+
$OCN_GRID == "tx2_3v2": = - ( - $NTASKS_OCN // 256)
3661+
$OCN_GRID == "tx0.25v1": = - ( - $NTASKS_OCN // 128)
36533662
GEOM_FILE:
36543663
description: |
36553664
default = ocean_geometry.nc

param_templates/input_nml.yaml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,10 @@ diag_manager_nml:
4747
else: 30
4848
max_axes:
4949
values: 90
50+
auto_merge_nc:
51+
values:
52+
$OCN_GRID in ["tx2_3v2", "tx0.25v1"]: .true.
53+
else: .false.
5054

5155
mpp_io_nml:
5256
cf_compliance:

param_templates/json/MOM_input.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2959,6 +2959,14 @@
29592959
"$OCN_GRID in [\"tx2_3v2\", \"tx0.25v1\"]": true
29602960
}
29612961
},
2962+
"TARGET_IO_PES": {
2963+
"description": "When AUTO_MASKTABLE is enabled, target number of IO PEs. If the given target\nnumber of IO PEs is not achievable, the target number of IO PEs is set to the\nnearest smaller number of PEs that is achievable.\n",
2964+
"datatype": "integer",
2965+
"value": {
2966+
"$OCN_GRID == \"tx2_3v2\"": "= - ( - $NTASKS_OCN // 256)",
2967+
"$OCN_GRID == \"tx0.25v1\"": "= - ( - $NTASKS_OCN // 128)"
2968+
}
2969+
},
29622970
"GEOM_FILE": {
29632971
"description": "default = ocean_geometry.nc\nThe file into which to write the ocean geometry.\n",
29642972
"datatype": "string",

param_templates/json/input_nml.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,12 @@
5555
},
5656
"max_axes": {
5757
"values": 90
58+
},
59+
"auto_merge_nc": {
60+
"values": {
61+
"$OCN_GRID in [\"tx2_3v2\", \"tx0.25v1\"]": ".true.",
62+
"else": ".false."
63+
}
5864
}
5965
},
6066
"mpp_io_nml": {

0 commit comments

Comments
 (0)