Skip to content

Commit ac3202d

Browse files
committed
Add new settings *Mesh* > *(Copy|Link)AsFiles
1 parent 7b84530 commit ac3202d

File tree

2 files changed

+139
-11
lines changed

2 files changed

+139
-11
lines changed

cape/cfdx/cntl.py

Lines changed: 126 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -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)",

0 commit comments

Comments
 (0)