cape.config: Surface configuration module

This is a module to interact with Cart3D’s Config.xml or similar files whose primary purpose is to describe and label surface geometry. In general, it can be used to create groups of surfaces using an XML, JSON, or MIXSUR file format. This originates from a Cart3D/OVERFLOW convention, but it can be used with other modules as well. Presently there are three classes, which each interface with a specific type of file:

Class

Common File

Description

ConfigXML

Config.xml

GMP component XML file

ConfigJSON

Config.json

Cape JSON surf config file

ConfigMIXSUR

mixsur.i

CGT input families stream

It is typical for a surface definition, whether a triangulation, system of overset structured grids, or mixed quads and triangles, to have each surface polygon to have a numbered component ID. This allows a user to group triangles and quads or other polygons together in some relevant way. For example, the user may tag each polygon on the left wing with the component ID of 12, and the entire surface is broken out in a similar fashion.

The cape.config module allows the user to do two main things: give meaningful names to these component IDs and group component IDs together. For example, it is usually much more convenient to refer to "left_wing" than remember to put "12" in all the data books, reports, etc. In addition, a user usually wants to know the integrated force on the entire airplane (or whatever other type of configuration is under investigation), so it is useful to make another component called "vehicle" that contains "left_wing", "right_wing", and "fuselage". The user specifies this in the XML file using the following syntax.

<?xml version="1.0" encoding="ISO-8859-1"?>
<Configuration Name="airplane" Source="Components.i.tri">

<Component Name="vehicle" Type="container">
</Component>

<Component Name="fuselage" Type="tri">
<Data> Face Label=1 </Data> </Component>

<Component Name="right_wing" Type="tri">
<Data> Face Label=11 </Data> </Component>

<Component Name="left_wing" Type="tri">
<Data> Face Label=12 </Data> </Component>

</Configuration>

The Source attribute of the first tag is not that important; it’s placed there based on a Cart3D template. The choice of encoding is not crucial but does affect the validity of the XML file, which some applications may check.

The major limitation of the XML format is that a component may not have multiple parents. A parent may have parent, allowing the user to subdivide groups into smaller groups, but the user may not, for example, split the vehicle into left half and right half and also create components for forward half and aft half.

An alternative version of the same is to use the JSON configuration format developed for Cape. It allows mixed parents like the forward/aft, left/right example described above, and it also allows the users to specify boundary conditions within the config file, which can consolidate information about your surface that would otherwise require multiple files. The version of the above configuration in JSON form is below.

{
    "Tree": {
        "vehicle": [
            "fuselage",
            "right_wing",
            "left_wing"
        ]
    },
    "Properties": {
        "fuselage": {
            "CompID": 1
        },
        "right_wing": 11,
        "left_wing": 12
    }
}

The "Properties" section allows generic options, for example those in the table below. If the Properties for a face is not a dict, it must be an int, which is assumed to be the CompID parameter for that face.

Component Property

Description

CompID

Surface component integer

Parent

Name of principal parent if ambiguous

fun3d_bc

Boundary condition for FUN3D

aflr3_bc

Boundary condition for AFLR3

blds

Initial BL spacing, AFLR3

bldel

Prism layer height, AFLR3

Finally, the ConfigMIXSUR file interprets the streams that are often given as inputs to the Chimera Grid Tools executables mixsur or usurp. These functions are used to divide an overset structured grid system into surface components and can also be used to create unique surface triangulations. These input streams are often saved as a file, by convention mixsur.i, and read into the CGT executable using a call such as mixsur < mixsur.i.

class cape.config.ConfigJSON(fname='Config.json')

JSON-based surface configuration interface

Call:
>>> cfg = ConfigJSON(fname="Config.json")
Inputs:
fname: {"Config.json"} | str

Name of JSON file from which to read tree and properties

Outputs:
cfg: cape.config.ConfigJSON

JSON-based configuration interface

Attributes:
cfg.faces: dict[list | int]

Dict of the component ID or IDs in each named face

cfg.comps: list[str]

List of components with no children

cfg.parents: dict[list[str]]

List of parent(s) by name for each component

cfg.IDs: list[int]

List of unique component ID numbers

cfg.name: None | str

Optional string to identify what is being represented

Versions:
  • 2016-10-21 @ddalle: Version 1.0

AppendChild(c, parent=None)

Process one component of the tree and recurse

Call:
>>> compID = cfg.AppendChild(c, parent=None)
Inputs:
cfg: cape.config.ConfigJSON

JSON-based configuration interface

c: str

Name of component in “Tree” section

parent: {None} | str

Name of parent component when called recursively

Outputs:
compID: list[int]

Full list of component IDs in c and its children

Versions:
  • 2016-10-21 @ddalle: Version 1.0

Copy()

Copy a configuration interface

Call:
>>> cfg2 = cfg.Copy()
Inputs:
cfg: cape.config.ConfigXML

XML surface config instance

Outputs:
cfg2: cape.config.ConfigXML

Copy of input

Versions:
  • 2014-11-24 @ddalle: Version 1.0

GetCompID(face)

Return a list of component IDs from generic input

Call:
>>> compID = cfg.GetCompID(face)
Inputs:
cfg: cape.config.ConfigJSON

XML surface config instance

face: str | int | list

Component number, name, or list thereof

Outputs:
compID: list[int]

List of component IDs

Versions:
  • 2014-10-12 @ddalle: Version 1.0 (ConfigXML)

  • 2016-10-21 @ddalle: Version 1.0

GetCompName(compID)

Get the name of a component by its number

Call:
>>> face = cfg.GetCompName(compID)
Inputs:
cfg: cape.config.ConfigXML

XML surface config instance

compID: int

Component ID number

Outputs:
face: None | str

Name of so-numbered component, if any

Versions:
  • 2017-03-30 @ddalle: Version 1.0

GetPropCompID(comp)

Get a CompID from the “Properties” section

Call:
>>> compID = cfg.GetPropCompID(comp)
Inputs:
cfg: cape.config.ConfigJSON

JSON-based configuration interface

c: str

Name of component in “Tree” section

Outputs:
compID: int

Full list of component IDs in c and its children

Versions:
  • 2016-10-21 @ddalle: Version 1.0

GetProperty(comp, k, name=None, vdef=None)

Get a cascading property from a component or its parents

Call:
>>> v = cfg.GetProperty(comp, k, name=None, vdef=None)
Inputs:
cfg: cape.config.ConfigJSON

JSON-based configuration interface

comp: str

Name of component to query

k: str

Name of property to query

name: {None} | str

Name to filter if k has multiple values; defaults to cfg.name if applicable

vdef: {None} | any

Default value

Outputs:
v: vdef | any

Value of k from comp with fallback to parents

Versions:
  • 2016-10-21 @ddalle: Version 1.0

  • 2022-03-15 @ddalle: Version 2.0; add name

  • 2022-04-14 @ddalle: Version 2.1; add vdef

GetTriFaces()

Get names of faces that are of type “tri” (not containers)

Call:
>>> comps = cfg.GetTriFaces()
Inputs:
cfg: cape.config.ConfigJSON

JSON-based configuration instance

Outputs:
comps: list[str]

List of lowest-level component names

Versions:
  • 2016-11-07 @ddalle: Version 1.0

RenumberCompID(face, compID)

Renumber the component ID number

This affects cfg.faces for face and each of its parents, and it also resets the component ID number in cfg.props.

Call:
>>> cfg.RenumberCompID(face, compID)
Inputs:
cfg: cape.config.ConfigJSON

JSON-based configuration

face: str

Name of component to rename

Versions:
  • 2016-11-09 @ddalle: Version 1.0

RenumberCompIDParent(face, compi, compo)

Recursively renumber the parents of face

Call:
>>> cfg.RenumberCompIDParent(face, compi, compo)
Inputs:
cfg: cape.config.ConfigJSON

JSON-based configuration

face: str

Name of component whose parents should be renumbered

compi: int

Incoming component ID number

compo: int

Outgoing component ID number

Versions:
  • 2016-11-09 @ddalle: Version 1.0

ResetCompIDs()

Renumber component IDs 1 to n

Call:
>>> comps = cfg.ResetCompIDs()
Inputs:
cfg: cape.config.ConfigJSON

JSON-based configuration instance

Versions:
  • 2016-11-09 @ddalle: Version 1.0

RestrictCompID(compIDs)

Restrict component IDs in cfg.faces to manual list

Call:
>>> cfg.RestrictCompID(compIDs)
Inputs:
cfg: cape.config.ConfigJSON

JSON-based configuration interface

compIDs: list[int]

List of relevant component IDs

Versions:
  • 2016-11-05 @ddalle: Version 1.0

SortCompIDs()

Get ordered list of components

Call:
>>> comps = cfg.SortCompIDs()
Inputs:
cfg: cape.config.ConfigJSON

JSON-based configuration instance

Outputs:
comps: list[str]

List of components

Versions:
  • 2016-11-09 @ddalle: Version 1.0

WriteAFLR3BC(fname)

Write a file that list AFLR3 boundary conditions for components

Call:
>>> cfg.WriteAFLR3BC(fname)
Inputs:
cfg: cape.config.ConfigJSON

JSON-based configuration instance

fname: str

Name of AFLR3 boundary condition file to write

Versions:
  • 2017-05-05 @ddalle: Version 1.0

WriteFun3DMapBC(fname)

Write a Fun3D “.mapbc” file

Call:
>>> cfg.WriteFun3DMapBC(fname)
Inputs:
cfg: cape.config.ConfigJSON

JSON-based configuration instance

fname: str

Name of mapbc file to write

Versions:
  • 2016-11-07 @ddalle: Version 1.0

WriteXML(fname='Config.xml', name=None, source=None)

Write a GMP-type Config.xml file

Call:
>>> cfg.WriteXML(fname="Config.xml", name=None, source=None)
Inputs:
cfg: cape.config.ConfigJSON

JSON-based configuration instance

fname: {"Config.xml"} | str

Name of file to write

name: {None} | str

Name of the configuration, defaults to cfg.name

source: {"Components.i.tri"} | str

Name of the “source” tri file, has no effect

Versions:
  • 2016-11-06 @ddalle: Version 1.0

class cape.config.ConfigMIXSUR(fname='mixsur.i', usurp=True)

Class to build a surf configuration from a mixsur file

Call:
>>> cfg = ConfigMIXSUR(fname="mixsur.i", usurp=True)
Inptus:
fname: {"mixsur.i"} | str

Name of mixsur input file

usurp: {True} | False

Whether or not to number components as with usurp output

Outputs:
cfg: cape.config.ConfigMIXSUR

mixsur-based configuration interface

Attributes:
cfg.faces: dict (list | int)

Dict of component ID or IDs in each named face

cfg.comps: list (str)

List of components with no children

cfg.parents: dict (list (str))

List of parent(s) by name for each component

cfg.IDs: list[int]

List of unique component ID numbers

Versions:
  • 2016-12-29 @ddalle: Version 1.0

Copy()

Copy a configuration interface

Call:
>>> cfg2 = cfg.Copy()
Inputs:
cfg: cape.config.ConfigXML

XML surface config instance

Outputs:
cfg2: cape.config.ConfigXML

Copy of input

Versions:
  • 2014-11-24 @ddalle: Version 1.0

FindParents(face)

Find the parents of a single face

Call:
>>> cfg.FindParents(face)
Inputs:
cfg: cape.config.ConfigMIXSUR

Configuration interface for mixsur triangulations

face: str

Name of face to check

Versions:
  • 2016-12-29 @ddalle: Version 1.0

GetCompID(face)

Return a list of component IDs from generic input

Call:
>>> compID = cfg.GetCompID(face)
Inputs:
cfg: cape.config.ConfigMIXSUR

XML surface config instance

face: str | int | list

Component number, name, or list thereof

Outputs:
compID: list[int]

List of component IDs

Versions:
  • 2014-10-12 @ddalle: Version 1.0 (ConfigXML)

  • 2016-12-29 @ddalle: Version 1.0

GetCompName(compID)

Get the name of a component by its number

Call:
>>> face = cfg.GetCompName(compID)
Inputs:
cfg: cape.config.ConfigXML

XML surface config instance

compID: int

Component ID number

Outputs:
face: None | str

Name of so-numbered component, if any

Versions:
  • 2017-03-30 @ddalle: Version 1.0

readline(f=None, n=100)

Read a non-blank line from a CGT-like input file

Call:
>>> V = cfg.readline(f=None, n=100)
Inputs:
cfg: cape.config.ConfigMIXSUR

Configuration interface for mixsur

f: {None} | file

File handle; defaults to cfg.f

n: {100} | int > 0

Maximum number of lines to check

Outputs:
V: list (str)

List of substrings split by commas or spaces

Versions:
  • 2016-12-29 @ddalle: Version 1.0

class cape.config.ConfigXML(fname='Config.xml')

Interface to Cart3D Config.xml files

Call:
>>> cfg = ConfigXML(fname='Config.xml')
>>> cfg = ConfigXML(fp)
Inputs:
fname: str

Name of configuration file to read

fp: io.IOBase

Readable stream of text or file

Outputs:
cfg: cape.config.ConfigXML

XML surface config instance

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

  • 2023-07-28 @ddalle: v1.1; allow fp input

AppendParent(c, compID)

Append a component ID to a parent container and its parents

Call:
>>> cfg.AppendParent(c, compID)
Inputs:
cfg: cape.config.ConfigXML

XML surface config instance

c: xml.Element

XML interface to element with tag 'Component'

compID: int

Component ID number to add to parents’ lists

Outputs:
comp: dict

Dictionary with compID appended in appropriate places

Versions:
  • 2014-10-13 @ddalle: Version 1.0

Copy()

Copy a configuration interface

Call:
>>> cfg2 = cfg.Copy()
Inputs:
cfg: cape.config.ConfigXML

XML surface config instance

Outputs:
cfg2: cape.config.ConfigXML

Copy of input

Versions:
  • 2014-11-24 @ddalle: Version 1.0

GetCompID(face)

Return a list of component IDs from generic input

Call:
>>> compID = cfg.GetCompID(face)
Inputs:
cfg: cape.config.ConfigXML

XML surface config instance

face: str | int | list

Component number, name, or list thereof

Outputs:
compID: list[int]

List of component IDs

Versions:
  • 2014-10-12 @ddalle: Version 1.0

GetCompName(compID)

Get the name of a component by its number

Call:
>>> face = cfg.GetCompName(compID)
Inputs:
cfg: cape.config.ConfigXML

XML surface config instance

compID: int

Component ID number

Outputs:
face: None | str

Name of so-numbered component, if any

Versions:
  • 2017-03-30 @ddalle: Version 1.0

GetPropCompID(comp)

Get a CompID from the “Properties” section w/o recursion

Call:
>>> compID = cfg.GetPropCompID(comp)
Inputs:
cfg: cape.config.ConfigXML

XML-based configuration interface

comp: str

Name of component

Outputs:
compID: int

Full list of component IDs in c and its children

Versions:
  • 2016-10-21 @ddalle: Version 1.0

ProcessStruc(c)

Process a GMP component of type 'struc'

Call:
>>> cfg.ProcessStruc(c)
Inputs:
cfg: cape.config.ConfigXML

XML surface config instance

c: xml.Element

XML interface to element with tag "Component"

Versions:
  • 2016-08-23 @ddalle: Version 1.0

  • 2021-09-30 @ddalle: Version 1.1
    • Element.getchildren() removed in Python 3.9

    • c is iterable

ProcessStrucData(comp, d)

Process a GMP data element with text for “Grid List”

Call:
>>> compID = cfg.ProcessStrucData(comp, d)
Inputs:
cfg: cape.config.ConfigXML

XML surface config instance

d: xml.Element

XML interface to element with tag 'Data'

Outputs:
compID: list[int]

Grid numbers “Grid List”

Attributes:
cfg.faces[comp]: list[int]

Gets set to compID

Versions:
  • 2016-08-23 @ddalle: Version 1.0

ProcessTransform(comp, t)

Process a GMP transformation

Call:
>>> cfg.ProcessTransform(t)
Inputs:
cfg: cape.config.ConfigXML

XML surface config instance

t: xml.Element

XML interface to element with tag 'Transform'

Versions:
  • 2016-08-23 @ddalle: Version 1.0

  • 2021-09-30 @ddalle: Version 1.1; iterate t directly

ProcessTri(c)

Process a GMP component of type "tri"

Call:
>>> cfg.ProcessTri(c)
Inputs:
cfg: cape.config.ConfigXML

XML surface config instance

c: xml.Element

XML interface to element with tag "Component"

Versions:
  • 2016-08-23 @ddalle: Version 1.0

  • 2021-09-30 @ddalle: Version 1.1
    • Element.getchildren() removed in Python 3.9

    • c is iterable

ProcessTriData(comp, d)

Process a GMP data element with text for “Face Label”

Call:
>>> compID = cfg.ProcessTriData(comp, d)
Inputs:
cfg: cape.config.ConfigXML

XML surface config instance

d: xml.Element

XML interface to element with tag 'Data'

Outputs:
compID: int

Component ID number from “Face Label”

Attributes:
cfg.faces[comp]: int

Gets set to compID

Versions:
  • 2016-08-23 @ddalle: Version 1.0

RestrictCompID(compIDs)

Restrict component IDs in cfg.faces to manual list

Call:
>>> cfg.RestrictCompID(compIDs)
Inputs:
cfg: cape.config.ConfigXML

XML-based configuration interface

compIDs: list[int]

List of relevant component IDs

Versions:
  • 2016-11-05 @ddalle: Version 1.0

SetRotation(comp, i=None, **kw)

Modify or add a rotation for component comp

Call:
>>> cfg.SetRotation(comp, i=None, **kw)
Inputs:
cfg: cape.config.ConfigXML

XML surface config instance

comp: str

Name of component

i: {None} | int

Index of the rotation

Center: {[0.0,0.0,0.0]} | list | str

Point about which to rotate

Axis: {[0.0, 1.0, 0.0]} | list | str

Axis about which to rotate

Angle: {0.0} | float | str

Angle for rotation

Frame: {"Body"} | None

Rotation type, body frame or Overflow frame

Versions:
  • 2016-08-23 @ddalle: Version 1.0

SetTranslation(comp, i=None, **kw)

Modify or add a translation for component comp

Call:
>>> cfg.SetTranslation(comp, i=0, **kw)
Inputs:
cfg: cape.config.ConfigXML

XML surface config instance

comp: str

Name of component

i: {0} | int

Index of the rotation

Displacement: list | str

Vector to move component

Versions:
  • 2016-08-23 @ddalle: Version 1.0

Write(fname=None)

Write the configuration to file

Call:
>>> cfg.Write(fname=None)
Inputs:
cfg: cape.config.ConfigXML

XML surface config instance

fname: {None} | str

Name of file to write

Versions:
  • 2016-08-23 @ddalle: Version 1.0

WriteComponent(f, comp)

Write a “Component” element to file

Data (either “Face Label” or “Grid List”) is written, and any transformations are also written.

Call:
>>> cfg.WriteComponent(f, comp)
Inputs:
cfg: cape.config.ConfigXML

XML surface config instance

f: file

File handle open for writing

comp: str

Name of component to write

Versions:
  • 2016-08-23 @ddalle: Version 1.0

  • 2017-08-25 @ddalle: Version 1.1, skip negative IDs

WriteComponentData(f, comp, label=None)

Write a “Data” element to file

Call:
>>> cfg.WriteComponentData(f, comp, label=None)
Inputs:
cfg: cape.config.ConfigXML

XML surface config instance

comp: str

Name of component to write

label: {None} | "Face Label" | "Grid List"

Label used to specify data

Versions:
  • 2016-08-23 @ddalle: Version 1.0

WriteComponentTransform(f, comp)

Write a “Transform” element to file

Call:
>>> cfg.WriteComponentData(f, comp, label=None)
Inputs:
cfg: cape.config.ConfigXML

XML surface config instance

comp: str

Name of component to write

label: {None} | "Face Label" | "Grid List"

Label used to specify data

Versions:
  • 2016-08-23 @ddalle: Version 1.0

WriteXML(fname=None, name=None)

Write the configuration to file

Call:
>>> cfg.WriteXML(fname=None)
Inputs:
cfg: cape.config.ConfigXML

XML surface config instance

fname: {None} | str

Name of file to write

Versions:
  • 2016-08-23 @ddalle: Version 1.0