From 7a5905882e7431379699f2b0f71eec8d3870808a Mon Sep 17 00:00:00 2001 From: Bernardo Pacini Date: Mon, 26 Jun 2023 14:41:31 -0400 Subject: [PATCH 01/15] Minimal implementation to check compatibility --- pygeo/mphys/mphys_dvgeo.py | 99 +++++++++++++++++++++++++++----------- 1 file changed, 71 insertions(+), 28 deletions(-) diff --git a/pygeo/mphys/mphys_dvgeo.py b/pygeo/mphys/mphys_dvgeo.py index 312b555e..242bae87 100644 --- a/pygeo/mphys/mphys_dvgeo.py +++ b/pygeo/mphys/mphys_dvgeo.py @@ -5,7 +5,7 @@ from openmdao.api import AnalysisError # Local modules -from .. import DVConstraints, DVGeometry, DVGeometryESP, DVGeometryVSP +from .. import DVConstraints, DVGeometry, DVGeometryESP, DVGeometryVSP, DVGeometryMulti # class that actually calls the dvgeometry methods @@ -46,6 +46,10 @@ def setup(self): self.DVGeo = DVGeometryESP(self.options["file"], comm=self.comm, **esp_options) + elif self.geo_type == "multi": + # we are doing a multi-DVGeo-based DVGeo + self.DVGeo = DVGeometryMulti() + self.DVCon = DVConstraints() self.DVCon.setDVGeo(self.DVGeo) self.omPtSetList = [] @@ -100,7 +104,26 @@ def nom_addChild(self, ffd_file): if pointSet not in self.DVGeo.children[-1].points: self.DVGeo.children[-1].addPointSet(self.DVGeo.points[pointSet], pointSet) - def nom_add_discipline_coords(self, discipline, points=None): + def nom_addComponent(self, comp, ffd_file, triMesh, scale=1.0): + if self.geo_type != "multi": + raise RuntimeError( + f"Only multi-based DVGeo objects can have components added to them, not type:{self.geo_type}" + ) + + # Add component + DVGeo = DVGeometry(ffd_file) + self.DVGeo.addComponent(comp=comp, DVGeo=DVGeo, triMesh=triMesh, scale=scale) + + def nom_addIntersection(self, compA, compB, dStarA, dStarB, featureCurves, project, includeCurves, curveEpsDict, anisotropy):#, trackSurfaces): + if self.geo_type != "multi": + raise RuntimeError( + f"Only multi-based DVGeo objects can have intersections added to them, not type:{self.geo_type}" + ) + + # Add intersection + self.DVGeo.addIntersection(compA=compA, compB=compB, dStarA=dStarA, dStarB=dStarB, featureCurves=featureCurves, project=project, includeCurves=includeCurves, curveEpsDict=curveEpsDict, anisotropy=anisotropy)#, trackSurfaces=trackSurfaces) + + def nom_add_discipline_coords(self, discipline, points=None, applyIC=False): # TODO remove one of these methods to keep only one method to add pointsets if points is None: @@ -110,13 +133,16 @@ def nom_add_discipline_coords(self, discipline, points=None): else: # we are provided with points. we can do the full initialization now - self.nom_addPointSet(points, "x_%s0" % discipline, add_output=False) + self.nom_addPointSet(points, "x_%s0" % discipline, add_output=False, applyIC=applyIC) self.add_input("x_%s_in" % discipline, distributed=True, val=points.flatten()) self.add_output("x_%s0" % discipline, distributed=True, val=points.flatten()) - def nom_addPointSet(self, points, ptName, add_output=True, **kwargs): + def nom_addPointSet(self, points, ptName, add_output=True, applyIC=False): # add the points to the dvgeo object - self.DVGeo.addPointSet(points.reshape(len(points) // 3, 3), ptName, **kwargs) + if self.geo_type == "multi": + self.DVGeo.addPointSet(points.reshape(len(points) // 3, 3), ptName, applyIC=applyIC) + else: + self.DVGeo.addPointSet(points.reshape(len(points) // 3, 3), ptName) self.omPtSetList.append(ptName) if self.geo_type == "ffd": @@ -135,7 +161,7 @@ def nom_add_point_dict(self, point_dict): for k, v in point_dict.items(): self.nom_addPointSet(v, k) - def nom_getDVGeo(self, childIdx=None): + def nom_getDVGeo(self, childIdx=None, comp=None): """ Gets the DVGeometry object held in the geometry component so DVGeo methods can be called directly on it @@ -152,13 +178,17 @@ def nom_getDVGeo(self, childIdx=None): """ # return the top level DVGeo - if childIdx is None: + if childIdx is None and comp is None: return self.DVGeo # return a child DVGeo - else: + elif childIdx is not None: return self.DVGeo.children[childIdx] + # return a component DVGeo + else: + return self.DVGeo.DVGeoDict[comp] + def nom_getDVCon(self): """ Gets the DVConstraints object held in the geometry component so DVCon methods can be called directly on it @@ -174,7 +204,7 @@ def nom_getDVCon(self): Wrapper for DVGeo functions """ - def nom_addGlobalDV(self, dvName, value, func, childIdx=None, isComposite=False): + def nom_addGlobalDV(self, dvName, value, func, childIdx=None, compName=None, isComposite=False): """Add a global design variable to the DVGeo object. This is a wrapper for the DVGeo.addGlobalDV method. Parameters @@ -202,16 +232,21 @@ def nom_addGlobalDV(self, dvName, value, func, childIdx=None, isComposite=False) Raised if the underlying DVGeo object is not an FFD """ # global DVs are only added to FFD-based DVGeo objects - if self.geo_type != "ffd": + if self.geo_type != "ffd" and self.geo_type != "multi": raise RuntimeError(f"Only FFD-based DVGeo objects can use global DVs, not type:{self.geo_type}") # call the dvgeo object and add this dv - if childIdx is None: - self.DVGeo.addGlobalDV(dvName, value, func) - shape = self.DVGeo.DV_listGlobal[dvName].nVal - else: - self.DVGeo.children[childIdx].addGlobalDV(dvName, value, func) - shape = self.DVGeo.children[childIdx].DV_listGlobal[dvName].nVal + if self.geo_type == "ffd": + if childIdx is None: + self.DVGeo.addGlobalDV(dvName, value, func) + shape = self.DVGeo.DV_listGlobal[dvName].nVal + else: + self.DVGeo.children[childIdx].addGlobalDV(dvName, value, func) + shape = self.DVGeo.children[childIdx].DV_listGlobal[dvName].nVal + + if self.geo_type == "multi": + self.DVGeo.DVGeoDict[compName].addGlobalDV(dvName, value, func) + shape = self.DVGeo.DVGeoDict[compName].DV_listGlobal[dvName].nVal # define the input # When composite DVs are used, input is not required for the default DVs. Now the composite DVs are @@ -219,15 +254,19 @@ def nom_addGlobalDV(self, dvName, value, func, childIdx=None, isComposite=False) if not isComposite: self.add_input(dvName, val=value, distributed=False, shape=shape) - def nom_addLocalDV(self, dvName, axis="y", pointSelect=None, childIdx=None, isComposite=False): + def nom_addLocalDV(self, dvName, axis="y", pointSelect=None, childIdx=None, compName=None, isComposite=False): # local DVs are only added to FFD-based DVGeo objects - if self.geo_type != "ffd": + if self.geo_type != "ffd" and self.geo_type != "multi": raise RuntimeError(f"Only FFD-based DVGeo objects can use local DVs, not type:{self.geo_type}") - if childIdx is None: - nVal = self.DVGeo.addLocalDV(dvName, axis=axis, pointSelect=pointSelect) - else: - nVal = self.DVGeo.children[childIdx].addLocalDV(dvName, axis=axis, pointSelect=pointSelect) + if self.geo_type == "ffd": + if childIdx is None: + nVal = self.DVGeo.addLocalDV(dvName, axis=axis, pointSelect=pointSelect) + else: + nVal = self.DVGeo.children[childIdx].addLocalDV(dvName, axis=axis, pointSelect=pointSelect) + + if self.geo_type == "multi": + nVal = self.DVGeo.DVGeoDict[compName].addLocalDV(dvName, axis=axis, pointSelect=pointSelect) # define the input # When composite DVs are used, input is not required for the default DVs. Now the composite DVs are @@ -399,16 +438,20 @@ def nom_addESPVariable(self, desmptr_name, isComposite=False, **kwargs): if not isComposite: self.add_input(desmptr_name, distributed=False, shape=val.shape, val=val) - def nom_addRefAxis(self, childIdx=None, **kwargs): + def nom_addRefAxis(self, childIdx=None, compName=None, **kwargs): # references axes are only needed in FFD-based DVGeo objects - if self.geo_type != "ffd": + if self.geo_type != "ffd" and self.geo_type != "multi": raise RuntimeError(f"Only FFD-based DVGeo objects can use reference axes, not type:{self.geo_type}") # we just pass this through - if childIdx is None: - return self.DVGeo.addRefAxis(**kwargs) - else: - return self.DVGeo.children[childIdx].addRefAxis(**kwargs) + if self.geo_type == "ffd": + if childIdx is None: + return self.DVGeo.addRefAxis(**kwargs) + else: + return self.DVGeo.children[childIdx].addRefAxis(**kwargs) + + if self.geo_type == "multi": + return self.DVGeo.DVGeoDict[compName].addRefAxis(**kwargs) """ Wrapper for DVCon functions From f6af3f5882fbc96d107994fe496e76be0141c547 Mon Sep 17 00:00:00 2001 From: Bernardo Pacini Date: Mon, 26 Jun 2023 16:08:46 -0400 Subject: [PATCH 02/15] Fixing pointset name call in derivative computation --- pygeo/mphys/mphys_dvgeo.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/pygeo/mphys/mphys_dvgeo.py b/pygeo/mphys/mphys_dvgeo.py index 242bae87..0701fe6c 100644 --- a/pygeo/mphys/mphys_dvgeo.py +++ b/pygeo/mphys/mphys_dvgeo.py @@ -611,7 +611,16 @@ def compute_jacvec_product(self, inputs, d_inputs, d_outputs, mode): jvtmp = np.dot(np.transpose(dcdx), dout) d_inputs[dvname] += jvtmp - for ptSetName in self.DVGeo.ptSetNames: + if self.geo_type != "multi": + ptSetNames = [] + for comp in self.DVGeo.DVGeoDict.keys(): + for ptSet in self.DVGeo.DVGeoDict[comp].ptSetNames: + if ptSet not in ptSetNames: + ptSetNames.append(ptSet) + else: + ptSetNames = self.DVGeo.ptSetNames + + for ptSetName in ptSetNames: if ptSetName in self.omPtSetList: dout = d_outputs[ptSetName].reshape(len(d_outputs[ptSetName]) // 3, 3) From 96251926ea159e455881c4d94af44cfa890a2f72 Mon Sep 17 00:00:00 2001 From: Bernardo Pacini Date: Mon, 26 Jun 2023 15:12:53 -0500 Subject: [PATCH 03/15] Fixing incorrect logical --- pygeo/mphys/mphys_dvgeo.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pygeo/mphys/mphys_dvgeo.py b/pygeo/mphys/mphys_dvgeo.py index 0701fe6c..177d0c57 100644 --- a/pygeo/mphys/mphys_dvgeo.py +++ b/pygeo/mphys/mphys_dvgeo.py @@ -611,7 +611,7 @@ def compute_jacvec_product(self, inputs, d_inputs, d_outputs, mode): jvtmp = np.dot(np.transpose(dcdx), dout) d_inputs[dvname] += jvtmp - if self.geo_type != "multi": + if self.geo_type == "multi": ptSetNames = [] for comp in self.DVGeo.DVGeoDict.keys(): for ptSet in self.DVGeo.DVGeoDict[comp].ptSetNames: From 92b736d24485624b8c76606bbb69fc8d16764254 Mon Sep 17 00:00:00 2001 From: Bernardo Pacini Date: Tue, 27 Jun 2023 17:51:32 -0400 Subject: [PATCH 04/15] Adding sliding curves for interfaces that can be remeshed --- pygeo/mphys/mphys_dvgeo.py | 9 ------ pygeo/parameterization/DVGeoMulti.py | 47 ++++++++++++++++++++-------- 2 files changed, 34 insertions(+), 22 deletions(-) diff --git a/pygeo/mphys/mphys_dvgeo.py b/pygeo/mphys/mphys_dvgeo.py index 177d0c57..777331a1 100644 --- a/pygeo/mphys/mphys_dvgeo.py +++ b/pygeo/mphys/mphys_dvgeo.py @@ -114,15 +114,6 @@ def nom_addComponent(self, comp, ffd_file, triMesh, scale=1.0): DVGeo = DVGeometry(ffd_file) self.DVGeo.addComponent(comp=comp, DVGeo=DVGeo, triMesh=triMesh, scale=scale) - def nom_addIntersection(self, compA, compB, dStarA, dStarB, featureCurves, project, includeCurves, curveEpsDict, anisotropy):#, trackSurfaces): - if self.geo_type != "multi": - raise RuntimeError( - f"Only multi-based DVGeo objects can have intersections added to them, not type:{self.geo_type}" - ) - - # Add intersection - self.DVGeo.addIntersection(compA=compA, compB=compB, dStarA=dStarA, dStarB=dStarB, featureCurves=featureCurves, project=project, includeCurves=includeCurves, curveEpsDict=curveEpsDict, anisotropy=anisotropy)#, trackSurfaces=trackSurfaces) - def nom_add_discipline_coords(self, discipline, points=None, applyIC=False): # TODO remove one of these methods to keep only one method to add pointsets diff --git a/pygeo/parameterization/DVGeoMulti.py b/pygeo/parameterization/DVGeoMulti.py index eeec1d16..6493c73b 100644 --- a/pygeo/parameterization/DVGeoMulti.py +++ b/pygeo/parameterization/DVGeoMulti.py @@ -160,6 +160,7 @@ def addIntersection( project=False, marchDir=1, includeCurves=False, + slidingCurves=[], intDir=None, curveEpsDict=None, trackSurfaces=None, @@ -209,6 +210,10 @@ def addIntersection( includeCurves : bool, optional Flag to specify whether to include features curves in the inverse-distance deformation. + slidingCurves : list, optional + The list of curves to project to, but on which the mesh nodes are not frozen in their initial positions. + This allows the mesh nodes to slide along the feature curve. + intDir : int, optional If there are multiple intersection curves, this specifies which curve to choose. The sign determines the direction and the value (1, 2, 3) specifies the axis (x, y, z). @@ -266,6 +271,7 @@ def addIntersection( project, marchDir, includeCurves, + slidingCurves, intDir, curveEpsDict, trackSurfaces, @@ -957,6 +963,7 @@ def __init__( project, marchDir, includeCurves, + slidingCurves, intDir, curveEpsDict, trackSurfaces, @@ -1146,6 +1153,10 @@ def __init__( # flag to include feature curves in ID-warping self.incCurves = includeCurves + # list of curves that allow nodes to slide on them. we only use these for the projection step, + # but they are not included in the first line based IDWarp + self.slidingCurves = slidingCurves + # direction to pick if we have multiple intersection curves self.intDir = intDir @@ -1331,7 +1342,7 @@ def addPointSet(self, pts, ptSetName, compMap, comm): elemIDs[:] = elemIDs + 1 # (we need to do this separetely because Fortran will actively change elemIDs contents. self.curveSearchAPI.mindistancecurve( - ptsToCurves.T, self.seam0.T, self.seamConn.T + 1, xyzProj.T, tanProj.T, dist2, elemIDs + ptsToCurves.T, self.seam0.T, self.seamConnFull.T + 1, xyzProj.T, tanProj.T, dist2, elemIDs ) # Adjust indices back to Python standards @@ -1441,7 +1452,7 @@ def update(self, ptSetName, delta): # we use the initial seam coordinates here coor = self.seam0 # bar connectivity for the remeshed elements - conn = self.seamConn + conn = self.seamConnWarp # deltas for each point (nNode, 3) in size if self.seam.shape == self.seam0.shape: dr = self.seam - self.seam0 @@ -1548,7 +1559,7 @@ def sens(self, dIdPt, ptSetName, comm): # we use the initial seam coordinates here coor = self.seam0 # bar connectivity for the remeshed elements - conn = self.seamConn + conn = self.seamConnWarp # Get the two end points for the line elements r0 = coor[conn[:, 0]] @@ -1685,7 +1696,7 @@ def project(self, ptSetName, newPts): # conn of the current curve seamBeg = self.seamBeg[curveName] seamEnd = self.seamEnd[curveName] - curveConn = self.seamConn[seamBeg:seamEnd] + curveConn = self.seamConnFull[seamBeg:seamEnd] # Project these to the combined curves using pySurf # Get number of points @@ -2692,7 +2703,8 @@ def _getIntersectionSeam(self, comm, firstCall=False): self.distFeature = {} remeshedCurves = np.zeros((0, 3), dtype=self.dtype) - remeshedCurveConn = np.zeros((0, 2), dtype="int32") + remeshedCurveConnFull = np.zeros((0, 2), dtype="int32") + remeshedCurveConnWarp = np.zeros((0, 2), dtype="int32") # loop over each curve, figure out what nodes get re-meshed, re-mesh, and append to seam... for curveName in self.featureCurveNames: @@ -2815,7 +2827,10 @@ def _getIntersectionSeam(self, comm, firstCall=False): # append this new curve to the featureCurve data remeshedCurves = np.vstack((remeshedCurves, newCoor)) - remeshedCurveConn = np.vstack((remeshedCurveConn, newBarsConn)) + remeshedCurveConnFull = np.vstack((remeshedCurveConnFull, newBarsConn)) + + if curveName not in self.slidingCurves: + remeshedCurveConnWarp = np.vstack((remeshedCurveConnWarp, newBarsConn)) # number of new nodes added in the opposite direction nNewNodesReverse = 0 @@ -2842,7 +2857,10 @@ def _getIntersectionSeam(self, comm, firstCall=False): newBarsConn = newBarsConn + len(remeshedCurves) remeshedCurves = np.vstack((remeshedCurves, newCoor)) - remeshedCurveConn = np.vstack((remeshedCurveConn, newBarsConn)) + remeshedCurveConnFull = np.vstack((remeshedCurveConnFull, newBarsConn)) + + if curveName not in self.slidingCurves: + remeshedCurveConnWarp = np.vstack((remeshedCurveConnWarp, newBarsConn)) if curveName in curveBegCoor: # finally, put the modified initial and final points back in place. @@ -2860,28 +2878,31 @@ def _getIntersectionSeam(self, comm, firstCall=False): if firstCall: # save the beginning and end indices of these elements self.seamBeg[curveName] = ( - len(finalConn) + len(remeshedCurveConn) - (nNewNodes + nNewNodesReverse) + 2 + len(finalConn) + len(remeshedCurveConnFull) - (nNewNodes + nNewNodesReverse) + 2 ) - self.seamEnd[curveName] = len(finalConn) + len(remeshedCurveConn) + self.seamEnd[curveName] = len(finalConn) + len(remeshedCurveConnFull) # Output the feature curves if self.comm.rank == 0 and self.debug: curvename = f"featureCurves_{self.counter}" - tecplot_interface.writeTecplotFEdata(remeshedCurves, remeshedCurveConn, curvename, curvename) + tecplot_interface.writeTecplotFEdata(remeshedCurves, remeshedCurveConnFull, curvename, curvename) # now we are done going over curves, # so we can append all the new curves to the "seam", # which now contains the intersection, and re-meshed feature curves # increment the conn from curves - remeshedCurveConn += len(seam) + remeshedCurveConnFull += len(seam) + remeshedCurveConnWarp += len(seam) # stack the nodes seam = np.vstack((seam, remeshedCurves)) # stack the conn - finalConn = np.vstack((finalConn, remeshedCurveConn)) + finalConnFull = np.vstack((finalConn, remeshedCurveConnFull)) + finalConnWarp = np.vstack((finalConn, remeshedCurveConnWarp)) # save the connectivity - self.seamConn = finalConn + self.seamConnFull = finalConnFull + self.seamConnWarp = finalConnWarp self.counter += 1 From 60c0e3973d4ec0e5ecd1bae26f252f8062175f70 Mon Sep 17 00:00:00 2001 From: Bernardo Pacini Date: Sat, 2 Dec 2023 14:24:04 -0500 Subject: [PATCH 05/15] Updating implementation for new MPhys DVGeo wrapper --- pygeo/mphys/mphys_dvgeo.py | 181 ++++++++++++++++++--------- pygeo/parameterization/DVGeoMulti.py | 2 +- 2 files changed, 126 insertions(+), 57 deletions(-) diff --git a/pygeo/mphys/mphys_dvgeo.py b/pygeo/mphys/mphys_dvgeo.py index a245fa54..155cfd84 100644 --- a/pygeo/mphys/mphys_dvgeo.py +++ b/pygeo/mphys/mphys_dvgeo.py @@ -5,7 +5,7 @@ from openmdao.api import AnalysisError # Local modules -from .. import DVConstraints, DVGeometry, DVGeometryESP, DVGeometryVSP +from .. import DVConstraints, DVGeometry, DVGeometryESP, DVGeometryVSP, DVGeometryMulti # class that actually calls the DVGeometry methods @@ -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) @@ -125,7 +128,21 @@ 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): + # 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) @@ -137,14 +154,18 @@ 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, applyIC=False): # TODO remove one of these methods to keep only one method to add pointsets if points is None: @@ -154,7 +175,7 @@ def nom_add_discipline_coords(self, discipline, points=None, DVGeoName=None): 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, applyIC=applyIC) self.add_input("x_%s_in" % discipline, distributed=True, val=points.flatten()) self.add_output("x_%s0" % discipline, distributed=True, val=points.flatten()) @@ -182,7 +203,7 @@ 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 @@ -205,14 +226,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 @@ -228,7 +257,7 @@ def nom_getDVCon(self): Wrapper for DVGeo functions """ - def nom_addGlobalDV(self, dvName, value, func, childName=None, isComposite=False, DVGeoName=None): + def nom_addGlobalDV(self, dvName, value, func, childName=None, comp=None, isComposite=False, DVGeoName=None): """ Add a global design variable to the DVGeo object. This is a wrapper for the DVGeo.addGlobalDV method. @@ -246,6 +275,9 @@ def nom_addGlobalDV(self, dvName, value, func, childName=None, isComposite=False 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 @@ -262,14 +294,18 @@ def nom_addGlobalDV(self, dvName, value, func, childName=None, isComposite=False DVGeo = self.nom_getDVGeo(DVGeoName=DVGeoName) # global DVs are only added to FFD-based DVGeo objects - if not isinstance(DVGeo, DVGeometry): + if not isinstance(DVGeo, DVGeometry) and not isinstance(DVGeo, DVGeometryMulti): raise RuntimeError(f"Only FFD-based DVGeo objects can use global DVs, not type: {type(DVGeo).__name__}") # call the dvgeo object and add this dv - if childName is None: - DVGeo.addGlobalDV(dvName, value, func) - else: + if childName is not None and comp is not None: + DVGeo.DVGeoDict[comp].children[childName].addGlobalDV(dvName, value, func) + elif comp is not None: + DVGeo.DVGeoDict[comp].addGlobalDV(dvName, value, func) + elif childName is not None: DVGeo.children[childName].addGlobalDV(dvName, value, func) + else: + DVGeo.addGlobalDV(dvName, value, func) # define the input # When composite DVs are used, input is not required for the default DVs. Now the composite DVs are @@ -277,24 +313,24 @@ def nom_addGlobalDV(self, dvName, value, func, childName=None, isComposite=False if not isComposite: self.add_input(dvName, distributed=False, shape=len(np.atleast_1d(value))) - # call the dvgeo object and add this dv - if childName is None: - DVGeo.addGlobalDV(dvName, value, func) - else: - DVGeo.children[childName].addGlobalDV(dvName, value, func) - - def nom_addLocalDV(self, dvName, axis="y", pointSelect=None, childName=None, isComposite=False, DVGeoName=None): + def nom_addLocalDV( + self, dvName, axis="y", pointSelect=None, childName=None, comp=None, isComposite=False, DVGeoName=None + ): # if we have multiple DVGeos use the one specified by name DVGeo = self.nom_getDVGeo(DVGeoName=DVGeoName) # local DVs are only added to FFD-based DVGeo objects - if not isinstance(DVGeo, DVGeometry): + if not isinstance(DVGeo, DVGeometry) and not isinstance(DVGeo, DVGeometryMulti): raise RuntimeError(f"Only FFD-based DVGeo objects can use local DVs, not type: {type(DVGeo).__name__}") - if childName is None: - nVal = DVGeo.addLocalDV(dvName, axis=axis, pointSelect=pointSelect) - else: + if childName is not None and comp is not None: + nVal = DVGeo.DVGeoDict[comp].children[childName].addLocalDV(dvName, axis=axis, pointSelect=pointSelect) + elif comp is not None: + nVal = DVGeo.DVGeoDict[comp].addLocalDV(dvName, axis=axis, pointSelect=pointSelect) + elif childName is not None: nVal = DVGeo.children[childName].addLocalDV(dvName, axis=axis, pointSelect=pointSelect) + else: + nVal = DVGeo.addLocalDV(dvName, axis=axis, pointSelect=pointSelect) # define the input # When composite DVs are used, input is not required for the default DVs. Now the composite DVs are @@ -308,6 +344,7 @@ def nom_addLocalSectionDV( dvName, secIndex, childName=None, + comp=None, axis=1, pointSelect=None, volList=None, @@ -332,6 +369,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 @@ -368,32 +408,37 @@ def nom_addLocalSectionDV( DVGeo = self.nom_getDVGeo(DVGeoName=DVGeoName) # local DVs are only added to FFD-based DVGeo objects - if not isinstance(DVGeo, DVGeometry): + if not isinstance(DVGeo, DVGeometry) and not isinstance(DVGeo, DVGeometryMulti): raise RuntimeError( f"Only FFD-based DVGeo objects can use local section DVs, not type: {type(DVGeo).__name__}" ) - # add the DV to a normal DVGeo - if childName is None: - nVal = DVGeo.addLocalSectionDV(dvName, secIndex, axis, pointSelect, volList, orient0, orient2, config) - # add the DV to a child DVGeo - else: + # add the DV to DVGeo + if childName is not None and comp is not None: + nVal = ( + DVGeo.DVGeoDict[comp] + .children[childName] + .addLocalSectionDV(dvName, secIndex, axis, pointSelect, volList, orient0, orient2, config) + ) + + elif comp is not None: + nVal = DVGeo.DVGeoDict[comp].addLocalSectionDV( + dvName, secIndex, axis, pointSelect, volList, orient0, orient2, config + ) + + elif childName is not None: nVal = DVGeo.children[childName].addLocalSectionDV( - dvName, - secIndex, - axis, - pointSelect, - volList, - orient0, - orient2, - config, + dvName, secIndex, axis, pointSelect, volList, orient0, orient2, config ) + else: + nVal = DVGeo.addLocalSectionDV(dvName, secIndex, axis, pointSelect, volList, orient0, orient2, config) + # define the input self.add_input(dvName, distributed=False, shape=nVal) return nVal - def nom_addShapeFunctionDV(self, dvName, shapes, childName=None, config=None, DVGeoName=None): + def nom_addShapeFunctionDV(self, dvName, shapes, childName=None, comp=None, config=None, DVGeoName=None): """ Add one or more local shape function design variables to the DVGeometry object Wrapper for :meth:`addShapeFunctionDV <.DVGeometry.addShapeFunctionDV>` @@ -410,6 +455,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 @@ -436,13 +484,19 @@ def nom_addShapeFunctionDV(self, dvName, shapes, childName=None, config=None, DV f"Only FFD-based DVGeo objects can use shape function DVs, not type: {type(DVGeo).__name__}" ) - # add the DV to a normal DVGeo - if childName is None: - nVal = DVGeo.addShapeFunctionDV(dvName, shapes, config) - # add the DV to a child DVGeo - else: + # add the DV to DVGeo + if childName is not None and comp is not None: + nVal = DVGeo.DVGeoDict[comp].children[childName].addShapeFunctionDV(dvName, shapes, config) + + elif comp is not None: + nVal = DVGeo.DVGeoDict[comp].addShapeFunctionDV(dvName, shapes, config) + + elif childName is not None: nVal = DVGeo.children[childName].addShapeFunctionDV(dvName, shapes, config) + else: + nVal = DVGeo.addShapeFunctionDV(dvName, shapes, config) + # define the input self.add_input(dvName, distributed=False, shape=nVal) return nVal @@ -501,21 +555,27 @@ def nom_addESPVariable(self, desmptr_name, isComposite=False, DVGeoName=None, ** if not isComposite: self.add_input(desmptr_name, distributed=False, shape=val.shape, val=val) - def nom_addRefAxis(self, childName=None, DVGeoName=None, **kwargs): + def nom_addRefAxis(self, childName=None, comp=None, DVGeoName=None, **kwargs): # if we have multiple DVGeos use the one specified by name DVGeo = self.nom_getDVGeo(DVGeoName=DVGeoName) # references axes are only needed in FFD-based DVGeo objects - if not isinstance(DVGeo, DVGeometry): + if not isinstance(DVGeo, DVGeometry) and not isinstance(DVGeo, DVGeometryMulti): raise RuntimeError(f"Only FFD-based DVGeo objects can use reference axes, not type: {type(DVGeo).__name__}") - # add ref axis to this DVGeo - if childName is None: - return DVGeo.addRefAxis(**kwargs) - # add ref axis to the specified child - else: + # add ref axis to the DVGeo + if childName is not None and comp is not None: + return DVGeo.DVGeoDict[comp].children[childName].addRefAxis(**kwargs) + + elif comp is not None: + return DVGeo.DVGeoDict[comp].addRefAxis(**kwargs) + + elif childName is not None: return DVGeo.children[childName].addRefAxis(**kwargs) + else: + return DVGeo.addRefAxis(**kwargs) + """ Wrapper for DVCon functions """ @@ -690,7 +750,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) @@ -722,4 +791,4 @@ def compute_jacvec_product(self, inputs, d_inputs, d_outputs, mode): # entry of this array since dvgeo always behaves like we are passing # in multiple objective seeds with totalSensitivity. we can remove the [0] # once we move back to totalSensitivityTransProd - d_inputs[k] += xdotg[k][0] \ No newline at end of file + d_inputs[k] += xdotg[k][0] diff --git a/pygeo/parameterization/DVGeoMulti.py b/pygeo/parameterization/DVGeoMulti.py index 5ce51643..665214f8 100644 --- a/pygeo/parameterization/DVGeoMulti.py +++ b/pygeo/parameterization/DVGeoMulti.py @@ -2935,7 +2935,7 @@ def _getIntersectionSeam(self, comm, firstCall=False): remeshedCurves = np.vstack((remeshedCurves, newCoor)) remeshedCurveConnFull = np.vstack((remeshedCurveConnFull, newBarsConn)) - + if curveName not in self.slidingCurves: remeshedCurveConnWarp = np.vstack((remeshedCurveConnWarp, newBarsConn)) From 45bf8a91b6474c7742d8df8f874001b626ed3f18 Mon Sep 17 00:00:00 2001 From: Bernardo Pacini Date: Sat, 2 Dec 2023 14:26:58 -0500 Subject: [PATCH 06/15] Removing new DVGeoMulti curve tracking --- pygeo/parameterization/DVGeoMulti.py | 47 ++++++++-------------------- 1 file changed, 13 insertions(+), 34 deletions(-) diff --git a/pygeo/parameterization/DVGeoMulti.py b/pygeo/parameterization/DVGeoMulti.py index 665214f8..7d9acfd5 100644 --- a/pygeo/parameterization/DVGeoMulti.py +++ b/pygeo/parameterization/DVGeoMulti.py @@ -184,7 +184,6 @@ def addIntersection( project=False, marchDir=1, includeCurves=False, - slidingCurves=[], intDir=None, curveEpsDict=None, trackSurfaces=None, @@ -234,10 +233,6 @@ def addIntersection( includeCurves : bool, optional Flag to specify whether to include features curves in the inverse-distance deformation. - slidingCurves : list, optional - The list of curves to project to, but on which the mesh nodes are not frozen in their initial positions. - This allows the mesh nodes to slide along the feature curve. - intDir : int, optional If there are multiple intersection curves, this specifies which curve to choose. The sign determines the direction and the value (1, 2, 3) specifies the axis (x, y, z). @@ -295,7 +290,6 @@ def addIntersection( project, marchDir, includeCurves, - slidingCurves, intDir, curveEpsDict, trackSurfaces, @@ -1012,7 +1006,6 @@ def __init__( project, marchDir, includeCurves, - slidingCurves, intDir, curveEpsDict, trackSurfaces, @@ -1202,10 +1195,6 @@ def __init__( # flag to include feature curves in ID-warping self.incCurves = includeCurves - # list of curves that allow nodes to slide on them. we only use these for the projection step, - # but they are not included in the first line based IDWarp - self.slidingCurves = slidingCurves - # direction to pick if we have multiple intersection curves self.intDir = intDir @@ -1444,7 +1433,7 @@ def addPointSet(self, pts, ptSetName, compMap, comm): elemIDs[:] = elemIDs + 1 # (we need to do this separetely because Fortran will actively change elemIDs contents. self.curveSearchAPI.mindistancecurve( - ptsToCurves.T, self.seam0.T, self.seamConnFull.T + 1, xyzProj.T, tanProj.T, dist2, elemIDs + ptsToCurves.T, self.seam0.T, self.seamConn.T + 1, xyzProj.T, tanProj.T, dist2, elemIDs ) # Adjust indices back to Python standards @@ -1554,7 +1543,7 @@ def update(self, ptSetName, delta): # we use the initial seam coordinates here coor = self.seam0 # bar connectivity for the remeshed elements - conn = self.seamConnWarp + conn = self.seamConn # deltas for each point (nNode, 3) in size if self.seam.shape == self.seam0.shape: dr = self.seam - self.seam0 @@ -1661,7 +1650,7 @@ def sens(self, dIdPt, ptSetName, comm): # we use the initial seam coordinates here coor = self.seam0 # bar connectivity for the remeshed elements - conn = self.seamConnWarp + conn = self.seamConn # Get the two end points for the line elements r0 = coor[conn[:, 0]] @@ -1798,7 +1787,7 @@ def project(self, ptSetName, newPts): # conn of the current curve seamBeg = self.seamBeg[curveName] seamEnd = self.seamEnd[curveName] - curveConn = self.seamConnFull[seamBeg:seamEnd] + curveConn = self.seamConn[seamBeg:seamEnd] # Project these to the combined curves using pySurf # Get number of points @@ -2780,8 +2769,7 @@ def _getIntersectionSeam(self, comm, firstCall=False): self.distFeature = {} remeshedCurves = np.zeros((0, 3), dtype=self.dtype) - remeshedCurveConnFull = np.zeros((0, 2), dtype="int32") - remeshedCurveConnWarp = np.zeros((0, 2), dtype="int32") + remeshedCurveConn = np.zeros((0, 2), dtype="int32") # loop over each curve, figure out what nodes get re-meshed, re-mesh, and append to seam... for curveName in self.featureCurveNames: @@ -2904,10 +2892,7 @@ def _getIntersectionSeam(self, comm, firstCall=False): # append this new curve to the featureCurve data remeshedCurves = np.vstack((remeshedCurves, newCoor)) - remeshedCurveConnFull = np.vstack((remeshedCurveConnFull, newBarsConn)) - - if curveName not in self.slidingCurves: - remeshedCurveConnWarp = np.vstack((remeshedCurveConnWarp, newBarsConn)) + remeshedCurveConn = np.vstack((remeshedCurveConn, newBarsConn)) # number of new nodes added in the opposite direction nNewNodesReverse = 0 @@ -2934,10 +2919,7 @@ def _getIntersectionSeam(self, comm, firstCall=False): newBarsConn = newBarsConn + len(remeshedCurves) remeshedCurves = np.vstack((remeshedCurves, newCoor)) - remeshedCurveConnFull = np.vstack((remeshedCurveConnFull, newBarsConn)) - - if curveName not in self.slidingCurves: - remeshedCurveConnWarp = np.vstack((remeshedCurveConnWarp, newBarsConn)) + remeshedCurveConn = np.vstack((remeshedCurveConn, newBarsConn)) if curveName in curveBegCoor: # finally, put the modified initial and final points back in place. @@ -2955,31 +2937,28 @@ def _getIntersectionSeam(self, comm, firstCall=False): if firstCall: # save the beginning and end indices of these elements self.seamBeg[curveName] = ( - len(finalConn) + len(remeshedCurveConnFull) - (nNewNodes + nNewNodesReverse) + 2 + len(finalConn) + len(remeshedCurveConn) - (nNewNodes + nNewNodesReverse) + 2 ) - self.seamEnd[curveName] = len(finalConn) + len(remeshedCurveConnFull) + self.seamEnd[curveName] = len(finalConn) + len(remeshedCurveConn) # Output the feature curves if self.comm.rank == 0 and self.debug: curvename = f"featureCurves_{self.counter}" - tecplot_interface.writeTecplotFEdata(remeshedCurves, remeshedCurveConnFull, curvename, curvename) + tecplot_interface.writeTecplotFEdata(remeshedCurves, remeshedCurveConn, curvename, curvename) # now we are done going over curves, # so we can append all the new curves to the "seam", # which now contains the intersection, and re-meshed feature curves # increment the conn from curves - remeshedCurveConnFull += len(seam) - remeshedCurveConnWarp += len(seam) + remeshedCurveConn += len(seam) # stack the nodes seam = np.vstack((seam, remeshedCurves)) # stack the conn - finalConnFull = np.vstack((finalConn, remeshedCurveConnFull)) - finalConnWarp = np.vstack((finalConn, remeshedCurveConnWarp)) + finalConn = np.vstack((finalConn, remeshedCurveConn)) # save the connectivity - self.seamConnFull = finalConnFull - self.seamConnWarp = finalConnWarp + self.seamConn = finalConn self.counter += 1 From e35ead0cd65ef0a118ee0ed5e93e46a4252f7cb6 Mon Sep 17 00:00:00 2001 From: Bernardo Pacini Date: Sat, 2 Dec 2023 15:01:10 -0500 Subject: [PATCH 07/15] Fixing isort issues --- pygeo/mphys/mphys_dvgeo.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pygeo/mphys/mphys_dvgeo.py b/pygeo/mphys/mphys_dvgeo.py index 155cfd84..d8eaf8d6 100644 --- a/pygeo/mphys/mphys_dvgeo.py +++ b/pygeo/mphys/mphys_dvgeo.py @@ -5,7 +5,7 @@ from openmdao.api import AnalysisError # Local modules -from .. import DVConstraints, DVGeometry, DVGeometryESP, DVGeometryVSP, DVGeometryMulti +from .. import DVConstraints, DVGeometry, DVGeometryESP, DVGeometryMulti, DVGeometryVSP # class that actually calls the DVGeometry methods From 8a341bf6e54630a492597d98d9f62daab233111d Mon Sep 17 00:00:00 2001 From: Bernardo Pacini Date: Sun, 3 Dec 2023 09:37:54 -0500 Subject: [PATCH 08/15] Fixing applyIC kwargs issue --- pygeo/mphys/mphys_dvgeo.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/pygeo/mphys/mphys_dvgeo.py b/pygeo/mphys/mphys_dvgeo.py index d8eaf8d6..4a8f4765 100644 --- a/pygeo/mphys/mphys_dvgeo.py +++ b/pygeo/mphys/mphys_dvgeo.py @@ -179,12 +179,15 @@ def nom_add_discipline_coords(self, discipline, points=None, DVGeoName=None, app self.add_input("x_%s_in" % discipline, distributed=True, val=points.flatten()) self.add_output("x_%s0" % discipline, distributed=True, val=points.flatten()) - def nom_addPointSet(self, points, ptName, add_output=True, DVGeoName=None, **kwargs): + def nom_addPointSet(self, points, ptName, add_output=True, DVGeoName=None, applyIC=False, **kwargs): # if we have multiple DVGeos use the one specified by name DVGeo = self.nom_getDVGeo(DVGeoName=DVGeoName) # add the points to the dvgeo object - DVGeo.addPointSet(points.reshape(len(points) // 3, 3), ptName, **kwargs) + if isinstance(DVGeo, DVGeometryMulti): + DVGeo.addPointSet(points.reshape(len(points) // 3, 3), ptName, applyIC, **kwargs) + else: + DVGeo.addPointSet(points.reshape(len(points) // 3, 3), ptName, **kwargs) self.omPtSetList.append(ptName) if isinstance(DVGeo, DVGeometry): From be3c868cf47881445d3dfb49060b97bfec863bfe Mon Sep 17 00:00:00 2001 From: Bernardo Pacini Date: Mon, 11 Dec 2023 11:09:40 -0500 Subject: [PATCH 09/15] Fixing child FFD naming issue --- pygeo/mphys/mphys_dvgeo.py | 44 +++++++++++++++++++++++--------------- 1 file changed, 27 insertions(+), 17 deletions(-) diff --git a/pygeo/mphys/mphys_dvgeo.py b/pygeo/mphys/mphys_dvgeo.py index 4a8f4765..edce7605 100644 --- a/pygeo/mphys/mphys_dvgeo.py +++ b/pygeo/mphys/mphys_dvgeo.py @@ -302,13 +302,13 @@ def nom_addGlobalDV(self, dvName, value, func, childName=None, comp=None, isComp # call the dvgeo object and add this dv if childName is not None and comp is not None: - DVGeo.DVGeoDict[comp].children[childName].addGlobalDV(dvName, value, func) + DVGeo.DVGeoDict[comp].children[childName].addGlobalDV(dvName, value, func, prependName=False) elif comp is not None: - DVGeo.DVGeoDict[comp].addGlobalDV(dvName, value, func) + DVGeo.DVGeoDict[comp].addGlobalDV(dvName, value, func, prependName=False) elif childName is not None: - DVGeo.children[childName].addGlobalDV(dvName, value, func) + DVGeo.children[childName].addGlobalDV(dvName, value, func, prependName=False) else: - DVGeo.addGlobalDV(dvName, value, func) + DVGeo.addGlobalDV(dvName, value, func, prependName=False) # define the input # When composite DVs are used, input is not required for the default DVs. Now the composite DVs are @@ -327,13 +327,17 @@ def nom_addLocalDV( raise RuntimeError(f"Only FFD-based DVGeo objects can use local DVs, not type: {type(DVGeo).__name__}") if childName is not None and comp is not None: - nVal = DVGeo.DVGeoDict[comp].children[childName].addLocalDV(dvName, axis=axis, pointSelect=pointSelect) + nVal = ( + DVGeo.DVGeoDict[comp] + .children[childName] + .addLocalDV(dvName, axis=axis, pointSelect=pointSelect, prependName=False) + ) elif comp is not None: - nVal = DVGeo.DVGeoDict[comp].addLocalDV(dvName, axis=axis, pointSelect=pointSelect) + nVal = DVGeo.DVGeoDict[comp].addLocalDV(dvName, axis=axis, pointSelect=pointSelect, prependName=False) elif childName is not None: - nVal = DVGeo.children[childName].addLocalDV(dvName, axis=axis, pointSelect=pointSelect) + nVal = DVGeo.children[childName].addLocalDV(dvName, axis=axis, pointSelect=pointSelect, prependName=False) else: - nVal = DVGeo.addLocalDV(dvName, axis=axis, pointSelect=pointSelect) + nVal = DVGeo.addLocalDV(dvName, axis=axis, pointSelect=pointSelect, prependName=False) # define the input # When composite DVs are used, input is not required for the default DVs. Now the composite DVs are @@ -421,21 +425,25 @@ def nom_addLocalSectionDV( nVal = ( DVGeo.DVGeoDict[comp] .children[childName] - .addLocalSectionDV(dvName, secIndex, axis, pointSelect, volList, orient0, orient2, config) + .addLocalSectionDV( + dvName, secIndex, axis, pointSelect, volList, orient0, orient2, config, prependName=False + ) ) elif comp is not None: nVal = DVGeo.DVGeoDict[comp].addLocalSectionDV( - dvName, secIndex, axis, pointSelect, volList, orient0, orient2, config + dvName, secIndex, axis, pointSelect, volList, orient0, orient2, config, prependName=False ) elif childName is not None: nVal = DVGeo.children[childName].addLocalSectionDV( - dvName, secIndex, axis, pointSelect, volList, orient0, orient2, config + dvName, secIndex, axis, pointSelect, volList, orient0, orient2, config, prependName=False ) else: - nVal = DVGeo.addLocalSectionDV(dvName, secIndex, axis, pointSelect, volList, orient0, orient2, config) + nVal = DVGeo.addLocalSectionDV( + dvName, secIndex, axis, pointSelect, volList, orient0, orient2, config, prependName=False + ) # define the input self.add_input(dvName, distributed=False, shape=nVal) @@ -489,16 +497,18 @@ def nom_addShapeFunctionDV(self, dvName, shapes, childName=None, comp=None, conf # add the DV to DVGeo if childName is not None and comp is not None: - nVal = DVGeo.DVGeoDict[comp].children[childName].addShapeFunctionDV(dvName, shapes, config) + nVal = ( + DVGeo.DVGeoDict[comp].children[childName].addShapeFunctionDV(dvName, shapes, config, prependName=False) + ) elif comp is not None: - nVal = DVGeo.DVGeoDict[comp].addShapeFunctionDV(dvName, shapes, config) + nVal = DVGeo.DVGeoDict[comp].addShapeFunctionDV(dvName, shapes, config, prependName=False) elif childName is not None: - nVal = DVGeo.children[childName].addShapeFunctionDV(dvName, shapes, config) + nVal = DVGeo.children[childName].addShapeFunctionDV(dvName, shapes, config, prependName=False) else: - nVal = DVGeo.addShapeFunctionDV(dvName, shapes, config) + nVal = DVGeo.addShapeFunctionDV(dvName, shapes, config, prependName=False) # define the input self.add_input(dvName, distributed=False, shape=nVal) @@ -509,7 +519,7 @@ def nom_addGeoCompositeDV(self, dvName, ptSetName=None, u=None, scale=None, DVGe DVGeo = self.nom_getDVGeo(DVGeoName=DVGeoName) # call the dvgeo object and add this dv - DVGeo.addCompositeDV(dvName, ptSetName=ptSetName, u=u, scale=scale, **kwargs) + DVGeo.addCompositeDV(dvName, ptSetName=ptSetName, u=u, scale=scale, prependName=False, **kwargs) val = DVGeo.getValues() # define the input From 00e1ac6c7e8aed910c2b3c64cd62312a58407c99 Mon Sep 17 00:00:00 2001 From: Bernardo Pacini Date: Tue, 12 Dec 2023 12:15:06 -0500 Subject: [PATCH 10/15] Updating kwargs for adding pointset --- pygeo/mphys/mphys_dvgeo.py | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/pygeo/mphys/mphys_dvgeo.py b/pygeo/mphys/mphys_dvgeo.py index edce7605..0eecb1bd 100644 --- a/pygeo/mphys/mphys_dvgeo.py +++ b/pygeo/mphys/mphys_dvgeo.py @@ -165,9 +165,8 @@ def nom_addChild(self, ffd_file, DVGeoName=None, childName=None, comp=None): 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, applyIC=False): + 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) @@ -175,19 +174,16 @@ def nom_add_discipline_coords(self, discipline, points=None, DVGeoName=None, app 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, applyIC=applyIC) + 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()) - def nom_addPointSet(self, points, ptName, add_output=True, DVGeoName=None, applyIC=False, **kwargs): + def nom_addPointSet(self, points, ptName, add_output=True, DVGeoName=None, **kwargs): # if we have multiple DVGeos use the one specified by name DVGeo = self.nom_getDVGeo(DVGeoName=DVGeoName) # add the points to the dvgeo object - if isinstance(DVGeo, DVGeometryMulti): - DVGeo.addPointSet(points.reshape(len(points) // 3, 3), ptName, applyIC, **kwargs) - else: - DVGeo.addPointSet(points.reshape(len(points) // 3, 3), ptName, **kwargs) + DVGeo.addPointSet(points.reshape(len(points) // 3, 3), ptName, **kwargs) self.omPtSetList.append(ptName) if isinstance(DVGeo, DVGeometry): From a383525aa321e916dc949d69e7db884000dbd62b Mon Sep 17 00:00:00 2001 From: Bernardo Pacini Date: Thu, 11 Jan 2024 15:36:12 -0500 Subject: [PATCH 11/15] Compacting if checks --- pygeo/mphys/mphys_dvgeo.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pygeo/mphys/mphys_dvgeo.py b/pygeo/mphys/mphys_dvgeo.py index 0eecb1bd..a63e0581 100644 --- a/pygeo/mphys/mphys_dvgeo.py +++ b/pygeo/mphys/mphys_dvgeo.py @@ -293,7 +293,7 @@ def nom_addGlobalDV(self, dvName, value, func, childName=None, comp=None, isComp DVGeo = self.nom_getDVGeo(DVGeoName=DVGeoName) # global DVs are only added to FFD-based DVGeo objects - if not isinstance(DVGeo, DVGeometry) and not isinstance(DVGeo, DVGeometryMulti): + if not isinstance(DVGeo, (DVGeometry, DVGeometryMulti)): raise RuntimeError(f"Only FFD-based DVGeo objects can use global DVs, not type: {type(DVGeo).__name__}") # call the dvgeo object and add this dv @@ -319,7 +319,7 @@ def nom_addLocalDV( DVGeo = self.nom_getDVGeo(DVGeoName=DVGeoName) # local DVs are only added to FFD-based DVGeo objects - if not isinstance(DVGeo, DVGeometry) and not isinstance(DVGeo, DVGeometryMulti): + if not isinstance(DVGeo, (DVGeometry, DVGeometryMulti)): raise RuntimeError(f"Only FFD-based DVGeo objects can use local DVs, not type: {type(DVGeo).__name__}") if childName is not None and comp is not None: @@ -411,7 +411,7 @@ def nom_addLocalSectionDV( DVGeo = self.nom_getDVGeo(DVGeoName=DVGeoName) # local DVs are only added to FFD-based DVGeo objects - if not isinstance(DVGeo, DVGeometry) and not isinstance(DVGeo, DVGeometryMulti): + if not isinstance(DVGeo, (DVGeometry, DVGeometryMulti)): raise RuntimeError( f"Only FFD-based DVGeo objects can use local section DVs, not type: {type(DVGeo).__name__}" ) @@ -569,7 +569,7 @@ def nom_addRefAxis(self, childName=None, comp=None, DVGeoName=None, **kwargs): DVGeo = self.nom_getDVGeo(DVGeoName=DVGeoName) # references axes are only needed in FFD-based DVGeo objects - if not isinstance(DVGeo, DVGeometry) and not isinstance(DVGeo, DVGeometryMulti): + 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 the DVGeo From e12cbc4629fbbbdffecf84596465131d2ceb4c76 Mon Sep 17 00:00:00 2001 From: Bernardo Pacini Date: Tue, 9 Jul 2024 15:44:09 -0400 Subject: [PATCH 12/15] Adding docstring for nom_addComponent function --- pygeo/mphys/mphys_dvgeo.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/pygeo/mphys/mphys_dvgeo.py b/pygeo/mphys/mphys_dvgeo.py index 6717fbc9..0006bd62 100644 --- a/pygeo/mphys/mphys_dvgeo.py +++ b/pygeo/mphys/mphys_dvgeo.py @@ -129,6 +129,24 @@ def compute(self, inputs, outputs): self.update_jac = True 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) From 68c5526bacc1aa9739e0178c8cfcb0b0f25451da Mon Sep 17 00:00:00 2001 From: Bernardo Pacini Date: Tue, 9 Jul 2024 15:54:27 -0400 Subject: [PATCH 13/15] Fixing extraneous addRefAxis call --- pygeo/mphys/mphys_dvgeo.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/pygeo/mphys/mphys_dvgeo.py b/pygeo/mphys/mphys_dvgeo.py index 0006bd62..d27ab6c2 100644 --- a/pygeo/mphys/mphys_dvgeo.py +++ b/pygeo/mphys/mphys_dvgeo.py @@ -629,9 +629,6 @@ def nom_addRefAxis( ) # add ref axis to the specified child - else: - return DVGeo.addRefAxis(**kwargs) - """ Wrapper for DVCon functions """ From 6948664063e98663f9174e38c2d7f3f4bca8322c Mon Sep 17 00:00:00 2001 From: Bernardo Pacini Date: Tue, 9 Jul 2024 16:01:46 -0400 Subject: [PATCH 14/15] Fixing black failures --- pygeo/mphys/mphys_dvgeo.py | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/pygeo/mphys/mphys_dvgeo.py b/pygeo/mphys/mphys_dvgeo.py index d27ab6c2..b880b157 100644 --- a/pygeo/mphys/mphys_dvgeo.py +++ b/pygeo/mphys/mphys_dvgeo.py @@ -278,7 +278,16 @@ def nom_getDVCon(self): """ def nom_addGlobalDV( - self, dvName, value, func, childName=None, comp=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. @@ -459,7 +468,9 @@ def nom_addLocalSectionDV( self.add_input(dvName, distributed=False, shape=nVal) return nVal - def nom_addShapeFunctionDV(self, dvName, shapes, childName=None, comp=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>` From 216832e6acbdf2fc829c7d22a4da5c1a2183655b Mon Sep 17 00:00:00 2001 From: Bernardo Pacini Date: Tue, 9 Jul 2024 19:03:22 -0400 Subject: [PATCH 15/15] Fixing addRefAxis call --- pygeo/mphys/mphys_dvgeo.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pygeo/mphys/mphys_dvgeo.py b/pygeo/mphys/mphys_dvgeo.py index b880b157..0de732c2 100644 --- a/pygeo/mphys/mphys_dvgeo.py +++ b/pygeo/mphys/mphys_dvgeo.py @@ -614,7 +614,7 @@ 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, DVGeometryMulti)):