Skip to content

Commit

Permalink
Merge dev (#27)
Browse files Browse the repository at this point in the history
  • Loading branch information
jbussemaker authored Oct 30, 2024
2 parents 08915b3 + a4090ff commit 3bd3889
Show file tree
Hide file tree
Showing 28 changed files with 61 additions and 24 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/tests_slow.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ jobs:
pip install -r requirements-tests.txt
pip install -r requirements-assignment.txt
pip install -r requirements-ota.txt
pip install -e .[arch_sbo,botorch,trieste,tpe,rocket,egor]
pip install -e .[arch_sbo,botorch,trieste,tpe,rocket,egor,hebo]
pip install jupyter ipython ipykernel
ipython kernel install --name "python3" --user
Expand Down
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -214,3 +214,5 @@ $RECYCLE.BIN/

n2.html
site/

sb_arch_opt/problems/turbofan_data
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,10 @@ If you use SBArchOpt in your work, please cite it:
Bussemaker, J.H., (2023). SBArchOpt: Surrogate-Based Architecture Optimization. Journal of Open Source Software, 8(89),
5564, DOI: [10.21105/joss.05564](https://doi.org/10.21105/joss.05564)

Bussemaker, J.H., et al., (2024). Surrogate-Based Optimization of System Architectures Subject to Hidden Constraints.
In AIAA AVIATION 2024 FORUM. Las Vegas, NV, USA.
DOI: [10.2514/6.2024-4401](https://arc.aiaa.org/doi/10.2514/6.2024-4401)

## Contributing

The project is coordinated by: Jasper Bussemaker (*jasper.bussemaker at dlr.de*)
Expand Down
7 changes: 4 additions & 3 deletions docs/algo/arch_sbo.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
# Architecture Surrogate-Based Optimization (SBO) Algorithm

ArchSBO implements a Surrogate-Based Optimization (SBO) algorithm configured for solving most types of architecture
optimization problems. It has been developed with experience from the following work:
optimization problems. It is presented in the following work:

J.H. Bussemaker et al., "Effectiveness of Surrogate-Based Optimization Algorithms for System Architecture Optimization",
AIAA Aviation 2021, DOI: [10.2514/6.2021-3095](https://arc.aiaa.org/doi/10.2514/6.2021-3095)
J.H. Bussemaker et al. "Surrogate-Based Optimization of System Architectures Subject to Hidden Constraints".
In: AIAA AVIATION 2024 FORUM. Las Vegas, NV, USA, July 2024.
DOI: [10.2514/6.2024-4401](https://arc.aiaa.org/doi/10.2514/6.2024-4401)

The algorithm uses state-of-the-art mixed-discrete hierarchical Gaussian Process (Kriging) surrogate models and ensures
that all evaluated and selected infill points are imputed (and therefore valid).
Expand Down
4 changes: 4 additions & 0 deletions docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,10 @@ If you use SBArchOpt in your work, please cite it:
Bussemaker, J.H., (2023). SBArchOpt: Surrogate-Based Architecture Optimization. Journal of Open Source Software, 8(89),
5564, DOI: [10.21105/joss.05564](https://doi.org/10.21105/joss.05564)

Bussemaker, J.H., et al., (2024). Surrogate-Based Optimization of System Architectures Subject to Hidden Constraints.
In AIAA AVIATION 2024 FORUM. Las Vegas, NV, USA.
DOI: [10.2514/6.2024-4401](https://arc.aiaa.org/doi/10.2514/6.2024-4401)

## Usage

See also the tutorial(s):
Expand Down
2 changes: 1 addition & 1 deletion sb_arch_opt/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = '1.5.2'
__version__ = '1.5.3'
16 changes: 8 additions & 8 deletions sb_arch_opt/algo/trieste_interface/algo.py
Original file line number Diff line number Diff line change
Expand Up @@ -237,19 +237,19 @@ def _run_doe(self, n: int):
return self.observer(self.search_space.sample(n))

def get_models(self, datasets):
# https://secondmind-labs.github.io/trieste/1.0.0/notebooks/inequality_constraints.html#Modelling-the-two-functions
# https://secondmind-labs.github.io/trieste/3.3.4/notebooks/inequality_constraints.html#Modelling-the-two-functions
search_space = self.search_space

models = {}
for tag, dataset in datasets.items():
# https://secondmind-labs.github.io/trieste/1.0.0/notebooks/failure_ego.html#Build-GPflow-models
# https://secondmind-labs.github.io/trieste/3.3.4/notebooks/failure_ego.html#Build-GPflow-models
if tag == FAILED:
classifier = build_vgp_classifier(dataset, search_space, noise_free=True)
models[tag] = VariationalGaussianProcess(
classifier, BatchOptimizer(tf.optimizers.Adam(1e-3)), use_natgrads=True)
continue

# https://secondmind-labs.github.io/trieste/1.0.0/notebooks/expected_improvement.html#Model-the-objective-function
# https://secondmind-labs.github.io/trieste/3.3.4/notebooks/expected_improvement.html#Model-the-objective-function
gpr = build_gpr(dataset, search_space, likelihood_variance=1e-7)
models[tag] = GaussianProcessRegression(gpr, num_kernel_samples=100)

Expand All @@ -271,16 +271,16 @@ def get_state_path(results_folder):
def get_acquisition_rule(self, pof=.5) -> 'AcquisitionRule':
"""
Builds the acquisition rule based on whether the problem is single- or multi-objective and constrained or not:
https://secondmind-labs.github.io/trieste/1.0.0/notebooks/inequality_constraints.html#Define-the-acquisition-process
https://secondmind-labs.github.io/trieste/1.0.0/notebooks/multi_objective_ehvi.html#Define-the-acquisition-function
https://secondmind-labs.github.io/trieste/3.3.4/notebooks/inequality_constraints.html#Define-the-acquisition-process
https://secondmind-labs.github.io/trieste/3.3.4/notebooks/multi_objective_ehvi.html#Define-the-acquisition-function
"""

if self._problem.n_eq_constr > 0:
raise RuntimeError('Trieste currently does not support equality constraints')

if self.is_constrained:
# Reduce the PoF rules into one
# https://secondmind-labs.github.io/trieste/1.0.0/notebooks/inequality_constraints.html#Constrained-optimization-with-more-than-one-constraint
# https://secondmind-labs.github.io/trieste/3.3.4/notebooks/inequality_constraints.html#Constrained-optimization-with-more-than-one-constraint
pof_builders = [ProbabilityOfFeasibility(threshold=pof).using(f'{CONSTR_PREFIX}{ig}')
for ig in range(self._problem.n_ieq_constr)]
pof_builder = pof_builders[0] if len(pof_builders) == 1 else Product(*pof_builders)
Expand Down Expand Up @@ -404,10 +404,10 @@ def to_population(self, datasets: Dict[Hashable, 'Dataset']) -> Population:
class ArchOptObserver:
"""
The observer function that evaluates each architecture, according to the tagged observer pattern:
https://secondmind-labs.github.io/trieste/1.0.0/notebooks/inequality_constraints.html
https://secondmind-labs.github.io/trieste/3.3.4/notebooks/inequality_constraints.html
Support for failed evaluations based on:
https://secondmind-labs.github.io/trieste/1.0.0/notebooks/failure_ego.html#Define-the-data-sets
https://secondmind-labs.github.io/trieste/3.3.4/notebooks/failure_ego.html#Define-the-data-sets
Class needed to prevent overflow in BayesianOptimizer.__repr__
"""
Expand Down
32 changes: 30 additions & 2 deletions sb_arch_opt/problems/turbofan_arch.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,13 @@
More information: https://github.com/jbussemaker/OpenTurbofanArchitecting
"""
import pickle
import shutil
import logging
import zipfile
import tempfile
import numpy as np
from typing import *
import urllib.request
import concurrent.futures
from cached_property import cached_property
from pymoo.core.variable import Real, Integer, Choice
Expand All @@ -43,6 +47,8 @@

log = logging.getLogger('sb_arch_opt.turb')

DATA_URL = 'https://github.com/jbussemaker/SBArchOpt_Data/archive/refs/heads/main.zip'


def check_dependency():
if not HAS_OPEN_TURB_ARCH:
Expand All @@ -63,7 +69,6 @@ class OpenTurbArchProblemWrapper(HierarchyProblemBase):
default_enable_pf_calc = False
_robust_correct_x = False # Bug in the bleed offtake choice

_data_folder = 'turbofan_data'
_sub_folder = None

def __init__(self, open_turb_arch_problem: 'ArchitectingProblem', n_parallel=None):
Expand Down Expand Up @@ -406,7 +411,7 @@ def _arch_evaluate_x_surrogate(self, x: np.ndarray):

@classmethod
def _get_data_path(cls, sub_path: str) -> str:
path = os.path.join(os.path.dirname(__file__), cls._data_folder, cls._sub_folder)
path = os.path.join(get_data_folder(), cls._sub_folder)
os.makedirs(path, exist_ok=True)
if sub_path is not None:
path = os.path.join(path, sub_path)
Expand Down Expand Up @@ -624,6 +629,29 @@ def _arch_evaluate_x(self, x: np.ndarray):
# return self._arch_evaluate_x_surrogate(x)


def get_data_folder(force_download=False):
"""Download problem data if needed, and return path to data"""
cache_folder = get_cache_path()
folder = os.path.join(cache_folder, 'turbofan_data')

if force_download or not os.path.exists(folder):
if os.path.exists(folder):
shutil.rmtree(folder)

log.info(f'Downloading turbofan problem data from: {DATA_URL}')
with tempfile.TemporaryDirectory() as tmp_folder:
zip_file_path = os.path.join(tmp_folder, 'data.zip')
urllib.request.urlretrieve(DATA_URL, zip_file_path)

with zipfile.ZipFile(zip_file_path, 'r') as zip_ref:
repo_root_folder = zip_ref.namelist()[0][:-1]
zip_ref.extractall(tmp_folder)
shutil.move(os.path.join(tmp_folder, repo_root_folder, 'turbofan_data'), folder)
log.info('Turbofan problem data downloaded and available!')

return folder


if __name__ == '__main__':
print(SimpleTurbofanArch().pareto_front())
# SimpleTurbofanArch().print_stats()
Expand Down
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file removed sb_arch_opt/problems/turbofan_data/simple/eval_f_pf.npy
Binary file not shown.
Binary file not shown.
Binary file removed sb_arch_opt/problems/turbofan_data/simple/eval_g_pf.npy
Binary file not shown.
Binary file not shown.
Binary file removed sb_arch_opt/problems/turbofan_data/simple/eval_x_pf.npy
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file removed sb_arch_opt/problems/turbofan_data/simple/x_all.pkl
Binary file not shown.
6 changes: 3 additions & 3 deletions sb_arch_opt/tests/algo/test_hebo.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ def check_dependency():
return pytest.mark.skipif(not HAS_HEBO, reason='HEBO dependencies not installed')


# @pytest.mark.skipif(int(os.getenv('RUN_SLOW_TESTS', 0)) != 1, reason='Set RUN_SLOW_TESTS=1 to run slow tests')
# def test_slow_tests():
# assert HAS_HEBO
@pytest.mark.skipif(int(os.getenv('RUN_SLOW_TESTS', 0)) != 1, reason='Set RUN_SLOW_TESTS=1 to run slow tests')
def test_slow_tests():
assert HAS_HEBO


@check_dependency()
Expand Down
1 change: 1 addition & 0 deletions sb_arch_opt/tests/algo/test_trieste.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from sb_arch_opt.problems.constrained import ArchCantileveredBeam
from sb_arch_opt.algo.trieste_interface.algo import ArchOptBayesianOptimizer


def check_dependency():
return pytest.mark.skipif(not HAS_TRIESTE, reason='Trieste dependencies not installed')

Expand Down
9 changes: 3 additions & 6 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,9 +78,9 @@ def _get_readme():
'botorch~=0.8.2',
],
'trieste': [
'trieste~=2.0.0',
# Until https://github.com/GPflow/GPflow/pull/2050 is merged and GPflow has been updated
# 'gpflow~=2.7.0', 'keras~=2.10.0', 'tensorflow-probability==0.18.0',
'trieste~=3.3',
# Until https://github.com/secondmind-labs/trieste/pull/858 is merged
'tensorflow<=2.16', 'tensorflow-probability<0.24',
],
'tpe': [
'tpe==0.0.8',
Expand All @@ -97,7 +97,4 @@ def _get_readme():
},
python_requires='>=3.7',
packages=find_packages(include='sb_arch_opt*'),
package_data={
'sb_arch_opt.problems': ['turbofan_data/*', 'turbofan_data/**/*'],
},
)

0 comments on commit 3bd3889

Please sign in to comment.