cape.cfdx.lineLoad: Sectional loads databook

This module contains functions for reading and processing sectional loads. This module is developed from cape.cfdx.dataBook, which is the overall databook interface. It provides the primary class DBLineLoad, which is a subclass of cape.cfdx.dataBook.DBBase. This class is an interface to all line load data for a specific surface component.

Overall, this module provides three classes:

  • DBLineLoad: Line load database for one component

  • CaseLL: Line load data for one component of one CFD solution

  • CaseSeam: Interface to “seam curves” to plot outline of surface

In addition to a database interface, this module also creates line loads. Specific modifications to the generic template provided here are needed for each individual CFD solver:

To calculate line loads, this module utilizes the Chimera Grid Tools executable called triloadCmd. This works by taking a Cart3D annotated surface triangulation (triq file), slicing the surface component into slices, and computing the loads on each slice. In order to create this surface triangulation, some solvers require steps to process the native CFD output. Those steps are performed by the solver-specific lineLoad modules.

class cape.cfdx.lineLoad.CaseLL(comp, proj='LineLoad', sec='dlds', **kw)

Interface to individual sectional load

Call:
>>> LL = CaseLL(comp, proj='LineLoad', sec='slds')
Inputs:
comp: str

Name of component

proj: str

Prefix for sectional load output files

sec: "clds" | {"dlds"} | "slds"

Cut type, cumulative, derivative, or sectional

ext: "clds" | {"dlds"} | "slds" | "csv"

File extension

fdir {None} | str

Name of sub folder to use

Outputs:
LL: cape.cfdx.lineLoad.CaseLL

Individual line load for one component from one case

Versions:
  • 2015-09-16 @ddalle: First version

  • 2016-06-07 @ddalle: Second version, universal

Copy()

Create a copy of a case line load object

Call:
>>> LL2 = LL.Copy()
Inputs:
LL: cape.cfdx.lineLoad.CaseLL

Single-case, single-component line load interface

Outputs:
LL2: cape.cfdx.lineLoad.CaseLL

Copy of the line load interface

Versions:
  • 2016-12-27 @ddalle: First version

CorrectCA(CA, CA1)

Correct CA using an unnormalized function

This function takes a function with the same dimensions as LL.CA and adds a multiple of it so that the integrated axial force coefficient (CA) matches a target integrated value given by the user.

Call:
>>> LL.CorrectCA(CA, CA1)
Inputs:
LL: cape.cfdx.lineLoad.CaseLL

Instance of single-case line load interface

CA: float

Target integrated value of CA

CA1: np.ndarray (LL.x.size)

Basis function to correct CA

Versions:
  • 2016-12-27 @ddalle: First version

CorrectCLL(CLL, CLL1)

Correct CLL using an unnormalized function

This function takes a function with the same dimensions as LL.CLL and adds a multiple of it so that the integrated rolling moment coefficient (CLL) matches a target integrated value given by the user.

Call:
>>> LL.CorrectCLL(CLL, CLL1)
Inputs:
LL: cape.cfdx.lineLoad.CaseLL

Instance of single-case line load interface

CLL: float

Target integrated value of CLL

CLL1: np.ndarray (LL.x.size)

Basis function to correct CLL

Versions:
  • 2016-12-27 @ddalle: First version

CorrectCN(CN, CLM, UCN, sig=None, xMRP=0.0)

Correct CN and CLM given n unnormalized functions

This function takes an m by n matrix where m is the size of LL.CN. It then calculates an increment to LL.CN that is a linear combination of the columns of that matrix UCN such that the integrated normal force coefficient (CN) and pitching moment coefficient (CLM) match target values provided by the user. The increment is

\[\Delta C_N = \sum_{i=1}^n k_i\phi_i\]

where \(\phi_i`\) is the i*th column of *UCN scaled so that it has an L2 norm of 1.

The weights of the linear coefficient are chosen in order to minimize the sum of an objective function subject to the integration constraints mentioned above. This objective function is

\[\sum_{i=1}^n a_i k_i^2 / \sigma_i\]

where \(a_i\) is the maximum absolute value of column i of UCN and \(\sigma_i\) is the associated singular value.

Call:
>>> LL.CorrectCN(CN, CLM, UCN, sig=None, xMRP=0.0)
Inputs:
LL: cape.cfdx.lineLoad.CaseLL

Instance of single-case line load interface

CN: float

Target integrated value of CN

CLM: float

Target integrated value of CLM

UCN: np.ndarray (LL.x.size,*n*)

Matrix of CN adjustment basis functions

sig: {None} | np.ndarray (n,)

Array of singular values

xMRP: {0.0} | float

x-coordinate of MRP divided by reference length

Versions:
  • 2017-02-02 @ddalle: First version

CorrectCN2(CN, CLM, CN1, CN2, xMRP=0.0)

Correct CN and CLM given two unnormalized functions

This function takes two functions with the same dimensions as LL.CN and adds a linear combination of them so that the integrated normal force coefficient (CN) and pitching moment coefficient (CLM) match target integrated values given by the user.

The user must specify two basis functions for correcting the CN sectional loads, and they must be linearly independent. The corrections to CLM will be selected automatically to ensure consistency between the CN and CLM.

Call:
>>> LL.CorrectCN2(CN, CLM, CN1, CN2)
Inputs:
LL: cape.cfdx.lineLoad.CaseLL

Instance of single-case line load interface

CN: float

Target integrated value of CN

CLM: float

Target integrated value of CLM

CN1: np.ndarray (LL.x.size)

First CN sectional load correction basis function

CN2: np.ndarray (LL.x.size)

Second CN sectional load correction basis function

xMRP: {0.0} | float

x-coordinate of MRP divided by reference length

Versions:
  • 2016-12-27 @ddalle: First version

CorrectCY(CY, CLN, UCY, sig=None, xMRP=0.0)

Correct CY and CLN given n unnormalized functions

This function takes an m by n matrix where m is the size of LL.CY. It then calculates an increment to LL.CY that is a linear combination of the columns of that matrix UCY such that the integrated normal force coefficient (CY) and pitching moment coefficient (CLN) match target values provided by the user. The increment is

\[\Delta C_Y = \sum_{i=1}^n k_i\phi_i\]

where \(\phi_i`\) is the i*th column of *UCY scaled so that it has an L2 norm of 1.

The weights of the linear coefficient are chosen in order to minimize the sum of an objective function subject to the integration constraints mentioned above. This objective function is

\[\sum_{i=1}^n a_i k_i^2 / \sigma_i\]

where \(a_i\) is the maximum absolute value of column i of UCY and \(\sigma_i\) is the associated singular value.

Call:
>>> LL.CorrectCY(CY, CLN, UCY, sig=None, xMRP=0.0)
Inputs:
LL: cape.cfdx.lineLoad.CaseLL

Instance of single-case line load interface

CY: float

Target integrated value of CY

CLN: float

Target integrated value of CLN

UCY: np.ndarray (LL.x.size,*n*)

Matrix of CY adjustment basis functions

sig: {None} | np.ndarray (n,)

Array of singular values

xMRP: {0.0} | float

x-coordinate of MRP divided by reference length

Versions:
  • 2017-02-02 @ddalle: First version

CorrectCY2(CY, CLN, CY1, CY2, xMRP=0.0)

Correct CY and CLN given two unnormalized functions

This function takes two functions with the same dimensions as LL.CY and adds a linear combination of them so that the integrated side force coefficient (CY) and yawing moment coefficient (CLN) match target integrated values given by the user.

The user must specify two basis functions for correcting the CY sectional loads, and they must be linearly independent. The corrections to CLN will be selected automatically to ensure consistency between the CY and CLN.

Call:
>>> LL.CorrectCY2(CY, CLN, CY1, CY2)
Inputs:
LL: cape.cfdx.lineLoad.CaseLL

Instance of single-case line load interface

CY: float

Target integrated value of CY

CLN: float

Target integrated value of CLN

CY1: np.ndarray (LL.x.size)

First CY sectional load correction basis function

CY2: np.ndarray (LL.x.size)

Second CY sectional load correction basis function

xMRP: {0.0} | float

x-coordinate of MRP divided by reference length

Versions:
  • 2016-12-27 @ddalle: First version

CorrectLinear(CN, CLM, CY, CLN, xMRP=0.0)

Correct line loads to match target integrated values using lines

Call:
>>> LL2 = LL.CorrectLinear(CN, CLM, xMRP=0.0)
Inputs:
LL: cape.cfdx.lineLoad.CaseLL

Instance of single-case line load interface

CN: float

Target integrated value of CN

CLM: float

Target integrated value of CLM

CY: float

Target integrated value of CY

CLN: float

Target integrated value of CLN

xMRP: {0.0} | float

x-coordinate of MRP divided by reference length

Outputs:
LL2: cape.cfdx.lineLoad.CaseLL

Line loads with integrated loads matching CN and CLM

Versions:
  • 2016-12-27 @ddalle: First version

Plot(coeff, **kw)

Plot a single line load

Call:
>>> LL.Plot(coeff, **kw)
Inputs:
LL: pyCart.lineLoad.CaseLL

Instance of data book line load interface

coeff: str

Name of coefficient to plot

x: {"x"} | "y" | "z"

Axis to use for independent axis

Seams: {[]} | list (str | CaseSeam)

List of seams to plot

SeamLocation: {"bottom"} | "left" | "right" | "top"

Location on which to plot seams

Orientation: {"vertical"} | "horizontal"

If not ‘vertical’, flip x and y axes

LineOptions: {{}} | dict

Dictionary of plot options

SeamOptions: {{}} | dict

Dictionary of plot options

Label: {LL.comp} | str

Plot label, LineOptions['label'] supersedes this variable

XLabel: {"x/Lref"} | str

Label for x-axis

YLabel: {coeff} | str

Label for y-axis

Legend: [ {True} | False ]

Whether or not to use a legend

FigWidth: float

Figure width

FigHeight: float

Figure height

SubplotMargin: {0.015} | float

Margin between subplots

Versions:
  • 2016-06-09 @ddalle: First version

PlotSeam(s='z', **kw)

Plot a set of seam curves

Call:
>>> h = LL.PlotSeam(s='z', **kw)
Inputs:
LL: cape.cfdx.lineLoad.CaseLL

Instance of data book line load interface

s: "x" | "y" | {"z"}

Type of slice to plot

x: {"x"} | "y" | "z"

Axis to plot on x-axis

y: "x" | {"y"} | "z"

Axis to plot on y-axis

LineOptions: {{}} | dict

Dictionary of plot options

Label: {LL.comp} | str

Plot label, LineOptions['label'] supersedes this variable

XLabel: {"x/Lref"} | str

Label for x-axis

XLabel: {coeff} | str

Label for y-axis

Outputs:
h: dict

Dictionary of plot handles

Versions:
  • 2016-06-09 @ddalle: First version

ReadCSV(fname=None, delim=',')

Read a sectional loads csv file from the data book

Call:
>>> LL.ReadCSV(fname, delim=',')
Inputs:
LL: cape.cfdx.lineLoad.CaseLL

Single-case, single component, line load interface

fname: str

Name of file to read

delim: {','} | ' ' | str

Text delimiter

Versions:
  • 2016-06-07 @ddalle: First version

ReadLDS(fname=None)

Read a sectional loads *.?lds file from triloadCmd

Call:
>>> LL.ReadLDS(fname)
Inputs:
LL: cape.cfdx.lineLoad.CaseLL

Single-case, single component, line load interface

fname: str

Name of file to read

Versions:
  • 2015-09-15 @ddalle: First version

ReadSeamCurves()

Read seam curves from a data book directory

Call:
>>> LL.ReadSeamCurves()
Inputs:
LL: pyCart.lineLoad.CaseLL

Instance of data book line load interface

Versions:
  • 2015-09-17 @ddalle: First version

WriteCSV(fname=None, delim=',')

Write a sectional loads csv file

Call:
>>> LL.WriteCSV(fname, delim=',')
Inputs:
LL: cape.cfdx.lineLoad.CaseLL

Single-case, single component, line load interface

fname: str

Name of file to write

delim: {','} | ' ' | str

Text delimiter

Versions:
  • 2016-06-07 @ddalle: First version

class cape.cfdx.lineLoad.CaseSeam(fname, comp='entire', proj='LineLoad')

Seam curve interface

Call:
>>> S = CaseSeam(fname, comp='entire', proj='LineLoad')
Inputs:
fname: str

Name of file to read

comp: str

Name of the component

Outputs:
S cape.cfdx.lineLoad.CaseSeam

Seam curve interface

S.ax: "x" | "y" | "z"

Name of coordinate being held constant

S.x: float | {list (np.ndarray)}

x-coordinate or list of seam x-coordinate vectors

S.y: float | {list (np.ndarray)}

y-coordinate or list of seam y-coordinate vectors

S.z: {float} | list (np.ndarray)

z-coordinate or list of seam z-coordinate vectors

Versions:
  • 2016-06-09 @ddalle: First version

Plot(**kw)

Plot a set of seam curves

Call:
>>> h = S.Plot(**kw)
Inputs:
S cape.cfdx.lineLoad.CaseSeam

Seam curve interface

x: {"x"} | "y" | "z"

Axis to plot on x-axis

y: "x" | {"y"} | "z"

Axis to plot on y-axis

LineOptions: {{}} | dict

Dictionary of plot options

Label: str

Plot label, LineOptions['label'] supersedes this variable

XLabel: {"x/Lref"} | str

Label for x-axis

XLabel: {coeff} | str

Label for y-axis

xpad: {0.03} | float

Relative margin to pad x-axis limits

ypad: {0.03} | float

Relative margin to pad y-axis limits

Outputs:
h: dict

Dictionary of plot handles

Versions:
  • 2016-06-09 @ddalle: First version

Read(fname=None)

Read a seam *.sm[yz] file

Call:
>>> S.Read(fname=None)
Inputs:
S cape.cfdx.lineLoad.CaseSeam

Seam curve interface

fname: str

Name of file to read

Outputs:
S.n: int

Number of points in vector entries

S.x: list (numpy.ndarray)

List of x coordinates of seam curves

S.y: float or list (numpy.ndarray)

Fixed y coordinate or list of seam curve y coordinates

S.z: float or list (numpy.ndarray)

Fixed z coordinate or list of seam curve z coordinates

Versions:
  • 2015-09-17 @ddalle: First version

  • 2016-06-09 @ddalle: Added possibility of x-cuts

Write(fname=None)

Write a seam curve file

Call:
>>> S.Write(fname)
Inputs:
S cape.cfdx.lineLoad.CaseSeam

Seam curve interface

fname: str

Name of file to read

Versions:
  • 2015-09-17 @ddalle: First version

  • 2016-06-09 @ddalle: Added possibility of x-cuts

  • 2016-06-09 @ddalle: Moved to seam class

class cape.cfdx.lineLoad.DBLineLoad(comp, cntl, conf=None, RootDir=None, **kw)

Line load (sectional load) data book for one group

Call:
>>> DBL = DBLineLoad(cntl, comp, conf=None, RootDir=None, targ=None)
Inputs:
cntl: cape.cntl.Cntl

CAPE run matrix control instance

comp: str

Name of line load component

conf: {None} | cape.config.Config

Surface configuration interface

RootDir: {None} | str

Root directory for the configuration

targ: {None} | str

If used, read target data book’s folder

Outputs:
DBL: cape.cfdx.lineLoad.DBLineLoad

Instance of line load data book

DBL.nCut: int

Number of x-cuts to make, from opts

DBL.RefL: float

Reference length

DBL.MRP: numpy.ndarray shape=(3,)

Moment reference center

DBL.x: numpy.ndarray shape=(nCut,)

Locations of x-cuts

DBL.CA: numpy.ndarray shape=(nCut,)

Axial force sectional load, d(CA)/d(x/RefL))

Versions:
  • 2015-09-16 @ddalle: First version

  • 2016-05-11 @ddalle: Moved to cape

CalculateTriloadTransformation(i, topts)

Write transformations to a triload.i input file

Usually this just writes an n for “no”, but it can also write a 3x3 transformation matrix if "Transformations" are defined for DBL.comp.

Call:
>>> R = DBL.CalculateTriloadTransformation(i, topts)
Inputs:
DBL: cape.cfdx.lineLoad.DBLineLoad

Line load data book

i: int

Case number

topts: dict

Dictionary of transformation options

Outputs:
R: np.ndarray shape=(3,3)

Rotation matrix

Versions:
  • 2017-04-14 @ddalle: First version

GetCoeffPOD(coeff, n=2, f=None, **kw)

Create a Proper Orthogonal Decomposition of lineloads for one coeff

Call:
>>> u, s = DBL.GetPOD(coeff, n=None, f=None, **kw)
Inputs:
DBL: cape.cfdx.lineLoad.DBLineLoad

Line load data book

n: {2} | positive int

Number of modes to keep

f: {None} | 0 < float <= 1

Keep enough modes so that this fraction of energy is kept

cons: {None} | list (str)

Constraints for which cases to include in basis

I: {None} | list[int]

List of cases to include in basis

Versions:
  • 2016-12-27 @ddalle: First version

GetCompID()

Create list of component IDs

Call:
>>> DBL.GetCompID()
Inputs:
DBL: cape.cfdx.lineLoad.DBLineLoad

Instance of line load data book

Versions:
  • 2016-12-22 @ddalle: First version, extracted from __init__

GetMRP()

Get moment reference point for given component

Call:
>>> MRP = db.GetMRP()
Inputs:
db: DBLineLoad

Line load databook

Outputs:
MRP: np.ndarray[float]

Coordinates of moment reference point

Versions:
  • 2023-02-03 @ddalle: v1.0

GetRefArea()

Get reference area for given component

Call:
>>> Aref = db.GetRefArea()
Inputs:
db: DBLineLoad

Line load databook

Outputs:
Aref: float

Reference area

Versions:
  • 2023-02-03 @ddalle: v1.0

GetRefLength()

Get reference length for given component

Call:
>>> Lref = db.GetRefLength()
Inputs:
db: DBLineLoad

Line load databook

Outputs:
Lref: float

Reference length

Versions:
  • 2023-02-03 @ddalle: v1.0

GetTriqFile()

Get most recent triq file and its associated iterations

Call:
>>> qtriq, ftriq, n, i0, i1 = DBL.GetTriqFile()
Inputs:
DBL: pyCart.lineLoad.DBLineLoad

Instance of line load data book

Outputs:
qtriq: {False}

Whether or not to convert file from other format

ftriq: str

Name of triq file

n: int

Number of iterations included

i0: int

First iteration in the averaging

i1: int

Last iteration in the averaging

Versions:
  • 2016-12-19 @ddalle: Added to the module

PreprocessTriq(ftriq, **kw)

Perform any necessary preprocessing to create triq file

Call:
>>> ftriq = DBL.PreprocessTriq(ftriq, qpbs=False, f=None)
Inputs:
DBL: cape.cfdx.lineLoad.DBLineLoad

Line load data book

ftriq: str

Name of triq file

qpbs: True | {False}

Whether or not to create a script and submit it

f: {None} | file

File handle if writing PBS script

i: {None} | int

Case index

Versions:
  • 2016-12-19 @ddalle: First version

  • 2016-12-21 @ddalle: Added PBS

Read(fname=None, keys=None)

Read a data book summary file for a single line load group

Call:
>>> DBL.Read()
>>> DBL.Read(fname)
Inputs:
DBL: cape.cfdx.lineLoad.DBLineLoad

Instance of line load data book

fname: str

Name of summary file

Versions:
  • 2015-09-16 @ddalle: First version

ReadCase(i)

Read data from a case from the data book archive

Call:
>>> DBL.ReadCase(i=None, j=None)
Inputs:
DBL: cape.cfdx.lineLoad.DBLineLoad

Line load data book

i: int

Case number from run matrix

j: int

Case number from data book

Versions:
  • 2016-06-07 @ddalle: First version

  • 2017-04-18 @ddalle: Alternate index inputs

ReadSeamCurves()

Read seam curves from a data book directory

Call:
>>> DBL.ReadSeamCurves()
Inputs:
DBL: cape.cfdx.lineLoad.DBLineLoad

Line load data book

Versions:
  • 2015-09-17 @ddalle: First version (CaseLL)

  • 2016-06-09 @ddalle: Adapted for DBLineLoad

RunTriload(qtriq=False, ftriq=None, qpbs=False, i=None)

Run triload for a case

Call:
>>> DBL.RunTriload(**kw)
Inputs:
DBL: cape.cfdx.lineLoad.DBLineLoad

Line load data book

qtriq: True | {False}

Whether or not preprocessing is needed to create TRIQ file

ftriq: {None} | str

Name of TRIQ file (if needed)

qpbs: True | {False}

Whether or not to create a script and submit it

Versions:
  • 2016-06-07 @ddalle: First version

  • 2016-12-21 @ddalle: PBS added

UpdateCase(i, qpbs=False, seam=False)

Update one line load entry if necessary

Call:
>>> n = DBL.UpdateLineLoadCase(i, qpbs=False, seam=False)
Inputs:
DBL: cape.cfdx.lineLoad.DBLineLoad

Line load data book

i: int

Case number

qpbs: True | {False}

Whether or not to submit as a script

seam: True | {False}

Option to always read local seam curves

Outputs:
n: 0 | 1

Number of cases updated or added

Versions:
  • 2016-06-07 @ddalle: First version

  • 2016-12-19 @ddalle: Modified for generic module

  • 2016-12-21 @ddalle: Added PBS

  • 2017-04-24 @ddalle: Removed PBS and added output

  • 2021-12-01 @ddalle: Added deam

UpdateRunMatrix()

Match the trajectory to the cases in the data book

Call:
>>> DBL.UpdateRunMatrix()
Inputs:
DBL: cape.cfdx.lineLoad.DBLineLoad

Line load data book

Versions:
  • 2015-05-22 @ddalle: First version

  • 2016-08-12 @ddalle: Copied from data book

Write(fname=None, merge=False, unlock=True)

Write a single line load data book summary file

Call:
>>> DBL.Write()
>>> DBL.Write(fname, merge=False, unlock=True)
Inputs:
DBL: pycart.lineLoad.DBLineLoad

Instance of line load data book

fname: str

Name of summary file

merge: True | {False}

Whether or not to attempt a merger before writing

unlock: {True} | False

Whether or not to delete any lock files

Versions:
  • 2015-09-16 @ddalle: First version

  • 2023-05-03 @aburkhea: Added unlock and merge

WriteSeamCurves()

Write seam curves to a common data book directory

Call:
>>> DBL.WriteSeamCurves()
Inputs:
DBL: cape.cfdx.lineLoad.DBLineLoad

Line load data book

Versions:
  • 2016-06-09 @ddalle: First version

WriteTriloadInput(ftriq, i, **kw)

Write triload.i input file to triloadCmd

Call:
>>> DBL.WriteTriloadInput(ftriq, i, **kw)
Inputs:
DBL: cape.cfdx.lineLoad.DBLineLoad

Line load data book

ftriq: str

Name of the triq file to analyze

i: int

Case number

Keyword arguments:
mach: float

Override Mach number

Re: float

Override Reynolds number input

gamma: float

Override ratio of specific heats

MRP: float

Override the moment reference point from the JSON input file

Versions:
  • 2016-06-07 @ddalle: First version

  • 2017-01-11 @ddalle: Moved code to WriteTriloadInputBase

WriteTriloadInputBase(ftriq, i, **kw)

Write triload.i input file to triloadCmd

Call:
>>> DBL.WriteTriloadInput(ftriq, i, **kw)
Inputs:
DBL: cape.cfdx.lineLoad.DBLineLoad

Line load data book

ftriq: str

Name of the triq file to analyze

i: int

Case number

Keyword arguments:
mach: float

Override Mach number

Re: float

Override Reynolds number input

gamma: float

Override ratio of specific heats

MRP: float

Override the moment reference point from the JSON input file

Versions:
  • 2016-06-07 @ddalle: First version

WriteTriloadTransformations(i, f)

Write transformations to a triload.i input file

Usually this just writes an n for “no”, but it can also write a 3x3 transformation matrix if "Transformations" are defined for DBL.comp.

Call:
>>> DBL.WriteTriloadTransformations(i, f)
Inputs:
DBL: cape.cfdx.lineLoad.DBLineLoad

Line load data book

i: int

Case number

f: file

Open file handle from WriteTriloadInputBase()

Versions:
  • 2017-04-14 @ddalle: First version

cape.cfdx.lineLoad.ImportPyPlot()

Import matplotlib.pyplot if not already loaded

Call:
>>> pyCart.dataBook.ImportPyPlot()
Versions:
  • 2014-12-27 @ddalle: First version