Skip to content

Commit d1caca8

Browse files
committed
add logger
1 parent 04adcd8 commit d1caca8

File tree

3 files changed

+54
-15
lines changed

3 files changed

+54
-15
lines changed

src/Drivers/hiopbbpy/BODriverEX.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ def cons_jac_vec(x):
102102

103103
options = {
104104
'acquisition_type': acq_type,
105+
'log_level': 'none',
105106
'bo_maxiter': 10,
106107
'opt_solver': 'IPOPT', #"SLSQP" "IPOPT" "trust-constr"
107108
'batch_size': 3,

src/hiopbbpy/opt/boalgorithm.py

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,11 @@
99
from numpy.random import uniform
1010
from scipy.optimize import minimize
1111
from scipy.stats import qmc
12-
import warnings
1312
from ..surrogate_modeling.gp import GaussianProcess
1413
from .acquisition import LCBacquisition, EIacquisition
1514
from ..problems.problem import Problem
1615
from .optproblem import IpoptProb
17-
from ..utils.util import Evaluator
16+
from ..utils.util import Evaluator, Logger
1817

1918
# A base class defining a general framework for Bayesian Optimization
2019
class BOAlgorithmBase:
@@ -35,6 +34,7 @@ def __init__(self):
3534
self.x_opt = None # Best observed point
3635
self.y_opt = None # Best observed value
3736
self.idx_opt = None # Index of the best observed value in the history
37+
self.logger = Logger() # logger
3838

3939
# Sets the acquisition function type and batch size
4040
def setAcquisitionType(self, acquisition_type, batch_size=1):
@@ -100,6 +100,8 @@ def __init__(self, prob:Problem, gpsurrogate:GaussianProcess, xtrain, ytrain,
100100
self.opt_evaluator = options.get('opt_evaluator', self.opt_evaluator)
101101
assert isinstance(self.opt_evaluator, Evaluator)
102102

103+
self.logger.setlevel(options.get('log_level', "INFO"))
104+
103105
if options and 'opt_solver' in options:
104106
opt_solver = options['opt_solver']
105107
assert opt_solver in ["SLSQP", "trust-constr", "IPOPT"], f"Invalid opt_solver: {opt_solver}"
@@ -219,17 +221,17 @@ def optimize(self):
219221
self.x_hist.append(x_train[-j].flatten())
220222
self.y_hist.append(y_train[-j].flatten())
221223
if self.batch_size == 1:
222-
print(f"Sample point X:")
224+
self.logger.info(f"Sample point X:")
223225
else:
224-
print(f"Sample points X:")
226+
self.logger.info(f"Sample points X:")
225227
for j in range(self.batch_size):
226-
print(f"{x_train[-j-1]}")
228+
self.logger.info(f"{x_train[-j-1]}")
227229
if self.batch_size == 1:
228-
print(f"\nObservation Y:")
230+
self.logger.info(f"Observation Y:")
229231
else:
230-
print(f"\nObservations Y:")
232+
self.logger.info(f"Observations Y:")
231233
for j in range(self.batch_size):
232-
print(f"{y_new[-j-1]}")
234+
self.logger.info(f"{y_new[-j-1]}")
233235

234236
# Save the optimal results and all the training data
235237
self.idx_opt = np.argmin(self.y_hist)
@@ -238,9 +240,7 @@ def optimize(self):
238240
self.setTrainingData(x_train, y_train)
239241

240242
print(f"\n\nOptimal at BO iteration: {self.idx_opt+1} ")
241-
print(f"Optimal point: {self.x_opt.flatten()}, Optimal value: {self.y_opt}")
242-
print()
243-
243+
print(f"Optimal point: {self.x_opt.flatten()}, Optimal value: {self.y_opt}\n\n")
244244

245245
class minimizer_wrapper:
246246
def __init__(self, fun, method, bounds, constraints, solver_options):
@@ -260,15 +260,15 @@ def minimizer_callback(self, x0s):
260260
y = minimize(self.fun['obj'], x0, method=self.method, bounds=self.bounds, constraints=self.constraints, options=self.solver_options)
261261
success = y.success
262262
if not success:
263-
print(y.message)
263+
self.logger.warning(y.message)
264264
xopt = y.x
265265
yopt = y.fun
266266
elif self.method == "trust-constr":
267267
nonlinear_constraint = NonlinearConstraint(self.constraints['cons'], self.constraints['cl'], self.constraints['cu'], jac=self.constraints['jac'])
268268
y = minimize(self.fun['obj'], x0, method=self.method, bounds=self.bounds, constraints=[nonlinear_constraint], options=self.solver_options)
269269
success = y.success
270270
if not success:
271-
print(y.message)
271+
self.logger.warning(y.message)
272272
xopt = y.x
273273
yopt = y.fun
274274
else:
@@ -281,7 +281,7 @@ def minimizer_callback(self, x0s):
281281
# ipopt returns 0 as success
282282
success = True
283283
else:
284-
warnings.warn(f"Ipopt failed to solve the problem. Status msg: {msg}")
284+
self.logger.warning(f"Ipopt failed to solve the problem. Status msg: {msg}")
285285
success = False
286286

287287
yopt = info['obj_val']

src/hiopbbpy/utils/util.py

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
"""
2727
import numpy as np
2828
from .evaluation_manager import EvaluationManager, is_running_with_mpi
29-
29+
import logging
3030

3131

3232
def check_required_keys(user_dict, required_keys):
@@ -95,3 +95,41 @@ def run(self, fun, Xin):
9595
Y = [Fi[0] for Fi in Fout]
9696
return Y
9797

98+
class Logger:
99+
"""
100+
A simple wrapper for Python's logging module that sets up a reusable logger.
101+
Logs to the console using a consistent format.
102+
"""
103+
104+
def __init__(self, name='hiopbbpy', level='ERROR'):
105+
# Create a logger instance with a given name
106+
self._logger = logging.getLogger(name)
107+
108+
# Create a console output handler
109+
ch = logging.StreamHandler()
110+
111+
# Define the output format: timestamp, logger name, level, and message
112+
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
113+
114+
# Add the handle
115+
ch.setFormatter(formatter)
116+
self._logger.addHandler(ch)
117+
118+
# Set log level
119+
self.setlevel(level)
120+
121+
def setlevel(self, level_str):
122+
"""Set the log level using a string from 'NONE', 'DEBUG', 'INFO', 'WARNING', 'ERROR' and 'CRITICAL' """
123+
if isinstance(level_str, str) and level_str.strip().lower() == 'none':
124+
level = logging.CRITICAL + 1 # Disable all logging
125+
else:
126+
# Default to INFO if string is unrecognized
127+
level = getattr(logging, str(level_str).upper(), logging.INFO)
128+
129+
self._logger.setLevel(level)
130+
for handler in self._logger.handlers:
131+
handler.setLevel(level)
132+
133+
def __getattr__(self, attr):
134+
# Forward all unknown attributes to the underlying logger
135+
return getattr(self._logger, attr)

0 commit comments

Comments
 (0)