Skip to content

Commit 3471013

Browse files
Adding DVGeometryMulti to MPhys (#230)
* 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
1 parent 3404b51 commit 3471013

1 file changed

Lines changed: 106 additions & 25 deletions

File tree

pygeo/mphys/mphys_dvgeo.py

Lines changed: 106 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
from openmdao.api import AnalysisError
66

77
# Local modules
8-
from .. import DVConstraints, DVGeometry, DVGeometryESP, DVGeometryVSP
8+
from .. import DVConstraints, DVGeometry, DVGeometryESP, DVGeometryMulti, DVGeometryVSP
99

1010

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

86+
elif info["type"] == "multi":
87+
self.DVGeos.update({name: DVGeometryMulti(comm=self.comm, **options)})
88+
8689
# add each geometry to the constraints object
8790
for _, DVGeo in self.DVGeos.items():
8891
self.DVCon.setDVGeo(DVGeo, name=DVConName)
@@ -125,7 +128,39 @@ def compute(self, inputs, outputs):
125128
# next time the jacvec product routine is called
126129
self.update_jac = True
127130

128-
def nom_addChild(self, ffd_file, DVGeoName=None, childName=None):
131+
def nom_addComponent(self, comp, ffd_file, triMesh, DVGeoName=None):
132+
"""
133+
Add a component a DVGeometryMulti object. This is a wrapper for the DVGeoMulti.addComponent method.
134+
135+
Parameters
136+
----------
137+
comp : str
138+
The name of the component.
139+
140+
ffd_file : str
141+
Path to the FFD file for the new DVGeo object for this component.
142+
143+
triMesh : str, optional
144+
Path to the triangulated mesh file for this component.
145+
146+
DVGeoName : str, optional
147+
The name of the DVGeo object to add this component to.
148+
"""
149+
150+
# if we have multiple DVGeos use the one specified by name
151+
DVGeo = self.nom_getDVGeo(DVGeoName=DVGeoName)
152+
153+
# can only add a DVGeo to a DVGeoMulti
154+
if not isinstance(DVGeo, DVGeometryMulti):
155+
raise RuntimeError(
156+
f"Only multi-based DVGeo objects can have components added to them, not type:{self.geo_type}"
157+
)
158+
159+
# Add component
160+
DVGeoComp = DVGeometry(ffd_file)
161+
DVGeo.addComponent(comp=comp, DVGeo=DVGeoComp, triMesh=triMesh)
162+
163+
def nom_addChild(self, ffd_file, DVGeoName=None, childName=None, comp=None):
129164
# if we have multiple DVGeos use the one specified by name
130165
DVGeo = self.nom_getDVGeo(DVGeoName=DVGeoName)
131166

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

138173
# Add child FFD
139174
child_ffd = DVGeometry(ffd_file, child=True, name=childName)
140-
DVGeo.addChild(child_ffd)
175+
176+
if comp is None:
177+
DVGeo.addChild(child_ffd)
178+
else:
179+
DVGeo.DVGeoDict[comp].addChild(child_ffd)
141180

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

147-
def nom_add_discipline_coords(self, discipline, points=None, DVGeoName=None):
186+
def nom_add_discipline_coords(self, discipline, points=None, DVGeoName=None, **kwargs):
148187
# TODO remove one of these methods to keep only one method to add pointsets
149-
150188
if points is None:
151189
# no pointset info is provided, just do a generic i/o. We will add these points during the first compute
152190
self.add_input("x_%s_in" % discipline, distributed=True, shape_by_conn=True)
153191
self.add_output("x_%s0" % discipline, distributed=True, copy_shape="x_%s_in" % discipline)
154192

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

@@ -182,18 +220,21 @@ def nom_add_point_dict(self, point_dict):
182220
for k, v in point_dict.items():
183221
self.nom_addPointSet(v, k)
184222

185-
def nom_getDVGeo(self, childName=None, DVGeoName=None):
223+
def nom_getDVGeo(self, childName=None, comp=None, DVGeoName=None):
186224
"""
187225
Gets the DVGeometry object held in the geometry component so DVGeo methods can be called directly on it
188226
189227
Parameters
190228
----------
191-
DVGeoName : string, optional
192-
The name of the DVGeo to return, necessary if there are multiple DVGeo objects
193-
194229
childName : str, optional
195230
Name of the child FFD, if you want a child DVGeo returned
196231
232+
comp : str, optional
233+
Name of the DVGeoMulti component, if this DV is for a multi component
234+
235+
DVGeoName : str, optional
236+
The name of the DVGeo to return, necessary if there are multiple DVGeo objects
237+
197238
Returns
198239
-------
199240
DVGeometry object
@@ -205,14 +246,22 @@ def nom_getDVGeo(self, childName=None, DVGeoName=None):
205246
else:
206247
DVGeo = self.DVGeos["defaultDVGeo"]
207248

208-
# return the top level DVGeo
209-
if childName is None:
210-
return DVGeo
249+
# return a child of a DVGeoMulti component
250+
if childName is not None and comp is not None:
251+
return DVGeo.DVGeoDict[comp].children[childName]
211252

212-
# return a child DVGeo
213-
else:
253+
# return a component of a DVGeoMulti
254+
elif comp is not None:
255+
return DVGeo.DVGeoDict[comp]
256+
257+
# return a child of a DVGeo
258+
elif childName is not None:
214259
return DVGeo.children[childName]
215260

261+
# return the top level DVGeo
262+
else:
263+
return DVGeo
264+
216265
def nom_getDVCon(self):
217266
"""
218267
Gets the DVConstraints object held in the geometry component so DVCon methods can be called directly on it
@@ -229,7 +278,16 @@ def nom_getDVCon(self):
229278
"""
230279

231280
def nom_addGlobalDV(
232-
self, dvName, value, func, childName=None, isComposite=False, DVGeoName=None, prependName=False, config=None
281+
self,
282+
dvName,
283+
value,
284+
func,
285+
childName=None,
286+
comp=None,
287+
isComposite=False,
288+
DVGeoName=None,
289+
prependName=False,
290+
config=None,
233291
):
234292
"""
235293
Add a global design variable to the DVGeo object. This is a wrapper for the DVGeo.addGlobalDV method.
@@ -248,6 +306,9 @@ def nom_addGlobalDV(
248306
childName : str, optional
249307
Name of the child FFD, if this DV is for a child FFD.
250308
309+
comp : str, optional
310+
Name of the DVGeoMulti component, if this DV is for a multi component
311+
251312
isComposite : bool, optional
252313
Whether this DV is to be included in the composite DVs, by default False
253314
@@ -261,10 +322,10 @@ def nom_addGlobalDV(
261322
"""
262323

263324
# if we have multiple DVGeos use the one specified by name
264-
DVGeo = self.nom_getDVGeo(childName=childName, DVGeoName=DVGeoName)
325+
DVGeo = self.nom_getDVGeo(childName=childName, comp=comp, DVGeoName=DVGeoName)
265326

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

270331
# if this DVGeo object has a name attribute, prepend it to match up with what DVGeo is expecting
@@ -287,17 +348,18 @@ def nom_addLocalDV(
287348
axis="y",
288349
pointSelect=None,
289350
childName=None,
351+
comp=None,
290352
isComposite=False,
291353
DVGeoName=None,
292354
prependName=False,
293355
volList=None,
294356
config=None,
295357
):
296358
# if we have multiple DVGeos use the one specified by name
297-
DVGeo = self.nom_getDVGeo(childName=childName, DVGeoName=DVGeoName)
359+
DVGeo = self.nom_getDVGeo(childName=childName, comp=comp, DVGeoName=DVGeoName)
298360

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

303365
# if this DVGeo object has a name attribute, prepend it to match up with what DVGeo is expecting
@@ -322,6 +384,7 @@ def nom_addLocalSectionDV(
322384
dvName,
323385
secIndex,
324386
childName=None,
387+
comp=None,
325388
axis=1,
326389
pointSelect=None,
327390
volList=None,
@@ -347,6 +410,9 @@ def nom_addLocalSectionDV(
347410
childName : str, optional
348411
Name of the child FFD, if this DV is for a child FFD.
349412
413+
comp : str, optional
414+
Name of the DVGeoMulti component, if this DV is for a multi component
415+
350416
axis : int, optional
351417
See wrapped
352418
@@ -383,7 +449,7 @@ def nom_addLocalSectionDV(
383449
DVGeo = self.nom_getDVGeo(childName=childName, DVGeoName=DVGeoName)
384450

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

405-
def nom_addShapeFunctionDV(self, dvName, shapes, childName=None, config=None, DVGeoName=None, prependName=False):
471+
def nom_addShapeFunctionDV(
472+
self, dvName, shapes, childName=None, comp=None, config=None, DVGeoName=None, prependName=False
473+
):
406474
"""
407475
Add one or more local shape function design variables to the DVGeometry object
408476
Wrapper for :meth:`addShapeFunctionDV <.DVGeometry.addShapeFunctionDV>`
@@ -419,6 +487,9 @@ def nom_addShapeFunctionDV(self, dvName, shapes, childName=None, config=None, DV
419487
childName : str, optional
420488
Name of the child FFD, if this DV is for a child FFD.
421489
490+
comp : str, optional
491+
Name of the DVGeoMulti component, if this DV is for a multi component
492+
422493
config : str or list, optional
423494
See wrapped
424495
@@ -522,6 +593,7 @@ def nom_addRefAxis(
522593
self,
523594
name,
524595
childName=None,
596+
comp=None,
525597
DVGeoName=None,
526598
curve=None,
527599
xFraction=None,
@@ -542,10 +614,10 @@ def nom_addRefAxis(
542614
# But doing this may create backward incompatibility. So we will use `volumes` for now
543615

544616
# if we have multiple DVGeos use the one specified by name
545-
DVGeo = self.nom_getDVGeo(childName=childName, DVGeoName=DVGeoName)
617+
DVGeo = self.nom_getDVGeo(childName=childName, comp=comp, DVGeoName=DVGeoName)
546618

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

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

916988
for _, DVGeo in self.DVGeos.items():
917-
for ptSetName in DVGeo.ptSetNames:
989+
if isinstance(DVGeo, DVGeometryMulti):
990+
ptSetNames = []
991+
for comp in DVGeo.DVGeoDict.keys():
992+
for ptSet in DVGeo.DVGeoDict[comp].ptSetNames:
993+
if ptSet not in ptSetNames:
994+
ptSetNames.append(ptSet)
995+
else:
996+
ptSetNames = DVGeo.ptSetNames
997+
998+
for ptSetName in ptSetNames:
918999
if ptSetName in self.omPtSetList:
9191000
dout = d_outputs[ptSetName].reshape(len(d_outputs[ptSetName]) // 3, 3)
9201001

0 commit comments

Comments
 (0)