Skip to content

Commit

Permalink
Merge branch 'main' into updateTests
Browse files Browse the repository at this point in the history
  • Loading branch information
eirikurj authored May 10, 2023
2 parents 16fa2e8 + 7ca8f36 commit f8cd959
Show file tree
Hide file tree
Showing 15 changed files with 194 additions and 107 deletions.
4 changes: 2 additions & 2 deletions .github/test_real.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
set -e
./input_files/get-input-files.sh

# All tests should pass on Ubuntu
if [[ $OS == "ubuntu" ]]; then
# No tests should be skipped on GCC and non Intel MPI
if [[ $COMPILERS == "gcc" ]] && [[ -z $I_MPI_ROOT ]]; then
EXTRA_FLAGS='--disallow_skipped'
fi

Expand Down
1 change: 1 addition & 0 deletions doc/API.rst
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ This package consists of the following modules:
:maxdepth: 1

DVConstraints
mphys_dvgeo
DVGeometry
DVGeometryMulti
DVGeometryESP
Expand Down
13 changes: 12 additions & 1 deletion doc/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,18 @@
)

# mock import for autodoc
autodoc_mock_imports = ["numpy", "mpi4py", "scipy", "pyspline", "baseclasses", "pysurf", "prefoil", "pyOCSM", "openvsp"]
autodoc_mock_imports = [
"numpy",
"mpi4py",
"scipy",
"pyspline",
"baseclasses",
"pysurf",
"prefoil",
"pyOCSM",
"openvsp",
"openmdao",
]

# This sets the bibtex bibliography file(s) to reference in the documentation
bibtex_bibfiles = ["ref.bib"]
6 changes: 6 additions & 0 deletions doc/mphys_dvgeo.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
.. _OM_DVGEOCOMP:

MPhys DVGeo Component
---------------------
.. autoclass:: pygeo.mphys.mphys_dvgeo.OM_DVGEOCOMP
:members:
4 changes: 4 additions & 0 deletions pygeo/constraints/DVCon.py
Original file line number Diff line number Diff line change
Expand Up @@ -1359,6 +1359,7 @@ def addThicknessToChordConstraints1D(

def addTriangulatedSurfaceConstraint(
self,
comm,
surface_1_name=None,
DVGeo_1_name="default",
surface_2_name="default",
Expand Down Expand Up @@ -1464,6 +1465,7 @@ def addTriangulatedSurfaceConstraint(

# Finally add constraint object
self.constraints[typeName][conName] = TriangulatedSurfaceConstraint(
comm,
conName,
surface_1,
surface_1_name,
Expand Down Expand Up @@ -3139,6 +3141,8 @@ def addMonotonicConstraints(
self, key, slope=1.0, name=None, start=0, stop=-1, config=None, childIdx=None, comp=None, DVGeoName="default"
):
"""
Add monotonic constraints to a given design variable.
Parameters
----------
key : str
Expand Down
14 changes: 8 additions & 6 deletions pygeo/constraints/areaConstraint.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
# External modules
from mpi4py import MPI
import numpy as np

# Local modules
Expand All @@ -22,6 +21,7 @@ class TriangulatedSurfaceConstraint(GeometricConstraint):

def __init__(
self,
comm,
name,
surface_1,
surface_1_name,
Expand All @@ -41,6 +41,8 @@ def __init__(

super().__init__(name, 2, -1e10, 0.0, scale, None, addToPyOpt)

self.comm = comm

# get the point sets
self.surface_1_name = surface_1_name
self.surface_2_name = surface_2_name
Expand Down Expand Up @@ -233,7 +235,7 @@ def evalTriangulatedSurfConstraint(self):
mindist_tmp,
self.rho,
self.maxdim,
MPI.COMM_WORLD.py2f(),
self.comm.py2f(),
)
# second run gets the well-conditioned KS
KS, perim_length, mindist, _, _ = geograd_parallel.compute(
Expand All @@ -246,16 +248,16 @@ def evalTriangulatedSurfConstraint(self):
mindist,
self.rho,
self.maxdim,
MPI.COMM_WORLD.py2f(),
self.comm.py2f(),
)

self.perim_length = perim_length
self.minimum_distance = mindist

if self.perim_length > self.max_perim:
failflag = True
if MPI.COMM_WORLD.rank == 0:
print("Intersection length ", str(perim_length), " exceeds tol, returning fail flag")
if self.comm.rank == 0:
print(f"Intersection length {self.perim_length} exceeds tol {self.max_perim}, returning fail flag")
else:
failflag = False
return KS, perim_length, failflag
Expand All @@ -275,7 +277,7 @@ def evalTriangulatedSurfConstraintSens(self):
self.minimum_distance,
self.rho,
self.maxdim,
MPI.COMM_WORLD.py2f(),
self.comm.py2f(),
)
return deriv_output

Expand Down
143 changes: 85 additions & 58 deletions pygeo/mphys/mphys_dvgeo.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
from mpi4py import MPI
import numpy as np
import openmdao.api as om
from openmdao.api import AnalysisError

# Local modules
from .. import DVConstraints, DVGeometry, DVGeometryESP, DVGeometryVSP
Expand Down Expand Up @@ -71,10 +72,13 @@ def compute(self, inputs, outputs):
# compute the DVCon constraint values
constraintfunc = dict()
self.DVCon.evalFunctions(constraintfunc, includeLinear=True)
comm = self.comm
if comm.rank == 0:
for constraintname in constraintfunc:
outputs[constraintname] = constraintfunc[constraintname]

for constraintname in constraintfunc:
# if any constraint returned a fail flag throw an error to OpenMDAO
# all constraints need the same fail flag, no <name_> prefix
if constraintname == "fail":
raise AnalysisError("Analysis error in geometric constraints")
outputs[constraintname] = constraintfunc[constraintname]

# we ran a compute so the inputs changed. update the dvcon jac
# next time the jacvec product routine is called
Expand Down Expand Up @@ -132,21 +136,49 @@ def nom_add_point_dict(self, point_dict):
self.nom_addPointSet(v, k)

def nom_addGlobalDV(self, dvName, value, func, childIdx=None, isComposite=False):
"""Add a global design variable to the DVGeo object. This is a wrapper for the DVGeo.addGlobalDV method.
Parameters
----------
dvName : str
See :meth:`addGlobalDV <.DVGeometry.addGlobalDV>`
value : float, or iterable list of floats
See :meth:`addGlobalDV <.DVGeometry.addGlobalDV>`
func : python function
See :meth:`addGlobalDV <.DVGeometry.addGlobalDV>`
childIdx : int, optional
The zero-based index of the child FFD, if this DV is for a child FFD.
The index is defined by the order in which you add the child FFD to the parent.
For example, the first child FFD has an index of 0, the second an index of 1, and so on.
isComposite : bool, optional
Whether this DV is to be included in the composite DVs, by default False
Raises
------
RuntimeError
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":
raise RuntimeError(f"Only FFD-based DVGeo objects can use global DVs, not type:{self.geo_type}")

# define the input
# When composite DVs are used, input is not required for the default DVs. Now the composite DVs are
# the actual DVs. So OpenMDAO don't need the default DVs as inputs.
if not isComposite:
self.add_input(dvName, distributed=False, shape=len(value))

# 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

# define the input
# When composite DVs are used, input is not required for the default DVs. Now the composite DVs are
# the actual DVs. So OpenMDAO don't need the default DVs as inputs.
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):
# local DVs are only added to FFD-based DVGeo objects
Expand Down Expand Up @@ -212,66 +244,64 @@ def nom_addESPVariable(self, desmptr_name, isComposite=False, **kwargs):

def nom_addThicknessConstraints2D(self, name, leList, teList, nSpan=10, nChord=10):
self.DVCon.addThicknessConstraints2D(leList, teList, nSpan, nChord, lower=1.0, name=name)
comm = self.comm
if comm.rank == 0:
self.add_output(name, distributed=True, val=np.ones((nSpan * nChord,)), shape=nSpan * nChord)
else:
self.add_output(name, distributed=True, shape=(0,))
self.add_output(name, distributed=False, val=np.ones((nSpan * nChord,)), shape=nSpan * nChord)

def nom_addThicknessConstraints1D(self, name, ptList, nCon, axis):
self.DVCon.addThicknessConstraints1D(ptList, nCon, axis, name=name)
comm = self.comm
if comm.rank == 0:
self.add_output(name, distributed=True, val=np.ones(nCon), shape=nCon)
else:
self.add_output(name, distributed=True, shape=(0))
def nom_addThicknessConstraints1D(self, name, ptList, nCon, axis, scaled=True):
self.DVCon.addThicknessConstraints1D(ptList, nCon, axis, name=name, scaled=scaled)
self.add_output(name, distributed=False, val=np.ones(nCon), shape=nCon)

def nom_addVolumeConstraint(self, name, leList, teList, nSpan=10, nChord=10):
self.DVCon.addVolumeConstraint(leList, teList, nSpan=nSpan, nChord=nChord, name=name)
comm = self.comm
if comm.rank == 0:
self.add_output(name, distributed=True, val=1.0)
else:
self.add_output(name, distributed=True, shape=0)
def nom_addVolumeConstraint(self, name, leList, teList, nSpan=10, nChord=10, surfaceName="default"):
self.DVCon.addVolumeConstraint(leList, teList, nSpan=nSpan, nChord=nChord, name=name, surfaceName=surfaceName)
self.add_output(name, distributed=False, val=1.0)

def nom_add_LETEConstraint(self, name, volID, faceID, topID=None, childIdx=None):
self.DVCon.addLeTeConstraints(volID, faceID, name=name, topID=topID, childIdx=childIdx)
# how many are there?
conobj = self.DVCon.linearCon[name]
nCon = len(conobj.indSetA)
comm = self.comm
if comm.rank == 0:
self.add_output(name, distributed=True, val=np.zeros((nCon,)), shape=nCon)
else:
self.add_output(name, distributed=True, shape=0)
self.add_output(name, distributed=False, val=np.zeros((nCon,)), shape=nCon)
return nCon

def nom_addLERadiusConstraints(self, name, leList, nSpan, axis, chordDir):
self.DVCon.addLERadiusConstraints(leList=leList, nSpan=nSpan, axis=axis, chordDir=chordDir, name=name)
comm = self.comm
if comm.rank == 0:
self.add_output(name, distributed=True, val=np.ones(nSpan), shape=nSpan)
else:
self.add_output(name, distributed=True, shape=0)
self.add_output(name, distributed=False, val=np.ones(nSpan), shape=nSpan)

def nom_addCurvatureConstraint1D(self, name, start, end, nPts, axis, **kwargs):
self.DVCon.addCurvatureConstraint1D(start=start, end=end, nPts=nPts, axis=axis, name=name, **kwargs)
comm = self.comm
if comm.rank == 0:
self.add_output(name, distributed=True, val=1.0)
else:
self.add_output(name, distributed=True, shape=0)
self.add_output(name, distributed=False, val=1.0)

def nom_addLinearConstraintsShape(self, name, indSetA, indSetB, factorA, factorB, childIdx=None):
self.DVCon.addLinearConstraintsShape(
indSetA=indSetA, indSetB=indSetB, factorA=factorA, factorB=factorB, name=name, childIdx=childIdx
)
lSize = len(indSetA)
comm = self.comm
if comm.rank == 0:
self.add_output(name, distributed=True, val=np.zeros(lSize), shape=lSize)
else:
self.add_output(name, distributed=True, shape=0)
self.add_output(name, distributed=False, val=np.zeros(lSize), shape=lSize)

def nom_addTriangulatedSurfaceConstraint(
self,
name,
surface_1_name=None,
DVGeo_1_name="default",
surface_2_name="default",
DVGeo_2_name="default",
rho=50.0,
heuristic_dist=None,
max_perim=3.0,
):
self.DVCon.addTriangulatedSurfaceConstraint(
comm=self.comm,
surface_1_name=surface_1_name,
DVGeo_1_name=DVGeo_1_name,
surface_2_name=surface_2_name,
DVGeo_2_name=DVGeo_2_name,
rho=rho,
heuristic_dist=heuristic_dist,
max_perim=max_perim,
name=name,
)

self.add_output(f"{name}_KS", distributed=False, val=0)
self.add_output(f"{name}_perim", distributed=False, val=0)

def nom_addRefAxis(self, childIdx=None, **kwargs):
# references axes are only needed in FFD-based DVGeo objects
Expand All @@ -284,9 +314,11 @@ def nom_addRefAxis(self, childIdx=None, **kwargs):
else:
return self.DVGeo.children[childIdx].addRefAxis(**kwargs)

def nom_setConstraintSurface(self, surface):
def nom_setConstraintSurface(
self, surface, name="default", addToDVGeo=False, DVGeoName="default", surfFormat="point-vector"
):
# constraint needs a triangulated reference surface at initialization
self.DVCon.setSurface(surface)
self.DVCon.setSurface(surface, name=name, addToDVGeo=addToDVGeo, DVGeoName=DVGeoName, surfFormat=surfFormat)

def compute_jacvec_product(self, inputs, d_inputs, d_outputs, mode):
# only do the computations when we have more than zero entries in d_inputs in the reverse mode
Expand All @@ -308,14 +340,9 @@ def compute_jacvec_product(self, inputs, d_inputs, d_outputs, mode):
for dvname in self.constraintfuncsens[constraintname]:
if dvname in d_inputs:
dcdx = self.constraintfuncsens[constraintname][dvname]
if self.comm.rank == 0:
dout = d_outputs[constraintname]
jvtmp = np.dot(np.transpose(dcdx), dout)
else:
jvtmp = 0.0
dout = d_outputs[constraintname]
jvtmp = np.dot(np.transpose(dcdx), dout)
d_inputs[dvname] += jvtmp
# OM does the reduction itself
# d_inputs[dvname] += self.comm.reduce(jvtmp, op=MPI.SUM, root=0)

for ptSetName in self.DVGeo.ptSetNames:
if ptSetName in self.omPtSetList:
Expand Down
Loading

0 comments on commit f8cd959

Please sign in to comment.