Skip to content

Commit

Permalink
merge validation to main
Browse files Browse the repository at this point in the history
  • Loading branch information
b4pm-devops committed Jul 17, 2024
2 parents 01e7715 + c9da378 commit faf9ab7
Show file tree
Hide file tree
Showing 72 changed files with 6,970 additions and 0 deletions.
14 changes: 14 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
*.pyc
__pycache__
.project
.pydevproject
.settings/
coverage.xml
nosetests.xml
.coverage
xdsm.html
build/
dist/
/.pytest_cache/
/sostrades_optimization_plugins/tests/__pycache__/
/sostrades_optimization_plugins/tests/.pytest_cache/
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# sostrades-optimization-plugin
59 changes: 59 additions & 0 deletions headers_ignore_config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
{
"extension_to_ignore": [
"pkl",
"png",
"jpg",
"csv",
"md",
"markdown",
"avif",
"json",
"in",
"gitignore",
"cfg",
"puml",
"pdf",
"txt",
"ipynb",
"zip",
"rst",
"ini",
"coveragerc",
"yaml",
"bat",
"tex",
"toml"
],
"files_to_ignore": [
"LICENSE",
".readthedocs",
"docs/Makefile",
".flake8",
".prettierignore",
"sostrades_optimization_plugins/models/design_var/design_var.py",
"sostrades_optimization_plugins/models/design_var/design_var_disc.py",
"sostrades_optimization_plugins/models/func_manager/func_manager.py",
"sostrades_optimization_plugins/models/func_manager/func_manager_disc.py",
"sostrades_optimization_plugins/sos_processes/test/test_sellar_opt_w_design_var/__init__.py",
"sostrades_optimization_plugins/sos_processes/test/test_sellar_opt_w_design_var/process.py",
"sostrades_optimization_plugins/sos_processes/test/test_sellar_opt_w_design_var/usecase.py",
"sostrades_optimization_plugins/sos_processes/test/test_sellar_opt_w_func_manager/__init__.py",
"sostrades_optimization_plugins/sos_processes/test/test_sellar_opt_w_func_manager/process.py",
"sostrades_optimization_plugins/sos_processes/test/test_sellar_opt_w_func_manager/usecase.py",
"sostrades_optimization_plugins/sos_processes/test/test_sellar_opt_w_func_manager_faulty/__init__.py",
"sostrades_optimization_plugins/sos_processes/test/test_sellar_opt_w_func_manager_faulty/process.py",
"sostrades_optimization_plugins/sos_processes/test/test_sellar_opt_w_func_manager_faulty/usecase.py",
"sostrades_optimization_plugins/tests/l0_test_14_optim_scenario_with_func_manager.py",
"sostrades_optimization_plugins/tests/l0_test_44_func_manager.py",
"sostrades_optimization_plugins/tests/l0_test_62_design_var_in_sellar.py",
"sostrades_optimization_plugins/tests/l1s_test_all_usecases.py",
"sostrades_optimization_plugins/tools/cst_manager/common_config.py",
"sostrades_optimization_plugins/tools/cst_manager/constraint_manager.py",
"sostrades_optimization_plugins/tools/cst_manager/constraint_object.py",
"sostrades_optimization_plugins/tools/cst_manager/database.py",
"sostrades_optimization_plugins/tools/cst_manager/fileutils.py",
"sostrades_optimization_plugins/tools/cst_manager/func_manager_common.py",
"sostrades_optimization_plugins/tools/cst_manager/__init__.py"
],
"airbus_rev_commit": "d833fdf740389587b876e30f084631430687fa5a"
}
1 change: 1 addition & 0 deletions platform_version_required.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
v4.1.0
5 changes: 5 additions & 0 deletions pytest.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
[pytest]
python_files = l*_test*.py
testpaths =
sostrades_optimization_plugins/tests
addopts = --numprocesses=auto
3 changes: 3 additions & 0 deletions requirements.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
numpy==1.24.4
pandas==2.2.2
plotly==5.3.0
13 changes: 13 additions & 0 deletions ruff.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
[lint]
select = ["I", "TCH", "PLC", "PLE", "F", "E", "W", "PERF"]
# extend-select = ["ALL"]

ignore = ["E722", "F841", "E501", "D400", "D415", "D212", "D300", "PERF203", "ANN101"]
# E722 Do not use bare `except`
# F841 Local variable `xxx` is assigned to but never used
# E501 Line too long
# D400 First line should end with a period
# D415 First line should end with a period, question mark, or exclamation point
# D212 [*] Multi-line docstring summary should start at the first line
# D300 [*] Use triple double quotes `"""`
# ANN101 Missing type annotation for `self` in method
15 changes: 15 additions & 0 deletions sostrades_optimization_plugins/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
'''
Copyright 2024 Capgemini
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
'''
15 changes: 15 additions & 0 deletions sostrades_optimization_plugins/models/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
'''
Copyright 2024 Capgemini
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
'''
15 changes: 15 additions & 0 deletions sostrades_optimization_plugins/models/design_var/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
'''
Copyright 2024 Capgemini
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
'''
199 changes: 199 additions & 0 deletions sostrades_optimization_plugins/models/design_var/design_var.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,199 @@
'''
Copyright 2022 Airbus SAS
Modifications on 2023/07/25-2024/05/16 Copyright 2023 Capgemini
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
'''
import numpy as np
from pandas import DataFrame, concat
from sostrades_core.execution_engine.sos_wrapp import SoSWrapp
from sostrades_core.tools.bspline.bspline import BSpline


class DesignVar(object):
"""
Class Design variable
"""
ACTIVATED_ELEM_LIST = "activated_elem"
VARIABLES = "variable"
VALUE = "value"
DATAFRAME_FILL = SoSWrapp.DATAFRAME_FILL
COLUMNS_NAMES = SoSWrapp.COLUMNS_NAMES
ONE_COLUMN_PER_KEY = "one column per key" # FIXME: on 4.0.3 --> SoSWrapp.ONE_COLUMN_PER_KEY
ONE_COLUMN_FOR_KEY = SoSWrapp.ONE_COLUMN_FOR_KEY
DATAFRAME_FILL_POSSIBLE_VALUES = [ONE_COLUMN_PER_KEY, ONE_COLUMN_FOR_KEY]
DESIGN_SPACE = 'design_space'
DESIGN_VAR_DESCRIPTOR = 'design_var_descriptor'
INDEX = 'index'
INDEX_NAME = 'index_name'
OUT_TYPE = 'out_type'
OUT_NAME = 'out_name'
FILL_ACTIVATED_ELEMENTS = 'fill_activated_elements'
LAST_ELEMENT_ACTIVATED = 'last element activated'
INITIAL_VALUE = 'initial_value'
FILL_ACTIVATED_ELEMENTS_POSSIBLE_VALUES = [LAST_ELEMENT_ACTIVATED, INITIAL_VALUE]

def __init__(self, inputs_dict, logger):
'''
Constructor
'''
self.design_var_descriptor = inputs_dict[self.DESIGN_VAR_DESCRIPTOR]
self.output_dict = {}
self.bspline_dict = {}
self.dspace = inputs_dict[self.DESIGN_SPACE]
self.logger = logger

def configure(self, inputs_dict):
'''
Configure with inputs_dict from the discipline
'''

self.output_dict = {}
list_ctrl = self.design_var_descriptor.keys()

for elem in list_ctrl:
l_activated = self.dspace.loc[self.dspace[self.VARIABLES]
== elem, self.ACTIVATED_ELEM_LIST].to_list()[0]
# check output length and compute BSpline only if necessary
# remark: float do not require any BSpline usage
output_length = len(self.design_var_descriptor[elem][self.INDEX])
deactivated_elem_flag = not all(l_activated)
if deactivated_elem_flag:
final_value, gradient = self.rebuild_input_array_with_activated_elements(inputs_dict, elem)
else:
final_value = inputs_dict[elem]
gradient = np.identity(output_length)

if len(final_value) == output_length:
self.bspline_dict[elem] = {
'bspline': None, 'eval_t': final_value, 'b_array': gradient}
else:
self.create_array_with_bspline(elem, final_value, output_length,
deactivated_elem_flag)

# loop over design_var_descriptor to build output
self.build_output_with_design_var_descriptor(elem, final_value)

def create_array_with_bspline(self, elem, final_value, output_length, deactivated_elem_flag):

list_t = np.linspace(0.0, 1.0, output_length)
bspline = BSpline(n_poles=len(final_value))
bspline.set_ctrl_pts(final_value)
eval_t, b_array = bspline.eval_list_t(list_t)
b_array = bspline.update_b_array(b_array)
if deactivated_elem_flag:
b_array = self.update_gradient_with_deactivated_elements_first_value(b_array)
self.bspline_dict[elem] = {
'bspline': bspline, 'eval_t': eval_t, 'b_array': b_array}

def rebuild_input_array_with_activated_elements(self, inputs_dict, elem):
'''
If some elements are desactivated wit the option activated_elem in design space, the function rebuild the correct array depending on the method
'''
# checks that dspace and activated elements are coherent with input element size
l_activated = self.dspace.loc[self.dspace[self.VARIABLES]
== elem, self.ACTIVATED_ELEM_LIST].to_list()[0]

elem_input_value = list(inputs_dict[elem])
input_length = len(elem_input_value)
if sum(l_activated) != input_length:
self.logger.error(
f'The size of the input element {elem} is not coherent with the design space and its activated elements : {sum(l_activated)} activated elements and elem of length {len(elem_input_value)}')

final_value = []
# TODO compute the gradient for each case
gradient = []
initial_gradient = np.identity(input_length).tolist()
# We fill deactivated elements with the last element activated in the array
if self.FILL_ACTIVATED_ELEMENTS in self.design_var_descriptor[elem] and self.design_var_descriptor[elem][
self.FILL_ACTIVATED_ELEMENTS] == self.LAST_ELEMENT_ACTIVATED:

for activated_bool in l_activated:
if activated_bool:
gradient.append(initial_gradient.pop(0))
final_value.append(elem_input_value.pop(0))
else:
final_value.append(final_value[-1])
# TODO gradient is not null but depend on last value
# need to fix it
gradient.append([0.] * input_length)
# by default we use initial value to fill the deactivated elements
else:
initial_value = self.dspace.loc[self.dspace[self.VARIABLES]
== elem, self.VALUE].to_list()[0]

for i, activated_bool in enumerate(l_activated):
if activated_bool:
final_value.append(elem_input_value.pop(0))
gradient.append(initial_gradient.pop(0))
else:
final_value.append(initial_value[i])
gradient.append([0.] * input_length)
return np.array(final_value), np.array(gradient)

def update_gradient_with_deactivated_elements_first_value(self, initial_gradient):
### TO DO generalize it with other deactivated elements

result = np.delete(initial_gradient, 0, axis=1)
return result

def build_output_with_design_var_descriptor(self, elem, final_value):

out_name = self.design_var_descriptor[elem][self.OUT_NAME]
out_type = self.design_var_descriptor[elem][self.OUT_TYPE]

if out_type == 'float':
if final_value.size != 1:
raise ValueError(" The input must be of size 1 for a float output")
self.output_dict[out_name] = final_value[0]
elif out_type == 'array':
self.output_dict[out_name] = self.bspline_dict[elem]['eval_t']
elif out_type == 'dataframe':
# dataframe fill is optional ,by default we fill the dataframe with one column per key
if self.DATAFRAME_FILL in self.design_var_descriptor[elem]:
dataframe_fill = self.design_var_descriptor[elem][self.DATAFRAME_FILL]
else:
dataframe_fill = self.ONE_COLUMN_PER_KEY
index = self.design_var_descriptor[elem][self.INDEX]
index_name = self.design_var_descriptor[elem][self.INDEX_NAME]
if dataframe_fill == self.ONE_COLUMN_PER_KEY:
# for the method one column per key we create a dataframe if it does not exists
if self.design_var_descriptor[elem][self.OUT_NAME] not in self.output_dict.keys():
# init output dataframes with index

self.output_dict[out_name] = DataFrame({index_name: index})
# we use the key 'key' in the design_var_descriptor for the name of the column and the column to the dataframe
col_name = self.design_var_descriptor[elem]['key']
self.output_dict[out_name][col_name] = self.bspline_dict[elem]['eval_t']
elif dataframe_fill == self.ONE_COLUMN_FOR_KEY:

column_names = self.design_var_descriptor[elem][self.COLUMNS_NAMES]
# # create a dataframe using column_names, in this method the dataframe will ALWAYS have 2 columns
# first column will store the key
# second column the value

df_to_merge = DataFrame(
{index_name: index,
column_names[0]: self.design_var_descriptor[elem]['key'],
column_names[1]: self.bspline_dict[elem]['eval_t']})
# if the dataframe still not exists werite it
if self.design_var_descriptor[elem][self.OUT_NAME] not in self.output_dict.keys():
self.output_dict[out_name] = df_to_merge
# if it exists, concatenate it in order to have multiple lines in the dataframe for each key
else:
self.output_dict[out_name] = concat([self.output_dict[out_name], df_to_merge],
ignore_index=True)
else:
raise (ValueError('Output type not yet supported'))
Loading

0 comments on commit faf9ab7

Please sign in to comment.