Skip to content

Commit 32f4eb6

Browse files
committed
Merge branch 'main' of /nobackupnfs1/ddalle/cape/hub/src/cape
2 parents 67506a6 + 1c48047 commit 32f4eb6

File tree

10 files changed

+256
-28
lines changed

10 files changed

+256
-28
lines changed

cape/cfdx/cntl.py

Lines changed: 127 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3199,7 +3199,7 @@ def DeleteCase(self, i: int, **kw):
31993199
# Local function to perform deletion
32003200
def del_folder(frun):
32013201
# Delete the folder using :mod:`shutil`
3202-
shutil.rmtree(frun)
3202+
shutil.rmtree(frun, ignore_errors=True)
32033203
# Status update
32043204
print(" Deleted folder '%s'" % frun)
32053205
# Get the case name and go there.
@@ -4497,17 +4497,51 @@ def abspath(self, fname: str) -> str:
44974497
return os.path.join(self.RootDir, fname_sys)
44984498

44994499
# Copy files
4500-
@run_rootdir
45014500
def copy_files(self, i: int):
4501+
r"""Copy files from *Mesh* section
4502+
4503+
This applies to both *CopyFiles* and *CopyAsFiles* in the
4504+
*Mesh* section. The former will copy a given file into the run
4505+
folder for case *i* using the base name of the original (source)
4506+
file. Using
4507+
4508+
.. code-block:: javascript
4509+
4510+
"Mesh": {
4511+
"CopyAsFiles": {
4512+
"inputs/mesh-config02.ugrid": "mesh.ugrid"
4513+
}
4514+
}
4515+
4516+
will copy the file ``inputs/mesh-config02.ugrid`` into the run
4517+
folder but name it ``mesh.ugrid`` there.
4518+
4519+
:Call:
4520+
>>> cntl.copy_files(i)
4521+
:Inputs:
4522+
*cntl*: :class:`cape.cfdx.cntl.Cntl`
4523+
Overall CAPE control instance
4524+
*i*: :class:`int`
4525+
Case index
4526+
:Versions:
4527+
* 2025-09-19 ``@ddalle``: v1.0
4528+
"""
4529+
# Ensure case index is set
4530+
self.opts.setx_i(i)
4531+
# Create case folder
4532+
self.make_case_folder(i)
4533+
# Two categories
4534+
self._copy_as_files(i)
4535+
self._copy_files(i)
4536+
4537+
# Copy files w/o renaming
4538+
@run_rootdir
4539+
def _copy_files(self, i: int):
45024540
# Get list of files to copy
45034541
files = self.opts.get_CopyFiles()
45044542
# Check for any
45054543
if files is None or len(files) == 0:
45064544
return
4507-
# Ensure case index is set
4508-
self.opts.setx_i(i)
4509-
# Create case folder
4510-
self.make_case_folder(i)
45114545
# Name of case folder
45124546
frun = self.x.GetFullFolderNames(i)
45134547
# Loop through files
@@ -4525,18 +4559,76 @@ def copy_files(self, i: int):
45254559
# Copy file
45264560
shutil.copy(fabs, fdest)
45274561

4528-
# Link files
4562+
# Copy files with renaming
45294563
@run_rootdir
4530-
def link_files(self, i: int):
4531-
# Get list of files to copy
4532-
files = self.opts.get_LinkFiles()
4564+
def _copy_as_files(self, i: int):
4565+
# Get dict of files to copy
4566+
filedict = self.opts.get_CopyAsFiles()
45334567
# Check for any
4534-
if files is None or len(files) == 0:
4568+
if filedict is None or len(filedict) == 0:
45354569
return
4570+
# Name of case folder
4571+
frun = self.x.GetFullFolderNames(i)
4572+
# Loop through files
4573+
for src, trg in filedict.items():
4574+
# Absolutize source
4575+
fabs = self.abspath(src)
4576+
# Destination file
4577+
fdest = os.path.join(self.RootDir, frun, trg)
4578+
# Check for overwrite
4579+
if os.path.isfile(fdest):
4580+
print(f" Replacing file '{src}' -> '{fdest}'")
4581+
os.remove(fdest)
4582+
# Copy file
4583+
shutil.copy(fabs, fdest)
4584+
4585+
# Link files
4586+
def link_files(self, i: int):
4587+
r"""Link files from *Mesh* section
4588+
4589+
This applies to both *LinkFiles* and *LinkAsFiles* in the
4590+
*Mesh* section. The former will copy a given file into the run
4591+
folder for case *i* using the base name of the original (source)
4592+
file. Using
4593+
4594+
.. code-block:: javascript
4595+
4596+
"Mesh": {
4597+
"LinkAsFiles": {
4598+
"inputs/mesh-config02.ugrid": "mesh.ugrid"
4599+
}
4600+
}
4601+
4602+
will create a link (using the absolute path) from
4603+
``inputs/mesh-config02.ugrid`` to ``mesh.ugrid`` in the case run
4604+
folder.
4605+
4606+
:Call:
4607+
>>> cntl.link_files(i)
4608+
:Inputs:
4609+
*cntl*: :class:`cape.cfdx.cntl.Cntl`
4610+
Overall CAPE control instance
4611+
*i*: :class:`int`
4612+
Case index
4613+
:Versions:
4614+
* 2025-09-19 ``@ddalle``: v1.0
4615+
"""
45364616
# Ensure case index is set
45374617
self.opts.setx_i(i)
45384618
# Create case folder
45394619
self.make_case_folder(i)
4620+
# Two parts
4621+
self._link_as_files(i)
4622+
self._link_files(i)
4623+
4624+
# Link files w/o renaming
4625+
@run_rootdir
4626+
def _link_files(self, i: int):
4627+
# Get list of files to copy
4628+
files = self.opts.get_LinkFiles()
4629+
# Check for any
4630+
if files is None or len(files) == 0:
4631+
return
45404632
# Name of case folder
45414633
frun = self.x.GetFullFolderNames(i)
45424634
# Loop through files
@@ -4553,6 +4645,30 @@ def link_files(self, i: int):
45534645
# Copy file
45544646
os.symlink(fabs, fdest)
45554647

4648+
# Link files with renaming
4649+
@run_rootdir
4650+
def _link_as_files(self, i: int):
4651+
# Get dict of files to copy
4652+
filedict = self.opts.get_LinkAsFiles()
4653+
# Check for any
4654+
if filedict is None or len(filedict) == 0:
4655+
return
4656+
# Name of case folder
4657+
frun = self.x.GetFullFolderNames(i)
4658+
# Loop through files
4659+
for src, trg in filedict.items():
4660+
# Absolutize source
4661+
fabs = self.abspath(src)
4662+
# Destination file
4663+
fdest = os.path.join(self.RootDir, frun, trg)
4664+
# Check for overwrite
4665+
if os.path.isfile(fdest):
4666+
raise FileExistsError(
4667+
f" Cannot copy '{os.path.basename(src)}' -> "
4668+
f"'{src}'; file exists")
4669+
# Copy file
4670+
os.symlink(fabs, fdest)
4671+
45564672
# --- Archiving ---
45574673
# Function to archive results and remove files
45584674
def ArchiveCases(self, **kw):

cape/cfdx/options/meshopts.py

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,9 @@ class MeshOpts(OptionsDict):
2727

2828
# List of options
2929
_optlist = {
30+
"CopyAsFiles",
3031
"CopyFiles",
32+
"LinkAsFiles",
3133
"LinkFiles",
3234
"MeshFile",
3335
"TriFile",
@@ -39,22 +41,32 @@ class MeshOpts(OptionsDict):
3941
"CopyFiles": 1,
4042
"LinkFiles": 1,
4143
}
42-
44+
4345
# Defaults
4446
_rc = {
4547
"LinkMesh": False,
4648
}
4749

4850
# Types
4951
_opttypes = {
52+
"CopyAsFiles": dict,
53+
"CopyFiles": str,
54+
"LinkAsFiles": dict,
55+
"LinkFiles": str,
5056
"MeshFile": str,
5157
"TriFile": str,
5258
"LinkMesh": BOOL_TYPES,
5359
}
5460

5561
# Descriptions
5662
_rst_descriptions = {
63+
"CopyAsFiles": (
64+
"file(s) to copy and rename; source file is left-hand side and "
65+
"target file name is right-hand side"),
5766
"CopyFiles": "file(s) to copy to run folder w/o changing file name",
67+
"LinkAsFiles": (
68+
"file(s) to link and rename; source file is left-hand side and "
69+
"target file name is right-hand side"),
5870
"LinkFiles": "file(s) to link into run folder w/o changing file name",
5971
"LinkMesh": "option to link mesh file(s) instead of copying",
6072
"MeshFile": "original mesh file name(s)",

cape/cfdx/options/runmatrixopts.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,17 @@
2121
"ALPHA_P": "aoap",
2222
"ALPHA_T": "aoap",
2323
"ALPHA_TOTAL": "aoap",
24+
"ALTITUDE": "altitude",
2425
"AOA": "alpha",
2526
"AOAP": "aoap",
2627
"AOS": "beta",
2728
"Alpha": "alpha",
2829
"Alpha_p": "aoap",
2930
"Alpha_t": "aoap",
3031
"Alpha_total": "aoap",
32+
"Alt": "altitude",
33+
"AltH": "altitude",
34+
"Altitude": "altitude",
3135
"BETA": "beta",
3236
"Beta": "beta",
3337
"CONFIG": "config",
@@ -44,6 +48,8 @@
4448
"Gamma": "gamma",
4549
"GroupPrefix": "config",
4650
"GroupSuffix": "GroupLabel",
51+
"HEIGHT": "altitude",
52+
"Height": "altitude",
4753
"LABEL": "label",
4854
"Label": "label",
4955
"M": "mach",
@@ -129,9 +135,13 @@
129135
"alpha_p": "aoap",
130136
"alpha_t": "aoap",
131137
"alpha_total": "aoap",
138+
"alt": "altitude",
139+
"alth": "altitude",
132140
"aoa": "alpha",
133141
"aos": "alpha",
134142
"density": "rho",
143+
"h": "altitude",
144+
"height": "altitude",
135145
"m": "mach",
136146
"other": "value",
137147
"p0_inf": "p0",
@@ -262,6 +272,17 @@ class AlphaKeyDefnOpts(KeyDefnOpts):
262272
}
263273

264274

275+
# Definitions for angle of attack
276+
class AltitudeKeyDefnOpts(KeyDefnOpts):
277+
# Attributes
278+
__slots__ = ()
279+
280+
# Defaults
281+
_rc = {
282+
"Abbreviation": "h",
283+
}
284+
285+
265286
# Definitions for total angle of attack
266287
class AOAPKeyDefnOpts(KeyDefnOpts):
267288
# Attributes
@@ -835,6 +856,7 @@ class KeyDefnCollectionOpts(OptionsDict):
835856
"V": VelocityKeyDefnOpts,
836857
"XMLInput": XMLInputKeyDefnOpts,
837858
"alpha": AlphaKeyDefnOpts,
859+
"altitude": AltitudeKeyDefnOpts,
838860
"aoap": AOAPKeyDefnOpts,
839861
"beta": BetaKeyDefnOpts,
840862
"config": ConfigKeyDefnOpts,

cape/cfdx/report.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2620,6 +2620,7 @@ def SubfigConditions(self, sfig, I, q=True):
26202620
spvars = self.cntl.opts.get_SubfigOpt(sfig, "SpecialVars")
26212621
# Dictionary of recognized special keys
26222622
spdict = {
2623+
"Altitude": ["alt", "GetAltitude"],
26232624
"AngleOfAttack": ["a", "GetAlpha"],
26242625
"a": ["a", "GetAlpha"],
26252626
"aoa": ["a", "GetAlpha"],

0 commit comments

Comments
 (0)