Skip to content

Commit

Permalink
Adding DVGeometryMulti to MPhys (#230)
Browse files Browse the repository at this point in the history
* Minimal implementation to check compatibility

* Fixing pointset name call in derivative computation

* Fixing incorrect logical

* Adding sliding curves for interfaces that can be remeshed

* Updating implementation for new MPhys DVGeo wrapper

* Removing new DVGeoMulti curve tracking

* Fixing isort issues

* Fixing applyIC kwargs issue

* Fixing child FFD naming issue

* Updating kwargs for adding pointset

* Compacting if checks

* Adding docstring for nom_addComponent function

* Fixing extraneous addRefAxis call

* Fixing black failures

* Fixing addRefAxis call
  • Loading branch information
bernardopacini authored Jul 30, 2024
1 parent 3404b51 commit 3471013
Showing 1 changed file with 106 additions and 25 deletions.
131 changes: 106 additions & 25 deletions pygeo/mphys/mphys_dvgeo.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from openmdao.api import AnalysisError

# Local modules
from .. import DVConstraints, DVGeometry, DVGeometryESP, DVGeometryVSP
from .. import DVConstraints, DVGeometry, DVGeometryESP, DVGeometryMulti, DVGeometryVSP


# class that actually calls the DVGeometry methods
Expand Down Expand Up @@ -83,6 +83,9 @@ def setup(self):
elif info["type"] == "esp":
self.DVGeos.update({name: DVGeometryESP(info["file"], comm=self.comm, name=DVGeoName, **options)})

elif info["type"] == "multi":
self.DVGeos.update({name: DVGeometryMulti(comm=self.comm, **options)})

# add each geometry to the constraints object
for _, DVGeo in self.DVGeos.items():
self.DVCon.setDVGeo(DVGeo, name=DVConName)
Expand Down Expand Up @@ -125,7 +128,39 @@ def compute(self, inputs, outputs):
# next time the jacvec product routine is called
self.update_jac = True

def nom_addChild(self, ffd_file, DVGeoName=None, childName=None):
def nom_addComponent(self, comp, ffd_file, triMesh, DVGeoName=None):
"""
Add a component a DVGeometryMulti object. This is a wrapper for the DVGeoMulti.addComponent method.
Parameters
----------
comp : str
The name of the component.
ffd_file : str
Path to the FFD file for the new DVGeo object for this component.
triMesh : str, optional
Path to the triangulated mesh file for this component.
DVGeoName : str, optional
The name of the DVGeo object to add this component to.
"""

# if we have multiple DVGeos use the one specified by name
DVGeo = self.nom_getDVGeo(DVGeoName=DVGeoName)

# can only add a DVGeo to a DVGeoMulti
if not isinstance(DVGeo, DVGeometryMulti):
raise RuntimeError(
f"Only multi-based DVGeo objects can have components added to them, not type:{self.geo_type}"
)

# Add component
DVGeoComp = DVGeometry(ffd_file)
DVGeo.addComponent(comp=comp, DVGeo=DVGeoComp, triMesh=triMesh)

def nom_addChild(self, ffd_file, DVGeoName=None, childName=None, comp=None):
# if we have multiple DVGeos use the one specified by name
DVGeo = self.nom_getDVGeo(DVGeoName=DVGeoName)

Expand All @@ -137,24 +172,27 @@ def nom_addChild(self, ffd_file, DVGeoName=None, childName=None):

# Add child FFD
child_ffd = DVGeometry(ffd_file, child=True, name=childName)
DVGeo.addChild(child_ffd)

if comp is None:
DVGeo.addChild(child_ffd)
else:
DVGeo.DVGeoDict[comp].addChild(child_ffd)

# Embed points from parent if not already done
for pointSet in DVGeo.points:
if pointSet not in child_ffd.points:
child_ffd.addPointSet(DVGeo.points[pointSet], pointSet)

def nom_add_discipline_coords(self, discipline, points=None, DVGeoName=None):
def nom_add_discipline_coords(self, discipline, points=None, DVGeoName=None, **kwargs):
# TODO remove one of these methods to keep only one method to add pointsets

if points is None:
# no pointset info is provided, just do a generic i/o. We will add these points during the first compute
self.add_input("x_%s_in" % discipline, distributed=True, shape_by_conn=True)
self.add_output("x_%s0" % discipline, distributed=True, copy_shape="x_%s_in" % discipline)

else:
# we are provided with points. we can do the full initialization now
self.nom_addPointSet(points, "x_%s0" % discipline, add_output=False, DVGeoName=DVGeoName)
self.nom_addPointSet(points, "x_%s0" % discipline, add_output=False, DVGeoName=DVGeoName, **kwargs)
self.add_input("x_%s_in" % discipline, distributed=True, val=points.flatten())
self.add_output("x_%s0" % discipline, distributed=True, val=points.flatten())

Expand Down Expand Up @@ -182,18 +220,21 @@ def nom_add_point_dict(self, point_dict):
for k, v in point_dict.items():
self.nom_addPointSet(v, k)

def nom_getDVGeo(self, childName=None, DVGeoName=None):
def nom_getDVGeo(self, childName=None, comp=None, DVGeoName=None):
"""
Gets the DVGeometry object held in the geometry component so DVGeo methods can be called directly on it
Parameters
----------
DVGeoName : string, optional
The name of the DVGeo to return, necessary if there are multiple DVGeo objects
childName : str, optional
Name of the child FFD, if you want a child DVGeo returned
comp : str, optional
Name of the DVGeoMulti component, if this DV is for a multi component
DVGeoName : str, optional
The name of the DVGeo to return, necessary if there are multiple DVGeo objects
Returns
-------
DVGeometry object
Expand All @@ -205,14 +246,22 @@ def nom_getDVGeo(self, childName=None, DVGeoName=None):
else:
DVGeo = self.DVGeos["defaultDVGeo"]

# return the top level DVGeo
if childName is None:
return DVGeo
# return a child of a DVGeoMulti component
if childName is not None and comp is not None:
return DVGeo.DVGeoDict[comp].children[childName]

# return a child DVGeo
else:
# return a component of a DVGeoMulti
elif comp is not None:
return DVGeo.DVGeoDict[comp]

# return a child of a DVGeo
elif childName is not None:
return DVGeo.children[childName]

# return the top level DVGeo
else:
return DVGeo

def nom_getDVCon(self):
"""
Gets the DVConstraints object held in the geometry component so DVCon methods can be called directly on it
Expand All @@ -229,7 +278,16 @@ def nom_getDVCon(self):
"""

def nom_addGlobalDV(
self, dvName, value, func, childName=None, isComposite=False, DVGeoName=None, prependName=False, config=None
self,
dvName,
value,
func,
childName=None,
comp=None,
isComposite=False,
DVGeoName=None,
prependName=False,
config=None,
):
"""
Add a global design variable to the DVGeo object. This is a wrapper for the DVGeo.addGlobalDV method.
Expand All @@ -248,6 +306,9 @@ def nom_addGlobalDV(
childName : str, optional
Name of the child FFD, if this DV is for a child FFD.
comp : str, optional
Name of the DVGeoMulti component, if this DV is for a multi component
isComposite : bool, optional
Whether this DV is to be included in the composite DVs, by default False
Expand All @@ -261,10 +322,10 @@ def nom_addGlobalDV(
"""

# if we have multiple DVGeos use the one specified by name
DVGeo = self.nom_getDVGeo(childName=childName, DVGeoName=DVGeoName)
DVGeo = self.nom_getDVGeo(childName=childName, comp=comp, DVGeoName=DVGeoName)

# global DVs are only added to FFD-based DVGeo objects
if not isinstance(DVGeo, DVGeometry):
if not isinstance(DVGeo, (DVGeometry, DVGeometryMulti)):
raise RuntimeError(f"Only FFD-based DVGeo objects can use global DVs, not type: {type(DVGeo).__name__}")

# if this DVGeo object has a name attribute, prepend it to match up with what DVGeo is expecting
Expand All @@ -287,17 +348,18 @@ def nom_addLocalDV(
axis="y",
pointSelect=None,
childName=None,
comp=None,
isComposite=False,
DVGeoName=None,
prependName=False,
volList=None,
config=None,
):
# if we have multiple DVGeos use the one specified by name
DVGeo = self.nom_getDVGeo(childName=childName, DVGeoName=DVGeoName)
DVGeo = self.nom_getDVGeo(childName=childName, comp=comp, DVGeoName=DVGeoName)

# local DVs are only added to FFD-based DVGeo objects
if not isinstance(DVGeo, DVGeometry):
if not isinstance(DVGeo, (DVGeometry, DVGeometryMulti)):
raise RuntimeError(f"Only FFD-based DVGeo objects can use local DVs, not type: {type(DVGeo).__name__}")

# if this DVGeo object has a name attribute, prepend it to match up with what DVGeo is expecting
Expand All @@ -322,6 +384,7 @@ def nom_addLocalSectionDV(
dvName,
secIndex,
childName=None,
comp=None,
axis=1,
pointSelect=None,
volList=None,
Expand All @@ -347,6 +410,9 @@ def nom_addLocalSectionDV(
childName : str, optional
Name of the child FFD, if this DV is for a child FFD.
comp : str, optional
Name of the DVGeoMulti component, if this DV is for a multi component
axis : int, optional
See wrapped
Expand Down Expand Up @@ -383,7 +449,7 @@ def nom_addLocalSectionDV(
DVGeo = self.nom_getDVGeo(childName=childName, DVGeoName=DVGeoName)

# local DVs are only added to FFD-based DVGeo objects
if not isinstance(DVGeo, DVGeometry):
if not isinstance(DVGeo, (DVGeometry, DVGeometryMulti)):
raise RuntimeError(
f"Only FFD-based DVGeo objects can use local section DVs, not type: {type(DVGeo).__name__}"
)
Expand All @@ -402,7 +468,9 @@ def nom_addLocalSectionDV(
self.add_input(dvName, distributed=False, shape=nVal)
return nVal

def nom_addShapeFunctionDV(self, dvName, shapes, childName=None, config=None, DVGeoName=None, prependName=False):
def nom_addShapeFunctionDV(
self, dvName, shapes, childName=None, comp=None, config=None, DVGeoName=None, prependName=False
):
"""
Add one or more local shape function design variables to the DVGeometry object
Wrapper for :meth:`addShapeFunctionDV <.DVGeometry.addShapeFunctionDV>`
Expand All @@ -419,6 +487,9 @@ def nom_addShapeFunctionDV(self, dvName, shapes, childName=None, config=None, DV
childName : str, optional
Name of the child FFD, if this DV is for a child FFD.
comp : str, optional
Name of the DVGeoMulti component, if this DV is for a multi component
config : str or list, optional
See wrapped
Expand Down Expand Up @@ -522,6 +593,7 @@ def nom_addRefAxis(
self,
name,
childName=None,
comp=None,
DVGeoName=None,
curve=None,
xFraction=None,
Expand All @@ -542,10 +614,10 @@ def nom_addRefAxis(
# But doing this may create backward incompatibility. So we will use `volumes` for now

# if we have multiple DVGeos use the one specified by name
DVGeo = self.nom_getDVGeo(childName=childName, DVGeoName=DVGeoName)
DVGeo = self.nom_getDVGeo(childName=childName, comp=comp, DVGeoName=DVGeoName)

# references axes are only needed in FFD-based DVGeo objects
if not isinstance(DVGeo, DVGeometry):
if not isinstance(DVGeo, (DVGeometry, DVGeometryMulti)):
raise RuntimeError(f"Only FFD-based DVGeo objects can use reference axes, not type: {type(DVGeo).__name__}")

# add ref axis to this DVGeo
Expand Down Expand Up @@ -914,7 +986,16 @@ def compute_jacvec_product(self, inputs, d_inputs, d_outputs, mode):
d_inputs[dvname] += jvtmp

for _, DVGeo in self.DVGeos.items():
for ptSetName in DVGeo.ptSetNames:
if isinstance(DVGeo, DVGeometryMulti):
ptSetNames = []
for comp in DVGeo.DVGeoDict.keys():
for ptSet in DVGeo.DVGeoDict[comp].ptSetNames:
if ptSet not in ptSetNames:
ptSetNames.append(ptSet)
else:
ptSetNames = DVGeo.ptSetNames

for ptSetName in ptSetNames:
if ptSetName in self.omPtSetList:
dout = d_outputs[ptSetName].reshape(len(d_outputs[ptSetName]) // 3, 3)

Expand Down

0 comments on commit 3471013

Please sign in to comment.