cape.cfdx.cntl: Base module for CFD operations and processing

This module provides tools and templates for tools to interact with various CFD codes and their input files. The base class is cape.cfdx.cntl.Cntl, and the derivative classes include cape.pycart.cntl.Cntl. This module creates folders for cases, copies files, and can be used as an interface to perform most of the tasks that Cape can accomplish except for running individual cases.

The control module is set up as a Python interface for thec master JSON file, which contains the settings to be used for a given CFD project.

The derivative classes are used to read input files, set up cases, submit and/or run cases, and be an interface for the various Cape options as they are customized for the various CFD solvers. The individualized modules are below.

See also:
cape.cfdx.cntl.COL_HEADERS = {'case': 'Case Folder', 'cpu-abbrev': 'CPU Hours', 'cpu-hours': 'CPU Time', 'frun': 'Config/Run Directory', 'gpu-abbrev': 'GPU Hours', 'gpu-hours': 'GPU Hours', 'group': 'Group Folder', 'i': 'Case', 'job': 'Job ID', 'job-id': 'Job ID', 'phase': 'Phase', 'progress': 'Iterations', 'queue': 'Que', 'status': 'Status'}

dict[str] Column headers for py{x} -c

class cape.cfdx.cntl.CaseCache(prop: str)

Cache of one property for cases in a run matrix

Call:
>>> cache = CaseCache(prop)
Inputs:
prop: str

Name of property being cached

Outputs:
cache: CaseCache

Cache of property for each case, like a dict

Attributes:
check_case(i: int) bool

Save a value for a case

Call:
>>> q = cache.check_case(i)
Inputs:
cache: CaseCache

Cache of property for cases in a run matrix

i: int

Case index

Outputs:
q: bool

Whether or not case i is present

Versions:
  • 2025-03-01 @ddalle: v1.0

clear_case(i: int)

Clear cache for one case, if present

Call:
>>> cache.clear_case(i)
Inputs:
cache: CaseCache

Cache of property for cases in a run matrix

i: int

Case index

Versions:
  • 2025-03-01 @ddalle: v1.0

get_value(i: int) Any

Get a value for a case, if any

Call:
>>> val = cache.get_value(i)
Inputs:
cache: CaseCache

Cache of property for cases in a run matrix

i: int

Case index

Outputs:
val: object | None

Value, if present

Versions:
  • 2025-03-01 @ddalle: v1.0

prop

str Name of property being cached

save_value(i: int, val: Any)

Save a value for a case

Call:
>>> cache.save_value(i, val)
Inputs:
cache: CaseCache

Cache of property for cases in a run matrix

i: int

Case index

val: object | None

Value, if present

Versions:
  • 2025-03-01 @ddalle: v1.0

class cape.cfdx.cntl.CaseLoopArgs(*args, **kw)

Argument parser for Cntl.caseloop_verbose()

class cape.cfdx.cntl.Cntl(fname: str | None = None)

Class to handle options, setup, and execution of CFD codes

Call:
>>> cntl = cape.Cntl(fname="cape.json")
Inputs:
fname: str

Name of JSON settings file from which to read options

Outputs:
cntl: Cntl

Instance of CAPE control interface

Class attributes:
  • _case_cls

  • _fjson_default

  • _name

  • _opts_cls

  • _report_cls

  • _solver

  • _warnmode_default

  • _warnmode_envvar

  • _zombie_files

Attributes:
Versions:
  • 2015-09-20 @ddalle: Started

  • 2016-04-01 @ddalle: v1.0

ApplyCase(i: int, **kw)

Rewrite CAPE inputs for case i

Call:
>>> cntl.ApplyCase(i, n=1, j=None, imax=None)
Inputs:
cntl: cape.pyfun.cntl.Cntl

CAPE main control instance

i: int

Run index

qsub: True | {False}

Option to submit case after applying settings

nPhase: int

Phase to apply settings to

ApplyCases(**kw)

Reapply settings to one or more cases

Call:
>>> cntl.ApplyCases(cons=[], j=None, extend=1, **kw)
Inputs:
cntl: cape.cfdx.cntl.Cntl

Instance of overall control interface

extend: {True} | positive int

Extend phase j by extend nominal runs

j: {None} | nonnegative int

Phase number

cons: list[str]

List of constraints

I: list[int]

List of indices

Versions:
  • 2016-12-12 @ddalle: v1.0

ArchiveCase(i: int, test: bool = False)

Perform --archive archiving on one case

There are no restrictions on the status of the case for this action.

Call:
>>> cntl.CleanCase(i, test=False)
Inputs:
cntl: cape.cfdx.cntl.Cntl

Instance of control interface

i: int

Case index

test: True | {False}

Log file/folder actions but don’t actually delete/copy

Versions:
  • 2024-09-18 @ddalle: v1.0

ArchiveCases(**kw)

Archive completed cases and clean them up if specified

Call:
>>> cntl.ArchiveCases()
>>> cntl.ArchiveCases(cons=[], **kw)
Inputs:
cntl: cape.cfdx.cntl.Cntl

Instance of overall control interface

cons: list[str]

List of constraints

I: list[int]

List of indices

Versions:
  • 2016-12-09 @ddalle: v1.0

  • 2024-09-19 @ddalle: v2.0

CaseFunction(i: int)

Run one or more functions at “prepare-case” hook

This function is executed at the beginning of PrepareCase(i)().

This is meant to serve as a filter if a user wants to change the settings for some subset of the cases. Using this function can change any setting, which can be dependent on the case i.

This calls the function(s) in the global "CaseFunction" option from the JSON file. These functions must take cntl as an input and the case number i. The function(s) are usually from a module imported via the "Modules" option. See the following example:

"Modules": ["testmod"],
"CaseFunction": ["testmod.testfunc"]

This leads CAPE to call testmod.testfunc(cntl, i) at the beginning of PrepareCase() for each case i in the run matrix. The function is also called at the beginning of ApplyCase() if pyfun --apply or similar is issued.

Call:
>>> cntl.CaseFunction(i)
Inputs:
cntl: cape.cfdx.cntl.Cntl

Overall control interface

i: int

Case number

Versions:
  • 2017-04-05 @ddalle: v1.0

See also:
CaseGetCurrentPhase() int

Get the current phase number from the appropriate module

This function utilizes the cape.cfdx.case module, and so it must be copied to the definition for each solver’s control class.

Call:
>>> j = cntl.CaseGetCurrentPhase()
Inputs:
cntl: cape.cfdx.cntl.Cntl

Overall CAPE control instance

Outputs:
j: int | None

Phase number

Versions:
  • 2017-06-29 @ddalle: v1.0

  • 2023-07-06 @ddalle: v1.1; use CaseRunner

CheckBatch() int

Check to see if we are running inside a batch job

This looks for environment variables to see if this is running inside a batch job. Currently supports slurm and PBS.

Call:
>>> q = cntl.CheckBatch()
Inputs:
cntl: cape.cfdx.cntl.Cntl

Overall CAPE control instance

Outputs:
jobid: int

0 if no batch environment was detected

Versions:
  • 2023-12-13 @dvicker: v1.0

  • 2023-12-18 @ddalle: v1.1; debug

CheckCase(i: int, force: bool = False, v: bool = False) int | None

Check current status of case i

Because the file structure is different for each solver, some of this method may need customization. This customization, however, can be kept to the functions cape.cfdx.casecntl.GetCurrentIter() and cape.cfdx.cntl.Cntl.CheckNone().

Call:
>>> n = cntl.CheckCase(i, v=False)
Inputs:
cntl: cape.cfdx.cntl.Cntl

Overall CAPE control instance

i: int

Index of the case to check (0-based)

v: True | {False}

Verbose flag; prints messages if n is None

Outputs:
n: int | None

Number of completed iterations or None if not set up

Versions:
  • 2014-09-27 @ddalle: v1.0

  • 2015-09-27 @ddalle: v2.0; generic

  • 2015-10-14 @ddalle: v2.1; no case req

  • 2017-02-22 @ddalle: v2.2; add verbose flag

  • 2023-11-06 @ddalle: v2.3; call setx_i(i)

CheckError(i: int) bool

Check if a case has a failure

Call:
>>> q = cntl.CheckError(i)
Inputs:
cntl: cape.cfdx.cntl.Cntl

Overall CAPE control instance

i: int

Run index

Outputs:
q: bool

If True, case has FAIL file in it

Versions:
  • 2015-01-02 @ddalle: v1.0

CheckFM(**kw)

Display missing force & moment components

Call:
>>> cntl.CheckFM(**kw)
Inputs:
cntl: cape.cfdx.cntl.Cntl

Overall CAPE control instance

fm, aero: {None} | str

Wildcard to subset list of FM components

I: list[int]

List of indices

cons: list[str]

List of constraints like 'Mach<=0.5'

Versions:
  • 2018-10-19 @ddalle: v1.0

CheckLL(**kw)

Display missing line load components

Call:
>>> cntl.CheckLL(**kw)
Inputs:
cntl: cape.cfdx.cntl.Cntl

Overall CAPE control instance

fm, aero: {None} | str

Wildcard to subset list of FM components

I: list[int]

List of indices

cons: list[str]

List of constraints like 'Mach<=0.5'

Versions:
  • 2018-10-19 @ddalle: v1.0

CheckNone(v: bool = False) bool

Check if the current directory has the needed files to run

This function needs to be customized for each CFD solver so that it checks for the appropriate files.

Call:
>>> q = cntl.CheckNone(v=False)
Inputs:
cntl: cape.cfdx.cntl.Cntl

Cape control interface

v: True | {False}

Verbose flag; prints message if q is True

Outputs:
q: `True | False`

Whether or not case is missing files

Versions:
  • 2015-09-27 @ddalle: v1.0

  • 2017-02-22 @ddalle: v1.1, verbosity option

CheckPhase(i: int, v: bool = False) int | None

Check current phase number of run i

Call:
>>> n = cntl.CheckPhase(i, v=False)
Inputs:
cntl: cape.cfdx.cntl.Cntl

Overall CAPE control instance

i: int

Index of the case to check (0-based)

v: True | {False}

Verbose flag; prints messages if n is None

Outputs:
j: int | None

Phase number

Versions:
  • 2017-06-29 @ddalle: v1.0

CheckRunning(i)

Check if a case is currently running

Call:
>>> q = cntl.CheckRunning(i)
Inputs:
cntl: cape.cfdx.cntl.Cntl

Overall CAPE control instance

i: int

Run index

Outputs:
q: bool

If True, case has RUNNING file in it

Versions:
  • 2014-10-03 @ddalle: v1.0

CheckTriqFM(**kw)

Display missing TriqFM components

Call:
>>> cntl.CheckTriqFM(**kw)
Inputs:
cntl: cape.cfdx.cntl.Cntl

Overall CAPE control instance

fm, aero: {None} | str

Wildcard to subset list of FM components

I: list[int]

List of indices

cons: list[str]

List of constraints like 'Mach<=0.5'

Versions:
  • 2018-10-19 @ddalle: v1.0

CheckTriqPoint(**kw)

Display missing TriqPoint components

Call:
>>> cntl.CheckTriqPoint(**kw)
Inputs:
cntl: cape.cfdx.cntl.Cntl

Overall CAPE control instance

fm, aero: {None} | str

Wildcard to subset list of FM components

I: list[int]

List of indices

cons: list[str]

List of constraints like 'Mach<=0.5'

Versions:
  • 2018-10-19 @ddalle: v1.0

CheckUsedPhase(i: int, v: bool = False)

Check maximum phase number run at least once

Call:
>>> j, n = cntl.CheckUsedPhase(i, v=False)
Inputs:
cntl: cape.cfdx.cntl.Cntl

Overall CAPE control instance

i: int

Index of the case to check (0-based)

v: True | {False}

Verbose flag; prints messages if n is None

Outputs:
j: int | None

Phase number

n: int | None

Maximum phase number

Versions:
  • 2017-06-29 @ddalle: v1.0

  • 2017-07-11 @ddalle: v1.1; verbosity option

  • 2025-03-02 @ddalle: v2.0; use CaseRunner

CheckZombie(i)

Check a case for ZOMBIE status

A running case is declared a zombie if none of the listed files (by default *.out) have been modified in the last 30 minutes. However, a case cannot be a zombie unless it contains a RUNNING file and returns True from CheckRunning().

Call:
>>> q = cntl.CheckZombie(i)
Inputs:
cntl: cape.cfdx.cntl.Cntl

Overall CAPE control instance

i: int

Run index

Outputs:
q: bool

True if no listed files have been modified recently

Versions:
  • 2017-04-04 @ddalle: v1.0

  • 2021-01-25 @ddalle: v1.1; use cls._zombie_files

CleanCase(i: int, test: bool = False)

Perform --clean archiving on one case

There are no restrictions on the status of the case for this action.

Call:
>>> cntl.CleanCase(i, test=False)
Inputs:
cntl: cape.cfdx.cntl.Cntl

Instance of control interface

i: int

Case index

test: True | {False}

Log file/folder actions but don’t actually delete/copy

CleanCases(**kw)

Clean a list of cases using Progress archive options only

Call:
>>> cntl.CleanCases(**kw)
Inputs:
cntl: cape.cfdx.cntl.Cntl

Instance of control interface

Versions:
  • 2017-03-13 @ddalle: v1.0

  • 2024-09-18 @ddalle: v2.0

CountQueuedCases(I: list | None = None, u: str | None = None, **kw) int

Count cases that have currently active PBS/Slurm jobs

Call:
>>> n = cntl.CountQueuedCases(I=None, u=None, **kw)
Inputs:
cntl: cape.cfdx.cntl.Cntl

Overall CAPE control instance

I: {None} | list[int]

List of indices

u: str

User name (defaults to process username)

kw: dict

Other kwargs used to subset the run matrix

Outputs:
n: int

Number of running or queued jobs (not counting the job from which function is called, if applicable)

Versions:
  • 2024-01-12 @ddalle: v1.0

  • 2024-01-17 @ddalle: v1.1; check for this_job

  • 2025-05-01 @ddalle: v1.2; remove jobs kwarg

CountRunningCases(I: list, jobs: dict | None = None, u: str | None = None) int

Count number of running cases via the batch system

Also print a status of the running jobs.

Call:
>>> n = cntl.CountRunningCases(I, jobs=None, u=None)
Inputs:
cntl: cape.cfdx.cntl.Cntl

Overall CAPE control instance

I: list[int]

List of indices

jobs: dict

Information on each job by ID number

u: str

User name (defaults to process username)

Outputs:
n: int

Number of running or queued jobs

Versions:
  • 2023-12-08 @dvicker: v1.0

DataBook

cape.cfdx.databook.DataBook Interface to post-processed data

DeleteCase(i: int, **kw)

Delete a case

This function deletes a case’s PBS job and removes the entire directory. By default, the method prompts for user’s confirmation before deleting; set prompt to False to delete without prompt.

Call:
>>> n = cntl.DeleteCase(i)
Inputs:
cntl: cape.cfdx.cntl.Cntl

Cape control interface

i: int

Index of the case to check (0-based)

prompt: {True} | False

Whether or not to prompt user before deleting case

Outputs:
n: 0 | 1

Number of folders deleted

Versions:
  • 2018-11-20 @ddalle: v1.0

Dezombie(**kw)

Clean up any ZOMBIE cases

Call:
>>> cntl.Dezombie(**kw)
Inputs:
cntl: cape.cfdx.cntl.Cntl

Instance of overall control interface

extend: {True} | positive int

Extend phase j by extend nominal runs

j: {None} | int >= 0

Phase number

imax: {None} | int

Do not increase iteration number beyond imax

cons: list[str]

List of constraints

I: list[int]

List of indices

Versions:
  • 2021-10-14 @ddalle: v1.0

DisplayStatus(**kw)

Display current status for all cases

This prints case names, current iteration numbers, and so on. This is the function that is called when the user issues a system command like cape -c.

Call:
>>> cntl.DisplayStatus(j=False)
Inputs:
cntl: cape.cfdx.cntl.Cntl

Overall CAPE control instance

j: bool

Whether or not to display job ID numbers

cons: list[str]

List of constraints like 'Mach<=0.5'

Versions:
  • 2014-10-04 @ddalle: v1.0

  • 2014-12-09 @ddalle: v2.0; --cons

  • 2025-06-20 @ddalle: v3.0; use caseloop_verbose()

ExecScript(**kw) int

Execute a script in a given case folder

This function is the interface to command-line calls using the -e flag, such as pycart -e 'ls -lh'.

Call:
>>> ierr = cntl.ExecScript(i, cmd)
Inputs:
cntl: cape.cfdx.cntl.Cntl

Overall CAPE control instance

i: int

Case index (0-based)

Outputs:
ierr: None | int

Exit status from the command

Versions:
  • 2016-08-26 @ddalle: v1.0

  • 2024-12-09 @jfdiaz3:v1.1

ExtendCase(i: int, n: int = 1, j: int | None = None, imax: int | None = None)

Add iterations to case i by repeating the last phase

Call:
>>> cntl.ExtendCase(i, n=1, j=None, imax=None)
Inputs:
cntl: cape.pyfun.cntl.Cntl

CAPE main control instance

i: int

Case index

n: {1} | positive int

Add n times steps to the total iteration count

j: {None} | int

Optional phase to extend

imax: {None} | nonnegative int

Use imax as the maximum iteration count

ExtendCases(**kw)

Extend one or more case by a number of iterations

By default, this applies to the final phase, but the phase number j can also be specified as input. The number of additional iterations is generally the nominal number of iterations that phase j would normally run.

Call:
>>> cntl.ExtendCases(cons=[], extend=1, **kw)
Inputs:
cntl: cape.cfdx.cntl.Cntl

Instance of overall control interface

extend: {True} | positive int

Extend phase j by extend nominal runs

imax: {None} | int

Do not increase iteration number beyond imax

j, phase: {None} | int

Optional index of phase to extend

cons: list[str]

List of constraints

I: list[int]

List of indices

Versions:
  • 2016-12-12 @ddalle: v1.0

FilterUser(i: int, **kw) bool

Determine if case i is assigned to current user

Call:
>>> q = cntl.FilterUser(i, **kw)
Inputs:
cntl: cape.cfdx.cntl.Cntl

Overall CAPE control instance

i: int

Index of the case to check (0-based)

u, user: str

User name (default: executing process’s username) for comparing to run matrix

Outputs:
q: bool

Whether user is owner of case i

Versions:

2017-07-10 @ddalle: v1.0

GetCPUTime(i: int)

Read a CAPE-style core-hour file from a case

This function needs to be customized for each solver because it needs to know the name of the file in which timing data is saved. It defaults to cape_time.dat. Modifying this command is a one-line fix with a call to cape.cfdx.cntl.Cntl.GetCPUTimeFromFile() with the correct file name.

Call:
>>> CPUt = cntl.GetCPUTime(i)
Inputs:
cntl: cape.cfdx.cntl.Cntl

CAPE control interface

i: int

Case index

Outputs:
CPUt: float | None

Total core hours used in this job

Versions:
  • 2015-12-22 @ddalle: v1.0

  • 2016-08-30 @ddalle: v1.1; check for RUNNING

  • 2016-08-31 @ddalle: v1.2; use GetCPUTimeBoth

  • 2023-07-09 @ddalle: v2.0; use CaseRunner

GetCaseIndex(frun: str) int | None

Get index of a case in the current run matrix

Call:
>>> i = cntl.GetCaseIndex(frun)
Inputs:
cntl: cape.cfdx.cntl.Cntl

Cape control interface

frun: str

Name of case, must match exactly

Outputs:
i: int | None

Index of case with name frun in run matrix, if present

Versions:
  • 2024-08-15 @ddalle: v1.0

  • 2024-10-16 @ddalle: v1.1; move to RunMatrix

GetCaseMeshFolder(i: int) str

Get relative path to folder where mesh should be copied

Call:
>>> fdir = cntl.GetCaseMeshFolder(i)
Inputs:
cntl: Cntl

CAPE run matrix control instance

i: {0} | int

Case index

Outputs:
fdir: str

Folder to copy file, relative to cntl.RootDir

Versions:
  • 2024-11-06 @ddalle: v1.0

GetCurrentIter(i: int, force: bool = False) int

Get the current iteration number (using case)

This function utilizes the cape.cfdx.case module, and so it must be copied to the definition for each solver’s control class.

Call:
>>> n = cntl.GetCurrentIter(i, force=False)
Inputs:
cntl: cape.cfdx.cntl.Cntl

Overall CAPE control instance

i: int

Index of the case to check (0-based)

force: True | {False}

Option to ignore cache

Outputs:
n: int

Number of completed iterations

Versions:
  • 2015-10-14 @ddalle: v1.0

  • 2023-07-07 @ddalle: v2.0; use CaseRunner

  • 2025-03-01 @ddalle: v3.0; add caching

GetInputMeshFileNames() list

Return the list of mesh files from file

Call:
>>> fnames = cntl.GetInputMeshFileNames()
Inputs:
cntl: Cntl

Run matrix control instance for unstructured-mesh solver

Outputs:
fnames: list[str]

List of file names read from root directory

Versions:
  • 2015-10-19 @ddalle: v1.0 (pyfun)

  • 2024-10-22 @ddalle: v1.0

GetLastIter(i: int) int

Get minimum required iteration for a given case

Call:
>>> nIter = cntl.GetLastIter(i)
Inputs:
cntl: cape.cfdx.cntl.Cntl

Cape control interface

i: int

Run index

Outputs:
nIter: int

Number of iterations required for case i

Versions:
  • 2014-10-03 @ddalle: v1.0

GetPBSJobID(i: int) str | None

Get PBS job number if one exists

Call:
>>> jobID = cntl.GetPBSJobID(i)
Inputs:
cntl: cape.cfdx.cntl.Cntl

Overall CAPE control instance

i: int

Run index

Outputs:
jobID: None | str

Most recent PBS/Slurm job name, if able

Versions:
  • 2014-10-06 @ddalle: v1.0

  • 2024-01-12 @ddalle: v1.1; remove CheckCase() for speed

GetPBSName(i: int) str

Get PBS name for a given case

Call:
>>> lbl = cntl.GetPBSName(i, pre=None)
Inputs:
cntl: cape.cfdx.cntl.Cntl

Overall CAPE control instance

i: int

Run index

pre: {None} | str

Prefix for PBS job name

Outputs:
lbl: str

Short name for the PBS job, visile via qstat

Versions:
  • 2014-09-30 @ddalle: v1.0

  • 2016-12-20 @ddalle: v1.1, moved to x

GetPhaseBreaks() list

Get expected iteration numbers at phase breaks

This fills in 0 entries in RunControl PhaseIters and returns the filled-out list.

Call:
>>> PI = cntl.GetPhaseBreaks()
Inputs:
cntl: cape.cfdx.cntl.Cntl

Cape control interface

Outputs:
PI: list[int]

Min iteration counts for each phase

Versions:
  • 2017-04-12 @ddalle: v1.0

GetProcessedMeshFileNames() list

Return the list of mesh files that are written

Call:
>>> fname = cntl.GetProcessedMeshFileNames()
Inputs:
cntl: Cntl

Run matrix control instance for unstructured-mesh solver

Outputs:
fname: list[str]

List of file names written to case folders

Versions:
  • 2015-10-19 @ddalle: v1.0

GetProjectRootName(j: int = 0) str

Get the project root name

The JSON file overrides the value from the namelist file if appropriate

Call:
>>> name = cntl.GetProjectName(j=0)
Inputs:
cntl: Cntl

CAPE run matrix control instance

j: {0} | int

Phase number

Outputs:
name: str

Project root name

Versions:
  • 2015-10-18 @ddalle: v1.0 (pyfun)

  • 2023-06-15 @ddalle: v1.1; cleaner logic

  • 2024-10-22 @ddalle: v2.0; moved to cfdx

  • 2025-07-15 @ddalle: v2.1; move into CntlBase

GetSurfCT_ExitArea(key: str, i: int, comp: str | None = None) float

Get exit area for a CT trajectory key

This can use either the area ratio (if available) or calculate from the exit Mach number. The input area is determined from the component ID. If using the exit Mach number M2, the input Mach number M1 is also needed. The relationship between area ratio and exit Mach is given below.

\[\begin{split}\\frac{A_2}{A_1} = \\frac{M_1}{M_2}\\left( \\frac{1+\\frac{\\gamma-1}{2}M_2^2}{ 1+\\frac{\\gamma-1}{2}M_1^2} \\right) ^ {\\frac{1}{2}\\frac{\\gamma+1}{\\gamma-1}}\end{split}\]
Call:
>>> A2 = cntl.GetSurfCT_ExitArea(key, i)
Inputs:
cntl: cape.cfdx.cntl.Cntl

Overall CAPE control instance

key: str

Name of trajectory key to check

i: int

Case number

comp: {None} | str

Name of component for which to get BCs

Outputs:
A2: list (float)

Exit area for each component referenced by this key

Versions:
  • 2016-04-13 @ddalle: v1.0

GetSurfCT_ExitMach(key: str, i: int, comp: str | None = None) float

Get exit Mach number for a CT trajectory key

This can use either the "ExitMach" parameter (if available) or calculate from the area ratio. If using the area ratio, the input Mach number is also needed. The relationship between area ratio and exit Mach is given below.

\[\frac{A_2}{A_1} = \frac{M_1}{M_2}\left( \frac{1+\frac{\gamma-1}{2}M_2^2}{ 1+\frac{\gamma-1}{2}M_1^2} \right) ^ {\frac{1}{2}\frac{\gamma+1}{\gamma-1}}\]
Call:
>>> M2 = cntl.GetSurfCT_ExitMach(key, i)
Inputs:
cntl: cape.cfdx.cntl.Cntl

Overall CAPE control instance

key: str

Name of trajectory key to check

i: int

Case number

comp: {None} | str

Name of component for which to get BCs

Outputs:
M2: float

Exit Mach number

Versions:
  • 2016-04-13 @ddalle: v1.0

GetSurfCT_RefArea(key: str, i: int) float

Get reference area for surface CT trajectory key

This references the "RefArea" parameter of the definition for the run matrix variable key. The user should set this parameter to 1.0 if thrust inputs are given as dimensional values.

If this is None, it returns the global reference area; if it is a string the reference area comes from the reference area for that component using cntl.opts.get_RefArea(comp).

Call:
>>> Aref = cntl.GetSurfCT_RefArea(key, i)
Inputs:
cntl: cape.cfdx.cntl.Cntl

Overall CAPE control instance

key: str

Name of trajectory key to check

i: int

Case number

Outputs:
Aref: float

Reference area for normalizing thrust coefficients

Versions:
  • 2016-04-13 @ddalle: v1.0

ImportModules()

Import user-defined modules if specified in the options

All modules from the "Modules" global option of the JSON file (cntl.opts["Modules"]) will be imported and saved as attributes of cntl. For example, if the user wants to use a module called dac3, it will be imported as cntl.dac3. A noncomprehensive list of disallowed module names is below.

DataBook, RootDir, jobs, opts, tri, x

The name of any method of this class is also disallowed. However, if the user wishes to import a module whose name is disallowed, he/she can use a dictionary to specify a different name to import the module as. For example, the user may import a module called tri as mytri using the following JSON syntax.

"Modules": [{"tri": "mytri"}]
Call:
>>> cntl.ImportModules()
Inputs:
cntl: cape.cfdx.cntl.Cntl

Instance of Cape control interface

Versions:
  • 2014-10-08 @ddalle: v1.0 (pycart)

  • 2015-09-20 @ddalle: v1.0

  • 2022-04-12 @ddalle: v2.0; use self.modules

InitFunction()

Run one or more functions a “initialization” hook

This calls the function(s) in the global "InitFunction" option from the JSON file. These functions must take cntl as an input, and they are usually from a module imported via the "Modules" option. See the following example:

"Modules": ["testmod"],
"InitFunction": ["testmod.testfunc"]

This leads CAPE to call testmod.testfunc(cntl).

Call:
>>> cntl.InitFunction()
Inputs:
cntl: cape.cfdx.cntl.Cntl

Overall control interface

Versions:
  • 2017-04-04 @ddalle: v1.0

  • 2022-04-12 @ddalle: v2.0; use _exec_funclist()

MarkERROR(**kw)

Mark one or more cases as ERROR and rewrite matrix

Call:
>>> cntl.MarkERROR(**kw)
Inputs:
cntl: cape.cfdx.cntl.Cntl

Overall CAPE control instance

I: list[int]

List of indices

cons: list[str]

List of constraints like 'Mach<=0.5'

flag: {"E"} | "e" | "ERROR" | "$E"

Marker to use to denote status

Versions:
  • 2019-06-14 @ddalle: v1.0

MarkPASS(**kw)

Mark one or more cases as PASS and rewrite matrix

Call:
>>> cntl.MarkPASS(**kw)
Inputs:
cntl: cape.cfdx.cntl.Cntl

Overall CAPE control instance

I: list[int]

List of indices

cons: list[str]

List of constraints like 'Mach<=0.5'

flag: {"p"} | "P" | "PASS" | "$p"

Marker to use to denote status

Versions:
  • 2019-06-14 @ddalle: v1.0

PrepareCase(i: int)

Prepare case for running if necessary

This function creates the folder, copies mesh files, and saves settings and input files. All of these tasks are completed only if they have not already been completed, and it needs to be customized for each CFD solver.

Call:
>>> cntl.PrepareCase(i)
Inputs:
cntl: cape.cfdx.cntl.Cntl

Overall CAPE control instance

i: int

Index of case to analyze

Versions:
  • 2014-09-30 @ddalle: v1.0

  • 2015-09-27 @ddalle: v2.0, convert to template

PrepareConfig(i: int)

Apply rotations, translations, etc. to Config.xml

Call:
>>> cntl.PrepareConfig(i)
Inputs:
cntl: cape.cfdx.cntl.Cntl

Overall CAPE control instance

i: int

Case index

Versions:
  • 2016-08-23 @ddalle: v1.0

PrepareConfigFunction(key: str, i: int)

Apply special configuration modification function for a case

Call:
>>> cntl.PrepareConfigFunction(key, i)
Inputs:
cntl: cape.cfdx.cntl.Cntl

Overall CAPE control instance

key: str

Name of key

i: int

Index of the case to check (0-based)

Versions:
  • 2016-08-23 @ddalle: v1.0

  • 2022-04-13 @ddalle: v2.0; exec_modfunction()

PrepareConfigRotation(key: str, i: int)

Apply a rotation to a component or components

Call:
>>> cntl.PrepareConfigRotation(key, i)
Inputs:
cntl: cape.cfdx.cntl.Cntl

Overall CAPE control instance

key: str

Name of the trajectory key

i: int

Index of the case to check (0-based)

Versions:
  • 2016-08-23 @ddalle: v1.0

PrepareConfigTranslation(key: str, i: int)

Apply a translation to a component or components

Call:
>>> cntl.PrepareConfigTranslation(key, i)
Inputs:
cntl: cape.cfdx.cntl.Cntl

Overall CAPE control instance

key: str

Name of variable from which to get value

i: int

Index of the case to check (0-based)

Versions:
  • 2016-08-23 @ddalle: v1.0

PrepareMesh(i: int)

Prepare the mesh for case i if necessary

Call:
>>> cntl.PrepareMesh(i)
Inputs:
cntl: cape.pyfun.cntl.Cntl

Instance of control class

i: int

Case index

Versions:
  • 2015-10-19 @ddalle: v1.0 (pyfun)

  • 2024-11-04 @ddalle: v1.3 (pyfun)

  • 2024-11-07 @ddalle: v1.0

PrepareMeshFiles(i: int) int

Copy main unstructured mesh files to case folder

Call:
>>> n = cntl.PrepareMeshFiles(i)
Inputs:
cntl: Cntl

CAPE run matrix control instance

i: int

Case index

Outputs:
n: int

Number of files copied

Versions:
  • 2024-11-05 @ddalle: v1.0

  • 2025-04-02 @ddalle: v1.1; add LinkMesh option

PrepareMeshTri(i: int)

Prepare surface triangulation for AFLR3, if appropriate

Call:
>>> cntl.PrepareMeshTri(i)
Inputs:
cntl: Cntl

CAPE run matrix control instance

i: int

Case index

Versions:
  • 2024-11-01 @ddalle: v1.0 (from pyfun’s PrepareMesh())

PrepareMeshUnstructured(i: int)

Prepare the mesh for case i if necessary

Call:
>>> cntl.PrepareMeshUnstructured(i)
Inputs:
cntl: cape.pyfun.cntl.Cntl

Instance of control class

i: int

Case index

Versions:
  • 2015-10-19 @ddalle: v1.0 (pyfun)

  • 2024-11-04 @ddalle: v1.3 (pyfun)

  • 2024-11-07 @ddalle: v1.0

  • 2025-07-15 @ddalle: v1.1; name change

PrepareMeshWarmStart(i: int) bool

Prepare WarmStart files for case, if appropriate

Call:
>>> warmstart = cntl.PrepareMeshWarmStart(i)
Inputs:
cntl: Cntl

Name of main CAPE input (JSON) file

i: int

Case index

Outputs:
warmstart: bool

Whether or not case was warm-started

Versions:
  • 2024-11-04 @ddalle: v1.0

PreparePoints(i: int)

Calculate the value of each named "Point" for case i

Call:
>>> x = cntl.PreparePoints(i)
Inputs:
cntl: cape.cfdx.cntl.Cntl

Overall CAPE control instance

i: int

Case index

Versions:
  • 2022-03-07 @ddalle: v1.0

PreparePointsRotation(key: str, i: int)

Apply a rotation to named config points for one col

Call:
>>> cntl.PreparePointsRotation(key, i)
Inputs:
cntl: cape.cfdx.cntl.Cntl

Overall CAPE control instance

key: str

Name of the trajectory key

i: int

Index of the case to check (0-based)

Versions:
  • 2022-03-07 @ddalle: v1.0

PreparePointsTranslation(key: str, i: int)

Apply a translation to named config points for one col

Call:
>>> cntl.PreparePointsTranslation(key, i)
Inputs:
cntl: cape.cfdx.cntl.Cntl

Overall CAPE control instance

key: str

Name of the trajectory key

i: int

Case index

Versions:
  • 2022-03-07 @ddalle: v1.0

PrepareTri(i: int)

Rotate/translate/etc. triangulation for given case

Call:
>>> cntl.PrepareTri(i)
Inputs:
cntl: cape.cfdx.cntl.Cntl

Overall CAPE control instance

i: int

Index of the case to check (0-based)

Versions:
  • 2014-12-01 @ddalle: v1.0

  • 2016-04-05 @ddalle: v1.1, pycart -> cape

PrepareTriFunction(key: str, i: int)

Apply special surf modification function for a case

Call:
>>> cntl.PrepareTriFunction(key, i)
Inputs:
cntl: cape.cfdx.cntl.Cntl

Overall CAPE control instance

key: str

Name of key

i: int

Index of the case to check (0-based)

Versions:
  • 2015-09-11 @ddalle: v1.0

  • 2016-04-05 @ddalle: v1.1, pycart -> cape

  • 2022-04-13 @ddalle: v2.0; exec_modfunction()

PrepareTriRotation(key: str, i: int)

Apply a rotation to a component or components

Call:
>>> cntl.PrepareTriRotation(key, i)
Inputs:
cntl: cape.cfdx.cntl.Cntl

Overall CAPE control instance

key: str

Run matrix for rotation defn’

i: int

Index of the case to check (0-based)

Versions:
  • 2015-09-11 @ddalle: v1.0

  • 2016-04-05 @ddalle: v1.1, pycart -> cape

PrepareTriTranslation(key: str, i: int)

Apply a translation to a component or components

Call:
>>> cntl.PrepareTriTranslation(key, i)
Inputs:
cntl: cape.cfdx.cntl.Cntl

Overall CAPE control instance

key: str

Run matrix key for translation def’n

i: int

Index of the case to check (0-based)

Versions:
  • 2015-09-11 @ddalle: v1.0

  • 2016-04-05 @ddalle: v1.1, pycart -> cape

ReadCaseRunner(i: int) CaseRunner

Read CaseRunner into slot

Call:
>>> runner = cntl.ReadCaseRunner(i)
Inputs:
cntl: cape.cfdx.cntl.Cntl

Overall CAPE control instance

i: int

Index of the case to check (0-based)

Outputs:
runner: CaseRunner

Controller to run one case of solver

ReadConfig(f: bool = False) ConfigXML | ConfigJSON

Read Config.xml or other surf configuration format

Call:
>>> cntl.ReadConfig(f=False)
Inputs:
cntl: cape.cfdx.cntl.Cntl

Overall CAPE control instance

f: True | {False}

Option to reread existing cntl.config

Versions:
  • 2016-06-10 @ddalle: v1.0

  • 2016-10-21 @ddalle: v2.0, added Config.json

  • 2020-09-01 @ddalle: v2.1, add f kwarg

ReadFolderCaseRunner(fdir: str) CaseRunner

Read a CaseRunner from a folder by name

Call:
>>> runner = cntl.ReadFolderCaseRunner(fdir)
Inputs:
cntl: cape.cfdx.cntl.Cntl

Overall CAPE control instance

fdir: str

Folder of case to read from

Outputs:
runner: CaseRunner

Controller to run one case of solver

ReadReport(rep: str) Report

Read a report interface

Call:
>>> rep = cntl.ReadReport(rep)
Inputs:
cntl: cape.cfdx.cntl.Cntl

CAPE main control instance

rep: str

Name of report

Outputs:
rep: cape.cfdx.report.Report

Report interface

Versions:
  • 2018-10-19 @ddalle: Version 1.0

ReadTri()

Read initial triangulation file(s)

Call:
>>> cntl.ReadTri()
Inputs:
cntl: cape.cfdx.cntl.Cntl

Overall CAPE control instance

Versions:
  • 2014-08-30 @ddalle: v1.0

RevertOptions()

Revert to cntl.opts0 as working options

Call:
>>> cntl.ResetOptions()
Inputs:
cntl: Cntl

CAPE solver control interface

Versions:
  • 2021-07-31 @ddalle: v1.0

RootDir

str Root folder for this run matrix

SaveOptions()

Copy cntl.opts and store it as cntl.opts0

Call:
>>> cntl.SaveOptions()
Inputs:
cntl: Cntl

CAPE solver control interface

Versions:
  • 2021-07-31 @ddalle: v1.0

SkeletonCase(i: int, test: bool = False)

Perform --skeleton archiving on one case

There are no restrictions on the status of the case for this action.

Call:
>>> cntl.SkeletonCase(i, test=False)
Inputs:
cntl: cape.cfdx.cntl.Cntl

Instance of control interface

i: int

Case index

test: True | {False}

Log file/folder actions but don’t actually delete/copy

Versions:
  • 2024-09-18 @ddalle: v1.0

SkeletonCases(**kw)

Archive completed cases and delete all but a few files

Call:
>>> cntl.SkeletonCases()
>>> cntl.SkeletonCases(cons=[], **kw)
Inputs:
cntl: cape.cfdx.cntl.Cntl

Instance of overall control interface

cons: list[str]

List of constraints

I: list[int]

List of indices

Versions:
  • 2016-12-14 @ddalle: v1.0

  • 2024-09-19 @ddalle: v2.0

StartCase(i: int)

Start a case by either submitting it or running it

This function checks whether or not a case is submittable. If so, the case is submitted via cape.cfdx.queue.pqsub(), and otherwise the case is started using a system call.

Before starting case, this function checks the folder using cape.cfdx.cntl.CheckCase(); if this function returns None, the case is not started. Actual starting of the case is done using CaseStartCase(), which has a specific version for each CFD solver.

Call:
>>> pbs = cntl.StartCase(i)
Inputs:
cntl: cape.cfdx.cntl.Cntl

Overall CAPE control instance

i: int

Index of the case to check (0-based)

Outputs:
pbs: int | None

PBS job ID if submitted successfully

StopCase(i: int)

Stop a case if running

This function deletes a case’s PBS job and removes the RUNNING file if it exists.

Call:
>>> cntl.StopCase(i)
Inputs:
cntl: cape.cfdx.cntl.Cntl

Cape control interface

i: int

Index of the case to check (0-based)

UnarchiveCases(**kw)

Unarchive a list of cases

Call:
>>> cntl.UnarchiveCases(**kw)
Inputs:
cntl: cape.cfdx.cntl.Cntl

Instance of control interface

Versions:
  • 2017-03-13 @ddalle: v1.0

  • 2023-10-20 @ddalle: v1.1; arbitrary-depth frun

  • 2024-09-20 @ddalle: v2.0; use CaseArchivist

UnmarkCase(**kw)

Remove PASS or ERROR marking from one or more cases

Call:
>>> cntl.UnmarkCase(**kw)
Inputs:
cntl: cape.cfdx.cntl.Cntl

Overall CAPE control instance

I: list[int]

List of indices

cons: list[str]

List of constraints like 'Mach<=0.5'

Versions:
  • 2019-06-14 @ddalle: v1.0

UpdateCaseProp(**kw)

Update generic-property databook for one or more comp

Call:
>>> cntl.UpdateCaseProp(cons=[], **kw)
Inputs:
cntl: cape.cfdx.cntl.Cntl

Overall CAPE control instance

prop: {None} | str

Wildcard to subset list of "Prop" components

I: list[int]

List of indices

cons: list[str]

List of constraints like 'Mach<=0.5'

Versions:
  • 2022-04-08 @ddalle: v1.0

UpdateFM(**kw)

Collect force and moment data

Call:
>>> cntl.UpdateFM(cons=[], **kw)
Inputs:
cntl: cape.cfdx.cntl.Cntl

Overall CAPE control instance

fm, aero: {None} | str

Wildcard to subset list of FM components

I: list[int]

List of indices

cons: list[str]

List of constraints like 'Mach<=0.5'

Versions:
  • 2014-12-12 @ddalle: v1.0

  • 2014-12-22 @ddalle: v2.0
    • Complete rewrite of DataBook class

    • Eliminate “Aero” class

  • 2017-04-25 @ddalle: v2.1, add wildcards

  • 2018-10-19 @ddalle: v3.0, rename from Aero()

UpdateLL(**kw)

Update one or more line load data books

Call:
>>> cntl.UpdateLL(ll=None, **kw)
Inputs:
cntl: cape.cfdx.cntl.Cntl

Overall CAPE control instance

ll: {None} | str

Optional name of line load component to update

I: list[int]

List of indices

cons: list[str]

List of constraints like 'Mach<=0.5'

delete: True | {False}

Option to delete entries i/o adding them

Versions:
  • 2016-06-07 @ddalle: v1.0

  • 2016-12-21 @ddalle: v1.1; add pbs flag

  • 2017-04-25 @ddalle: v1.2; rm pbs, add delete

  • 2025-08-13 @ddalle; v2.0; use dex

UpdatePyFuncDataBook(**kw)

Update Python function databook for one or more comp

Call:
>>> cntl.UpdatePyFuncDataBook(cons=[], **kw)
Inputs:
cntl: cape.cfdx.cntl.Cntl

Overall CAPE control instance

prop: {None} | str

Wildcard to subset list of "PyFunc" components

I: list[int]

List of indices

cons: list[str]

List of constraints like 'Mach<=0.5'

Versions:
  • 2022-04-10 @ddalle: v1.0

UpdateReport(**kw)

Update a report

Call:
>>> cntl.UpdateReport(**kw)
Inputs:
cntl: cape.cfdx.cntl.Cntl

CAPE main control instance

report: {True} | str

Name of report (or first report)

I: {None} | np.ndarray[int]

Indices to report

Versions:
  • 2025-08-25 @ddalle: v1.0

UpdateSurfCp(**kw)

Collect surface pressure data

Call:
>>> cntl.UpdateSurfCp(cons=[], **kw)
Inputs:
cntl: cape.cfdx.cntl.Cntl

Overall CAPE control instance

fm, aero: {None} | str

Wildcard to subset list of FM components

I: list[int]

List of indices

cons: list[str]

List of constraints like 'Mach<=0.5'

Versions:
  • 2014-12-12 @ddalle: v1.0

  • 2014-12-22 @ddalle: v2.0
    • Complete rewrite of DataBook class

    • Eliminate “Aero” class

  • 2017-04-25 @ddalle: v2.1, add wildcards

  • 2018-10-19 @ddalle: v3.0, rename from Aero()

UpdateTS(**kw)

Update one or more time series data books

Call:
>>> cntl.UpdateTS(ts=None, **kw)
Inputs:
cntl: cape.cfdx.cntl.Cntl

Overall CAPE control instance

ts: {None} | str

Optional name of time series component to update

I: list[int]

List of indices

cons: list[str]

List of constraints like 'Mach<=0.5'

pbs: True | {False}

Whether or not to calculate line loads with PBS scripts

Versions:
  • 2016-06-07 @ddalle: v1.0

  • 2016-12-21 @ddalle: v1.1, Add pbs flag

  • 2017-04-25 @ddalle: v1.2
    • Removed pbs

    • Added --delete

UpdateTriqFM(**kw)

Update one or more TriqFM data books

Call:
>>> cntl.UpdateTriqFM(comp=None, **kw)
Inputs:
cntl: cape.cfdx.cntl.Cntl

Control class

comp: {None} | str

Name of TriqFM component

I: list[int]

List of indices

cons: list[str]

List of constraints like 'Mach<=0.5'

Versions:
  • 2017-03-29 @ddalle: v1.0

UpdateTriqPoint(**kw)

Update one or more TriqPoint point sensor data books

Call:
>>> cntl.UpdateTriqPoint(comp=None, **kw)
Inputs:
cntl: cape.cfdx.cntl.Cntl

Control class

comp: {None} | str

Name of TriqFM component

I: list[int]

List of indices

cons: list[str]

List of constraints like 'Mach<=0.5'

Versions:
  • 2017-03-29 @ddalle: v1.0

WriteCaseJSON(i: int, rc: dict | None = None)

Write JSON file with run control settings for case i

Call:
>>> cntl.WriteCaseJSON(i, rc=None)
Inputs:
cntl: cape.cfdx.cntl.Cntl

Generic control class

i: int

Run index

rc: {None} | dict

If specified, write specified “RunControl” options

Versions:
  • 2015-10-19 @ddalle: v1.0

  • 2023-03-31 @ddalle: v2.0; manual options input

  • 2023-08-29 @ddalle: v2.1; call sample_dict()

  • 2024-08-24 @ddalle: v2.2; use CaseRunner

  • 2025-01-23 @ddalle: v2.3; eliminate Arvhive settings

WriteConditionsJSON(i: int)

Write JSON file with run matrix settings for case i

Call:
>>> cntl.WriteConditionsJSON(i, rc=None)
Inputs:
cntl: cape.cfdx.cntl.Cntl

Generic control class

i: int

Run index

rc: {None} | dict

If specified, write specified “RunControl” options

Versions:
  • 2021-09-08 @ddalle: v1.0

WritePBS(i: int)

Write the PBS script(s) for a given case

Call:
>>> cntl.WritePBS(i)
Inputs:
cntl: cape.pyfun.cntl.Cntl

CAPE main control instance

i: int

Run index

Versions:
  • 2014-10-19 @ddalle: v1.0

  • 2023-10-20 @ddalle: v1.1; arbitrary frun depth

  • 2024-08-01 @ddalle: v2.0; solver-agnostic

WritePBSHeader(fp: IOBase, i: int | None = None, j: int = 0, typ: str | None = None, wd: str | None = None)

Write common part of PBS or Slurm script

Call:
>>> cntl.WritePBSHeader(fp, i=None, j=0, typ=None, wd=None)
Inputs:
cntl: cape.cfdx.cntl.Cntl

Overall CAPE control instance

fp: IOBase

Open file handle

i: {None} | int

Case index (ignore if None); used for PBS job name

j: int

Phase number

typ: {None} | "batch" | "post"

Group of PBS options to use

wd: {None} | str

Folder to enter when starting the job

Versions:
  • 2015-09-30 @ddalle: v1.0, fork WritePBS()

  • 2016-09-25 @ddalle: v1.1, “BatchPBS”

  • 2016-12-20 @ddalle: v1.2
    • Consolidated to opts

    • Added prefix

  • 2024-08-15 @ddalle: v1.3
    • Use cntl.opts.name as prefix

    • User-controlled job name length, longer default

abspath(fname: str) str

Absolutize a file name

Call:
>>> fabs = cntl.abspath(fname)
Inputs:
cntl: Cntl

CAPE main control instance

fname: str

A file name

Outputs:
fabs: str

Absolute file path

Versions:
  • 2021-10-25 @ddalle: v1.0

  • 2025-03-26 @ddalle: v1.1; Windows compatibility fix

cache_iter

CaseCache Cache of current iteration for each case

caseindex

int Case index of the current case runner

caseloop(casefunc: Callable, **kw)

Loop through cases and execute function for each case

Call:
>>> cntl.caseloop(casefun, **kw)
Inputs:
cntl: cape.cfdx.cntl.Cntl

CAPE run matrix control instance

indent: {0} | int

Number of spaces to indent each case name

Versions:
  • 2025-02-12 @ddalle: v1.0

caseloop_verbose(casefunc: Callable | None = None, **kw) int

Loop through cases and produce verbose table

Call:
>>> n = cntl.caseloop_verbose(casefunc, **kw)
Inputs:
cntl: cape.cfdx.cntl.Cntl

Overall CAPE control instance

casefunc: {None} | Callable

Optional function to run in each case folder

I: {None} | np.ndarray[int]

Case indices

Outputs:
n: int

Number of cases started/submitted

Versions:
  • 2025-06-19 @ddalle: v1.0

caserunner

CaseRunner Slot for the current case runner

check_case_job(i: int, active: bool = True) str

Get queue status of the PBS/Slurm job from case i

Call:
>>> s = cntl.check_case_job(i, active=True)
Inputs:
cntl: Cntl

Controller for one CAPE run matrix

i: int

Case index

active: {True} | False

Whether or not to allow new calls to qstat

Outputs:
s: str

Job queue status

  • -: not in queue

  • Q: job queued (not running)

  • R: job running

  • H: job held

  • E: job error status

Versions:
  • 2025-05-04 @ddalle: v1.0

check_case_status(i: int, active: bool = True) str

Get queue status of the PBS/Slurm job from case i

Call:
>>> sts = cntl.check_case_job(i, active=True)
Inputs:
cntl: Cntl

Controller for one CAPE run matrix

i: int

Case index

active: {True} | False

Whether or not to allow new calls to qstat

Outputs:
sts: str

Case status

  • ---: folder does not exist

  • INCOMP: case incomplete but [partially] set up

  • QUEUE: case waiting in PBS/Slurm queue

  • RUNNING: case currently running

  • DONE: all phases and iterations complete

  • PASS: DONE and marked by user as passed

  • ZOMBIE: seems running; but no recent file updates

  • PASS*: case marked by user but not DONE

  • ERROR: case marked as error

  • FAIL: case failed but not marked by user

Versions:
  • 2025-05-04 @ddalle: v1.0

copy_files(i: int)

Copy files from Mesh section

This applies to both CopyFiles and CopyAsFiles in the Mesh section. The former will copy a given file into the run folder for case i using the base name of the original (source) file. Using

"Mesh": {
    "CopyAsFiles": {
        "inputs/mesh-config02.ugrid": "mesh.ugrid"
    }
}

will copy the file inputs/mesh-config02.ugrid into the run folder but name it mesh.ugrid there.

Call:
>>> cntl.copy_files(i)
Inputs:
cntl: cape.cfdx.cntl.Cntl

Overall CAPE control instance

i: int

Case index

Versions:
  • 2025-09-19 @ddalle: v1.0

data

dict[DataExchanger] Data extraction classes for each component of DataBook

exec_cntl_function_dict(funcspec: dict)

Execute a Cntl function, accessing user-specified modules

Call:
>>> v = cntl.exec_cntl_function_dict(funcspec)
Inputs:
cntl: cape.cfdx.cntl.Cntl

Overall control interface

funcspec: dict

Function opts parsed by UserFuncOpts

Outputs:
v: any

Output from execution of function

Versions:
  • 2025-03-28 @ddalle: v1.0

exec_cntlfunction(funcspec: str | dict) Any

Execute a Cntl function, accessing user-specified modules

Call:
>>> v = cntl.exec_cntlfunction(funcname)
>>> v = cntl.exec_cntlfunction(funcspec)
Inputs:
cntl: cape.cfdx.cntl.Cntl

Overall control interface

funcname: str

Name of function to execute, e.g. "mymod.myfunc"

funcspec: dict

Function opts parsed by UserFuncOpts

Outputs:
v: any

Output from execution of function

Versions:
  • 2025-03-28 @ddalle: v1.0

exec_cntlfunction_str(funcname: str) Any

Execute a function from cntl.modules

Call:
>>> v = cntl.exec_modfunction(funcname, a, kw, name=None)
Inputs:
cntl: cape.cfdx.cntl.Cntl

Overall control interface

funcname: str

Name of function to execute, e.g. "mymod.myfunc"

Outputs:
v: any

Output from execution of function

Versions:
  • 2025-03-28 @ddalle: v1.0

exec_modfunction(funcname: str, a: tuple | list | None = None, kw: dict | None = None, name: str | None = None) Any

Execute a function from cntl.modules

Call:
>>> v = cntl.exec_modfunction(funcname, a, kw, name=None)
Inputs:
cntl: cape.cfdx.cntl.Cntl

Overall control interface

funcname: str

Name of function to execute, e.g. "mymod.myfunc"

a: {None} | tuple

Positional arguments to called function

kw: {None} | dict

Keyworkd arguments to called function

name: {None} | str

Hook name to use in status update

Outputs:
v: any

Output from execution of function

Versions:
  • 2022-04-12 @ddalle: v1.0

  • 2025-03-28 @ddalle: v1.1; improve error messages

get_databook_comp_nmin(comp: str) int

Calculate the min iterations required for a DataBook comp

Call:
>>> n = cntl.get_databook_comp_nmin(comp)
Inputs:
cntl: cape.cfdx.cntl.Cntl

CAPE run matrix control instance

comp: str

Name of DataBook component

Outputs:
n: int

Iteration number

Versions:
  • 2025-07-29 @ddalle: v1.0

get_funcname(frame: int = 1) str

Get name of calling function, mostly for log messages

Call:
>>> funcname = runner.get_funcname(frame=1)
Inputs:
cntl: Cntl

CAPE run matrix control instance

frame: {1} | int

Depth of function to seek title of

Outputs:
funcname: str

Name of calling function

Versions:
  • 2025-04-30 @ddalle

get_logger() CntlLogger

Get current logger and/or initialize one

Call:
>>> logger = cntl.get_logger()
Inputs:
cntl: Cntl

CAPE run matrix control instance

Outputs:
logger: CntlLogger

Run matrix logger instance

Versions:
  • 2025-04-30 @ddalle: v1.0

get_pbs_jobs(force: bool = False, u: str | None = None, server: str | None = None, qstat: bool = True) dict

Get dictionary of current jobs active by one user

Call:
>>> jobs = cntl.get_pbs_jobs(force=False, **kw)
Inputs:
cntl: cape.cfdx.cntl.Cntl

Overall CAPE control instance

force: True | {False}

Query current queue even if cntl.jobs exists

u: {None} | str

User name (defaults to process username)

server: {None} | str

Name of non-default PBS/Slurm server

Outputs:
jobs: dict

Information on each job by ID number

Versions:
  • 2024-01-12 @ddalle: v1.0

  • 2024-08-22 @ddalle: v1.1; add qstat option

  • 2025-05-01 @ddalle: v1.2; simplify flow

get_phase_niter(i: int, j: int) int

Get number of steps for one call of phase j in case i

Call:
>>> niter = cntl.get_Phase_inter(i, j)
Inputs:
cntl: cape.pyfun.cntl.Cntl

CAPE main control instance

i: int

Case index

j: int

Phase number

Outputs:
niter: int

Number of iterations for phase j; may be specific to case i

Versions:
  • 2025-08-11 @ddalle: v1.0

get_transformation_matrix(topts: dict, i: int) ndarray | None

Calculate rotation matrix for a databook transformation

Call:
>>> mat = cntl.get_transformation_matrix(topts, i)
Inputs:
cntl: cape.cfdx.cntl.Cntl

Overall CAPE control instance

topts: dict

Definitions for transformation

i: int

Case number

Outputs:
mat: None | np.ndarray[float]

Rotation matrix if topts is a rotation

Versions:
  • 2025-01-30 @ddalle: v1.0

getval(opt: str, i: int) Any

Get run matrix or case status value for one case

Call:
>>> v = cntl.getval(opt, i)
Inputs:
cntl: cape.cfdx.cntl.Cntl

Overall CAPE control instance

opt: str

Name of option or run matrix key

i: int

Case index

Outputs:
v: Any

Value of option opt for case i

Versions:
  • 2025-06-16 @ddalle: v1.0

getvalstr(opt: str, i: int) str

Get value of run matrix variable as string

Call:
>>> txt = cntl.getvalstr(opt, i)
Inputs:
cntl: cape.cfdx.cntl.Cntl

Overall CAPE control instance

opt: str

Name of option or run matrix key

i: int

Case index

Outputs:
txt: str

Text of value of option opt for case i

Versions:
  • 2025-06-16 @ddalle: v1.0

import_module(modname: str)

Import a module by name, if possible

Call:
>>> mod = cntl.import_module(modname)
Inputs:
cntl: cape.cfdx.cntl.Cntl

Overall control interface

modname: str

Name of module to import

Outputs:
mod: module

Python module

Versions:
  • 2025-03-28 @ddalle: v1.0

init_post()

Do py{x} specific initialization actions

Call:
>>> cntl.init_post()
Inputs:
cntl: cape.cfdx.cntl.Cntl

CAPE run matrix control instance

Versions:
  • 2023-05-31 @ddalle: v1.0

job

str Job name to check

jobqueues

list[str] List of queues that have been checked

jobs

dict[str] Dictionary of PBS/slurm job IDs

Link files from Mesh section

This applies to both LinkFiles and LinkAsFiles in the Mesh section. The former will copy a given file into the run folder for case i using the base name of the original (source) file. Using

"Mesh": {
    "LinkAsFiles": {
        "inputs/mesh-config02.ugrid": "mesh.ugrid"
    }
}

will create a link (using the absolute path) from inputs/mesh-config02.ugrid to mesh.ugrid in the case run folder.

Call:
>>> cntl.link_files(i)
Inputs:
cntl: cape.cfdx.cntl.Cntl

Overall CAPE control instance

i: int

Case index

Versions:
  • 2025-09-19 @ddalle: v1.0

log_main(msg: str, title: str | None = None, parent: int = 0)

Write a message to primary log

Call:
>>> runner.log_main(msg, title, parent=0)
Inputs:
runner: CaseRunner

Controller to run one case of solver

msg: str

Primary content of message

title: {None} | str

Manual title (default is name of calling function)

parent: {0} | int

Extra levels to use for calling function name

Versions:
  • 2025-04-30 @ddalle: v1.0

logger

CntlLogger Run matrix logger instacnce

make_case_folder(i: int)

Create folder(s) if needed for case i

Call:
>>> cntl.make_case_folder(i)
Inputs:
cntl: cape.cfdx.cntl.Cntl

Overall CAPE control instance

i: int

Index of case to analyze

Versions:
  • 2023-08-25 @ddalle: v1.0 (CreateFolder)

  • 2023-10-20 @ddalle: v2.0; support arbitrary depth

modules

dict Dictionary of imported custom modules

opts

cape.cfdx.options.Options Options interface for this run matrix

prepare_mesh_overset(i: int)

Copy/link mesh files from config folder into case folder

Call:
>>> cntl.prepare_mesh_overset(i)
Inputs:
cntl: Cntl

CAPE run matrix controller instance

i: int

Case index

Versions:
  • 2024-10-10 @ddalle: v1.0

preprocess_kwargs(kw: dict)

Preprocess command-line arguments and flags/keywords

This will effect the following CLI options:

--cons CONS

Comma-separated constraints split into a list

-x FPY

Each -x argument is executed (can be repeated)

-I INDS

Convert INDS like 3-6,8 to [3, 4, 5, 8]

Call:
>>> opts = cntl.cli_preprocess(*a, **kw)
Inputs:
cntl: cape.cfdx.cntl.Cntl

Overall CAPE control instance

kw: dict[True | False | str]

CLI keyword arguments and flags, modified in-place

Versions:
  • 2024-12-19 @ddalle: v1.0

process_mesh_filename(fname: str, fproj: str | None = None) str

Return a mesh file name using the project root name

Call:
>>> fout = cntl.process_mesh_filename(fname, fproj=None)
Inputs:
cntl: Cntl

Run matrix control instance for unstructured-mesh solver

fname: str

Raw file name to be converted to case-folder file name

fproj: {None} | :class;`str`

Project root name

Outputs:
fout: str

Name of file name using project name as prefix

Versions:
  • 2016-04-05 @ddalle: v1.0 (pyfun)

  • 2023-03-15 @ddalle: v1.1; add fproj

  • 2024-10-22 @ddalle: v2.0; move to cfdx

qdel_cases(**kw)

Kill/stop PBS job of cases

This function deletes a case’s PBS/Slurm jobbut not delete the foder for a case.

Call:
>>> cntl.qdel_cases(**kw)
Inputs:
cntl: cape.cfdx.cntl.Cntl

Cape control interface

I: {None} | list[int]

List of cases to delete

kw: dict

Other subset parameters, e.g. re, cons

Versions:
  • 2025-06-22 @ddalle: v1.0

read_case_json(i: int) RunControlOpts

Read case.json file from case i if possible

Call:
>>> rc = cntl.read_case_json(i)
Inputs:
cntl: cape.cfdx.cntl.Cntl

Instance of control class

i: int

Case index

Outputs:
rc: None | dict

Run control interface read from case.json file

Versions:
  • 2016-12-12 @ddalle: v1.0

  • 2017-04-12 @ddalle: v1.1; add to cape.cfdx

  • 2023-06-29 @ddalle: v2.0; use _case_mod

  • 2023-07-07 @ddalle: v2.1; use CaseRunner

read_dex(comp: str, force: bool = False) DataExchanger

Read a DataBook component using DataExchanger

Call:
>>> db = cntl.read_dex(comp, force=False)
Inputs:
cntl: Cntl

CAPE run matrix controller instance

comp: str

Name of component to read

force: True | {False}

Option to re-read even if present in database

Outputs:
db: cape.cfdx.dex.DataExchanger

Data extracted from run matrix for comp comp

Versions:
  • 2025-07-25 @ddalle: v1.0

read_options(fjson: str)

Read options using appropriate class

This allows users to set warning mode via an environment variable.

Call:
>>> cntl.read_options(fjson)
Inputs:
cntl: cape.cfdx.cntl.Cntl

CAPE run matrix control instance

fjson: str

Name of JSON file to read

Versions:
  • 2023-05-26 @ddalle: v1.0; forked from __init__()

  • 2023-12-13 @ddalle: v1.1; add RootDir and JSONFile

rm_cases(prompt: bool = True, **kw) int

Delete one or more cases

This function deletes a case’s PBS job and removes the entire directory. By default, the method prompts for confirmation before deleting; set prompt to False to delete without prompt, but only cases with 0 iterations can be deleted this way.

Call:
>>> n = cntl.rm_cases(prompt=True, **kw)
Inputs:
cntl: cape.cfdx.cntl.Cntl

Cape control interface

prompt: {True} | False

Whether or not to prompt user before deleting case

I: {None} | list[int]

List of cases to delete

kw: dict

Other subset parameters, e.g. re, cons

Outputs:
n: int

Number of folders deleted

Versions:
  • 2025-06-20 @ddalle: v1.0

run_batch(argv: list) str

Write and submit PBS/Slurm script for a CLI

Call:
>>> jobid = cntl.run_batch(argv)
Inputs:
argv: list[str]

List of command-line inputs

Outputs:
jobid: str

PBS/Slurm job number/ID

Versions:
  • 2024-12-20 @ddalle: v1.0

update_dex_case(comp: str, i: int) int

Update one case of a DataBook component

Call:
>>> n = cntl.update_dex_case(comp, i)
Inputs:
cntl: Cntl

CAPE run matrix controller instance

comp: str

Name of component to read

i: int

Case to index

Outputs:
n: 0 | 1

Number of updates made

Versions:
  • 2025-07-25 @ddalle: v1.0

update_dex_comp(comp: str, **kw)

Update a DataBook component

Call:
>>> n = cntl.update_dex_comp(comp, **kw)
Inputs:
cntl: Cntl

CAPE run matrix controller instance

comp: str

Name of component to read

I: {None} | np.ndarray[int]

Indices of cases to process

Versions:
  • 2025-07-29 @ddalle: v1.0

x

cape.cfdx.runmatrix.RunMatrix Run matrix instance

cape.cfdx.cntl.JOB_STATUSES = ('PASS', 'PASS*', '---', 'INCOMP', 'RUN', 'DONE', 'QUEUE', 'ERROR', 'ERROR*', 'FAIL', 'ZOMBIE', 'THIS_JOB')

tuple[str] Typical job statuses

cape.cfdx.cntl.run_rootdir(func)

Decorator to run a function within a specified folder

Call:
>>> func = run_rootdir(func)
Wrapper Signature:
>>> v = cntl.func(*a, **kw)
Inputs:
func: func

Name of function

cntl: Cntl

Control instance from which to use cntl.RootDir

a: tuple

Positional args to cntl.func()

kw: dict

Keyword args to cntl.func()

Versions:
  • 2018-11-20 @ddalle: v1.0

  • 2020-02-25 @ddalle: v1.1: better exceptions

  • 2023-06-16 @ddalle: v1.2; use finally