Skip to content

Commit

Permalink
Include non-objective/constraint functions in history output (#184)
Browse files Browse the repository at this point in the history
* Include non-objective/constraint functions in history output

* added History.extraFuncsNames

* updated tests

Co-authored-by: Neil Wu <[email protected]>
  • Loading branch information
A-CGray and ewu63 authored Nov 8, 2020
1 parent bf9ed3a commit b648e4f
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 1 deletion.
24 changes: 24 additions & 0 deletions pyoptsparse/pyOpt_history.py
Original file line number Diff line number Diff line change
Expand Up @@ -209,9 +209,14 @@ def _processDB(self):

# extract all information stored in the call counters
self.iterKeys = set()
self.extraFuncsNames = set()
for i in self.callCounters:
val = self.read(i)
self.iterKeys.update(val.keys())
if "funcs" in val.keys():
self.extraFuncsNames.update(val["funcs"].keys())
# remove objective and constraint keys
self.extraFuncsNames = self.extraFuncsNames.difference(self.conNames).difference(self.objNames)

from .__init__ import __version__

Expand Down Expand Up @@ -283,6 +288,22 @@ def getObjNames(self):
return
return copy.deepcopy(list(self.objInfo.keys()))

def getExtraFuncsNames(self):
"""
Returns extra funcs names.
These are extra key: value pairs stored in the ``funcs`` dictionary for each iteration, which are not used by the optimizer.
Returns
-------
list of str
A list containing the names of extra funcs keys.
"""
# only do this if we open the file with 'r' flag
if self.flag != "r":
return
return copy.deepcopy(list(self.extraFuncsNames))

def getObjInfo(self, key=None):
"""
Returns the `ObjInfo`, for all keys by default. A `key` parameter can also
Expand Down Expand Up @@ -535,6 +556,7 @@ def getValues(self, names=None, callCounters=None, major=True, scale=False, stac
self.DVNames.union(self.conNames)
.union(self.objNames)
.union(self.iterKeys)
.union(self.extraFuncsNames)
.difference(set(["funcs", "funcsSens", "xuser"]))
)
# cast string input into a single list
Expand Down Expand Up @@ -615,6 +637,8 @@ def getValues(self, names=None, callCounters=None, major=True, scale=False, stac
data[name].append(conDict[name])
elif name in self.objNames:
data[name].append(objDict[name])
elif name in self.extraFuncsNames:
data[name].append(val["funcs"][name])
else: # must be opt
data[name].append(val[name])
elif val["fail"] and user_specified_callCounter:
Expand Down
13 changes: 12 additions & 1 deletion test/test_hs015.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ def objfunc(self, xdict):
conval[0] = x[0] * x[1]
conval[1] = x[0] + x[1] ** 2
funcs["con"] = conval
# extra keys
funcs["extra1"] = 0.0
funcs["extra2"] = 1.0
fail = False
return funcs, fail

Expand Down Expand Up @@ -142,11 +145,19 @@ def check_hist_file(self, optimizer, tol):
last = hist.read("last") # 'last' key should be present
self.assertIn(last, callCounters)

# iterKey checks
# iterKeys checks
iterKeys = hist.getIterKeys()
for key in ["xuser", "fail", "isMajor"]:
self.assertIn(key, iterKeys)

# extraFuncsNames checks
extraFuncsNames = hist.getExtraFuncsNames()
for key in ["extra1", "extra2"]:
self.assertIn(key, extraFuncsNames)

# getValues checks
val = hist.getValues()

# this check is only used for optimizers that guarantee '0' and 'last' contain funcs
if optimizer in ["SNOPT", "SLSQP", "PSQP"]:
val = hist.getValues(callCounters=["0", "last"], stack=True)
Expand Down

0 comments on commit b648e4f

Please sign in to comment.