pyfemtet 0.8.4__py3-none-any.whl → 0.8.6__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of pyfemtet might be problematic. Click here for more details.
- pyfemtet/__init__.py +1 -1
- pyfemtet/opt/_femopt.py +37 -10
- pyfemtet/opt/_femopt_core.py +63 -28
- pyfemtet/opt/_test_utils/record_history.py +23 -16
- pyfemtet/opt/interface/__init__.py +4 -1
- pyfemtet/opt/interface/_surrogate/_base.py +11 -11
- pyfemtet/opt/interface/_surrogate/_singletaskgp.py +4 -3
- pyfemtet/opt/prediction/single_task_gp.py +6 -4
- pyfemtet/opt/visualization/_base.py +12 -1
- pyfemtet/opt/visualization/_complex_components/control_femtet.py +7 -7
- pyfemtet/opt/visualization/_complex_components/main_graph.py +65 -29
- pyfemtet/opt/visualization/_complex_components/pm_graph.py +17 -16
- pyfemtet/opt/visualization/_process_monitor/application.py +20 -3
- pyfemtet/opt/visualization/_process_monitor/pages.py +2 -2
- pyfemtet/opt/visualization/result_viewer/pages.py +6 -6
- {pyfemtet-0.8.4.dist-info → pyfemtet-0.8.6.dist-info}/METADATA +1 -1
- {pyfemtet-0.8.4.dist-info → pyfemtet-0.8.6.dist-info}/RECORD +20 -20
- {pyfemtet-0.8.4.dist-info → pyfemtet-0.8.6.dist-info}/LICENSE +0 -0
- {pyfemtet-0.8.4.dist-info → pyfemtet-0.8.6.dist-info}/WHEEL +0 -0
- {pyfemtet-0.8.4.dist-info → pyfemtet-0.8.6.dist-info}/entry_points.txt +0 -0
pyfemtet/__init__.py
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
__version__ = "0.8.
|
|
1
|
+
__version__ = "0.8.6"
|
pyfemtet/opt/_femopt.py
CHANGED
|
@@ -27,6 +27,7 @@ from pyfemtet.opt._femopt_core import (
|
|
|
27
27
|
History,
|
|
28
28
|
OptimizationStatus,
|
|
29
29
|
logger,
|
|
30
|
+
MonitorHostRecord,
|
|
30
31
|
)
|
|
31
32
|
from pyfemtet._message import Msg, encoding
|
|
32
33
|
from pyfemtet.opt.optimizer.parameter import Parameter, Expression
|
|
@@ -135,6 +136,7 @@ class FEMOpt:
|
|
|
135
136
|
self.monitor_process_future = None
|
|
136
137
|
self.monitor_server_kwargs = dict()
|
|
137
138
|
self.monitor_process_worker_name = None
|
|
139
|
+
self.monitor_host_record = None
|
|
138
140
|
self._hv_reference = None
|
|
139
141
|
self._extra_space_dir = None
|
|
140
142
|
|
|
@@ -403,7 +405,7 @@ class FEMOpt:
|
|
|
403
405
|
|
|
404
406
|
if names is not None:
|
|
405
407
|
if isinstance(names, str):
|
|
406
|
-
names = [f'
|
|
408
|
+
names = [f'{names}_{i}' for i in range(n_return)]
|
|
407
409
|
else:
|
|
408
410
|
# names = names
|
|
409
411
|
pass
|
|
@@ -679,11 +681,11 @@ class FEMOpt:
|
|
|
679
681
|
# ===== fem の設定 ==--=
|
|
680
682
|
|
|
681
683
|
# Femtet 特有の処理
|
|
682
|
-
|
|
684
|
+
extra_data = dict()
|
|
683
685
|
if isinstance(self.fem, FemtetInterface):
|
|
684
686
|
|
|
685
687
|
# 結果 csv に記載する femprj に関する情報の作成
|
|
686
|
-
|
|
688
|
+
extra_data.update(
|
|
687
689
|
dict(
|
|
688
690
|
femprj_path=self.fem.original_femprj_path,
|
|
689
691
|
model_name=self.fem.model_name
|
|
@@ -774,23 +776,25 @@ class FEMOpt:
|
|
|
774
776
|
|
|
775
777
|
with self.client.cluster as _cluster, self.client as _client:
|
|
776
778
|
|
|
777
|
-
# actor の設定
|
|
779
|
+
# ===== status actor の設定 =====
|
|
778
780
|
self.status = OptimizationStatus(_client, worker_address=self.monitor_process_worker_name)
|
|
779
781
|
self.worker_status_list = [OptimizationStatus(_client, worker_address=self.monitor_process_worker_name, name=name) for name in worker_addresses] # tqdm 検討
|
|
780
782
|
self.status.set(OptimizationStatus.SETTING_UP)
|
|
783
|
+
self.monitor_host_record = MonitorHostRecord(_client, self.monitor_process_worker_name)
|
|
784
|
+
logger.info('Status Actor initialized successfully.')
|
|
785
|
+
|
|
786
|
+
# ===== initialize history =====
|
|
781
787
|
self.history = History(
|
|
782
788
|
self.history_path,
|
|
783
789
|
self.opt.variables.get_parameter_names(),
|
|
784
790
|
list(self.opt.objectives.keys()),
|
|
785
791
|
list(self.opt.constraints.keys()),
|
|
786
792
|
_client,
|
|
787
|
-
metadata,
|
|
788
793
|
self._hv_reference
|
|
789
794
|
)
|
|
790
|
-
logger.info('Status Actor initialized successfully.')
|
|
791
795
|
|
|
796
|
+
# ===== launch monitor =====
|
|
792
797
|
# launch monitor
|
|
793
|
-
# noinspection PyTypeChecker
|
|
794
798
|
self.monitor_process_future = _client.submit(
|
|
795
799
|
# func
|
|
796
800
|
_start_monitor_server,
|
|
@@ -799,6 +803,7 @@ class FEMOpt:
|
|
|
799
803
|
self.status,
|
|
800
804
|
worker_addresses,
|
|
801
805
|
self.worker_status_list,
|
|
806
|
+
self.monitor_host_record,
|
|
802
807
|
# kwargs
|
|
803
808
|
**self.monitor_server_kwargs,
|
|
804
809
|
# kwargs of submit
|
|
@@ -807,6 +812,16 @@ class FEMOpt:
|
|
|
807
812
|
)
|
|
808
813
|
logger.info('Process monitor initialized successfully.')
|
|
809
814
|
|
|
815
|
+
# update extra_data of history to notify
|
|
816
|
+
# how to emit interruption signal by
|
|
817
|
+
# external processes
|
|
818
|
+
start = time()
|
|
819
|
+
while len(self.monitor_host_record.get()) == 0:
|
|
820
|
+
sleep(0.1)
|
|
821
|
+
extra_data.update(self.monitor_host_record.get())
|
|
822
|
+
self.history.extra_data.update(extra_data)
|
|
823
|
+
|
|
824
|
+
# ===== setup fem and opt before parallelization =====
|
|
810
825
|
# fem
|
|
811
826
|
self.fem._setup_before_parallel(_client)
|
|
812
827
|
|
|
@@ -817,6 +832,11 @@ class FEMOpt:
|
|
|
817
832
|
self.opt.history = self.history
|
|
818
833
|
self.opt._setup_before_parallel()
|
|
819
834
|
|
|
835
|
+
# ===== 最適化ループ開始 =====
|
|
836
|
+
# opt から non-serializable な com を
|
|
837
|
+
# 有している可能性のある fem を削除
|
|
838
|
+
# ただし main process の sub thread では
|
|
839
|
+
# これをそのまま使うので buff に退避
|
|
820
840
|
buff = self.opt.fem
|
|
821
841
|
del self.opt.fem
|
|
822
842
|
|
|
@@ -832,8 +852,12 @@ class FEMOpt:
|
|
|
832
852
|
allow_other_workers=False,
|
|
833
853
|
)
|
|
834
854
|
|
|
855
|
+
# 退避した fem を戻す
|
|
835
856
|
self.opt.fem = buff
|
|
836
857
|
|
|
858
|
+
# リモートクラスタではない場合
|
|
859
|
+
# main process の sub thread で
|
|
860
|
+
# 計算開始
|
|
837
861
|
t_main = None
|
|
838
862
|
if not self.opt.is_cluster:
|
|
839
863
|
# ローカルプロセスでの計算(opt._run 相当の処理)
|
|
@@ -857,7 +881,7 @@ class FEMOpt:
|
|
|
857
881
|
)
|
|
858
882
|
t_main.start()
|
|
859
883
|
|
|
860
|
-
# save history
|
|
884
|
+
# ===== save history during optimization =====
|
|
861
885
|
def save_history():
|
|
862
886
|
while True:
|
|
863
887
|
sleep(2)
|
|
@@ -872,7 +896,6 @@ class FEMOpt:
|
|
|
872
896
|
t_save_history.start()
|
|
873
897
|
|
|
874
898
|
# ===== 終了 =====
|
|
875
|
-
|
|
876
899
|
# クラスターの Unexpected Exception のリストを取得
|
|
877
900
|
opt_exceptions: list[Exception or None] = _client.gather(calc_futures) # gather() で終了待ちも兼ねる
|
|
878
901
|
|
|
@@ -884,7 +907,7 @@ class FEMOpt:
|
|
|
884
907
|
local_opt_exception = self.opt._exception # Exception を取得
|
|
885
908
|
opt_exceptions.append(local_opt_exception)
|
|
886
909
|
|
|
887
|
-
#
|
|
910
|
+
# 終了シグナルを送る
|
|
888
911
|
self.status.set(OptimizationStatus.TERMINATED)
|
|
889
912
|
end = time()
|
|
890
913
|
|
|
@@ -910,6 +933,8 @@ class FEMOpt:
|
|
|
910
933
|
print()
|
|
911
934
|
|
|
912
935
|
# monitor worker を残してユーザーが結果を確認できるようにする
|
|
936
|
+
# with 文を抜けると monitor worker が終了して
|
|
937
|
+
# daemon thread である run_forever が終了する
|
|
913
938
|
if confirm_before_exit:
|
|
914
939
|
print()
|
|
915
940
|
print('='*len(Msg.CONFIRM_BEFORE_EXIT))
|
|
@@ -945,6 +970,7 @@ def _start_monitor_server(
|
|
|
945
970
|
status,
|
|
946
971
|
worker_addresses,
|
|
947
972
|
worker_status_list,
|
|
973
|
+
host_record,
|
|
948
974
|
host=None,
|
|
949
975
|
port=None,
|
|
950
976
|
):
|
|
@@ -955,5 +981,6 @@ def _start_monitor_server(
|
|
|
955
981
|
worker_status_list,
|
|
956
982
|
host,
|
|
957
983
|
port,
|
|
984
|
+
host_record,
|
|
958
985
|
)
|
|
959
986
|
return 'Exit monitor server process gracefully'
|
pyfemtet/opt/_femopt_core.py
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
# typing
|
|
2
|
+
import json
|
|
2
3
|
from typing import List, TYPE_CHECKING
|
|
3
4
|
|
|
4
5
|
# built-in
|
|
@@ -524,7 +525,6 @@ class History:
|
|
|
524
525
|
obj_names (List[str], optional): The names of objectives. Defaults to None.
|
|
525
526
|
cns_names (List[str], optional): The names of constraints. Defaults to None.
|
|
526
527
|
client (dask.distributed.Client): Dask client.
|
|
527
|
-
additional_metadata (str, optional): metadata of optimization process.
|
|
528
528
|
hv_reference (str or list[float or np.ndarray, optional):
|
|
529
529
|
The method to calculate hypervolume or
|
|
530
530
|
the reference point itself.
|
|
@@ -550,7 +550,6 @@ class History:
|
|
|
550
550
|
obj_names=None,
|
|
551
551
|
cns_names=None,
|
|
552
552
|
client=None,
|
|
553
|
-
additional_metadata=None,
|
|
554
553
|
hv_reference=None,
|
|
555
554
|
):
|
|
556
555
|
# hypervolume 計算メソッド
|
|
@@ -561,7 +560,8 @@ class History:
|
|
|
561
560
|
self.prm_names = prm_names
|
|
562
561
|
self.obj_names = obj_names
|
|
563
562
|
self.cns_names = cns_names
|
|
564
|
-
self.
|
|
563
|
+
self.extra_data = dict()
|
|
564
|
+
self.meta_columns = None
|
|
565
565
|
self.__scheduler_address = client.scheduler.address if client is not None else None
|
|
566
566
|
|
|
567
567
|
# 最適化実行中かどうか
|
|
@@ -575,15 +575,15 @@ class History:
|
|
|
575
575
|
|
|
576
576
|
# 続きからなら df を読み込んで df にコピー
|
|
577
577
|
if self.is_restart:
|
|
578
|
-
self.load()
|
|
578
|
+
self.load() # 中で meta_columns を読む
|
|
579
579
|
|
|
580
580
|
# そうでなければ df を初期化
|
|
581
581
|
else:
|
|
582
|
-
columns,
|
|
582
|
+
columns, meta_columns = self.create_df_columns()
|
|
583
583
|
df = pd.DataFrame()
|
|
584
584
|
for c in columns:
|
|
585
585
|
df[c] = None
|
|
586
|
-
self.
|
|
586
|
+
self.meta_columns = meta_columns
|
|
587
587
|
self.set_df(df)
|
|
588
588
|
|
|
589
589
|
# 一時ファイルに書き込みを試み、UnicodeEncodeError が出ないかチェック
|
|
@@ -609,16 +609,16 @@ class History:
|
|
|
609
609
|
# df を読み込む
|
|
610
610
|
df = pd.read_csv(self.path, encoding=self.ENCODING, header=self.HEADER_ROW)
|
|
611
611
|
|
|
612
|
-
#
|
|
612
|
+
# meta_columns を読み込む
|
|
613
613
|
with open(self.path, mode='r', encoding=self.ENCODING, newline='\n') as f:
|
|
614
614
|
reader = csv.reader(f, delimiter=',')
|
|
615
|
-
self.
|
|
615
|
+
self.meta_columns = reader.__next__()
|
|
616
616
|
|
|
617
617
|
# 最適化問題を読み込む
|
|
618
618
|
columns = df.columns
|
|
619
|
-
prm_names = [column for i, column in enumerate(columns) if self.
|
|
620
|
-
obj_names = [column for i, column in enumerate(columns) if self.
|
|
621
|
-
cns_names = [column for i, column in enumerate(columns) if self.
|
|
619
|
+
prm_names = [column for i, column in enumerate(columns) if self.meta_columns[i] == 'prm']
|
|
620
|
+
obj_names = [column for i, column in enumerate(columns) if self.meta_columns[i] == 'obj']
|
|
621
|
+
cns_names = [column for i, column in enumerate(columns) if self.meta_columns[i] == 'cns']
|
|
622
622
|
|
|
623
623
|
# is_restart の場合、読み込んだ names と引数の names が一致するか確認しておく
|
|
624
624
|
if self.is_restart:
|
|
@@ -662,7 +662,7 @@ class History:
|
|
|
662
662
|
logger.debug('Access df of History before it is initialized.')
|
|
663
663
|
return pd.DataFrame()
|
|
664
664
|
except OSError:
|
|
665
|
-
logger.error('Scheduler is already dead. Most frequent
|
|
665
|
+
logger.error('Scheduler is already dead. Most frequent reason to show this message is that the pyfemtet monitor UI is not refreshed even if the main optimization process is terminated.')
|
|
666
666
|
return pd.DataFrame()
|
|
667
667
|
|
|
668
668
|
def set_df(self, df: pd.DataFrame):
|
|
@@ -687,46 +687,46 @@ class History:
|
|
|
687
687
|
columns = list()
|
|
688
688
|
|
|
689
689
|
# columns のメタデータを作成
|
|
690
|
-
|
|
690
|
+
meta_columns = list()
|
|
691
691
|
|
|
692
692
|
# trial
|
|
693
693
|
columns.append('trial') # index
|
|
694
|
-
|
|
694
|
+
meta_columns.append('') # extra_data. save 時に中身を記入する。
|
|
695
695
|
|
|
696
696
|
# parameter
|
|
697
697
|
for prm_name in self.prm_names:
|
|
698
698
|
columns.extend([prm_name, prm_name + '_lower_bound', prm_name + '_upper_bound'])
|
|
699
|
-
|
|
699
|
+
meta_columns.extend(['prm', 'prm_lb', 'prm_ub'])
|
|
700
700
|
|
|
701
701
|
# objective relative
|
|
702
702
|
for name in self.obj_names:
|
|
703
703
|
columns.append(name)
|
|
704
|
-
|
|
704
|
+
meta_columns.append('obj')
|
|
705
705
|
columns.append(name + '_direction')
|
|
706
|
-
|
|
706
|
+
meta_columns.append('obj_direction')
|
|
707
707
|
columns.append('non_domi')
|
|
708
|
-
|
|
708
|
+
meta_columns.append('')
|
|
709
709
|
|
|
710
710
|
# constraint relative
|
|
711
711
|
for name in self.cns_names:
|
|
712
712
|
columns.append(name)
|
|
713
|
-
|
|
713
|
+
meta_columns.append('cns')
|
|
714
714
|
columns.append(name + '_lower_bound')
|
|
715
|
-
|
|
715
|
+
meta_columns.append('cns_lb')
|
|
716
716
|
columns.append(name + '_upper_bound')
|
|
717
|
-
|
|
717
|
+
meta_columns.append('cns_ub')
|
|
718
718
|
columns.append('feasible')
|
|
719
|
-
|
|
719
|
+
meta_columns.append('')
|
|
720
720
|
|
|
721
721
|
# the others
|
|
722
722
|
columns.append('hypervolume')
|
|
723
|
-
|
|
723
|
+
meta_columns.append('')
|
|
724
724
|
columns.append('message')
|
|
725
|
-
|
|
725
|
+
meta_columns.append('')
|
|
726
726
|
columns.append('time')
|
|
727
|
-
|
|
727
|
+
meta_columns.append('')
|
|
728
728
|
|
|
729
|
-
return columns,
|
|
729
|
+
return columns, meta_columns
|
|
730
730
|
|
|
731
731
|
def record(
|
|
732
732
|
self,
|
|
@@ -973,13 +973,16 @@ class History:
|
|
|
973
973
|
|
|
974
974
|
df = self.get_df()
|
|
975
975
|
|
|
976
|
+
# extra_data の更新
|
|
977
|
+
self.meta_columns[0] = json.dumps(self.extra_data)
|
|
978
|
+
|
|
976
979
|
if _f is None:
|
|
977
980
|
# save df with columns with prefix
|
|
978
981
|
with open(self.path, 'w', encoding=self.ENCODING) as f:
|
|
979
982
|
writer = csv.writer(f, delimiter=',', lineterminator="\n")
|
|
980
|
-
writer.writerow(self.
|
|
983
|
+
writer.writerow(self.meta_columns)
|
|
981
984
|
for i in range(self.HEADER_ROW-1):
|
|
982
|
-
writer.writerow([''] * len(self.
|
|
985
|
+
writer.writerow([''] * len(self.meta_columns))
|
|
983
986
|
df.to_csv(f, index=None, encoding=self.ENCODING, lineterminator='\n')
|
|
984
987
|
else: # test
|
|
985
988
|
df.to_csv(_f, index=None, encoding=self.ENCODING, lineterminator='\n')
|
|
@@ -1088,3 +1091,35 @@ class OptimizationStatus:
|
|
|
1088
1091
|
def get_text(self) -> str:
|
|
1089
1092
|
"""Get optimization status message."""
|
|
1090
1093
|
return self._actor.status
|
|
1094
|
+
|
|
1095
|
+
|
|
1096
|
+
class _MonitorHostRecordActor:
|
|
1097
|
+
host = None
|
|
1098
|
+
port = None
|
|
1099
|
+
|
|
1100
|
+
def set(self, host, port):
|
|
1101
|
+
self.host = host
|
|
1102
|
+
self.port = port
|
|
1103
|
+
|
|
1104
|
+
|
|
1105
|
+
class MonitorHostRecord:
|
|
1106
|
+
|
|
1107
|
+
def __init__(self, client, worker_name):
|
|
1108
|
+
self._future = client.submit(
|
|
1109
|
+
_MonitorHostRecordActor,
|
|
1110
|
+
actor=True,
|
|
1111
|
+
workers=(worker_name,),
|
|
1112
|
+
allow_other_workers=False,
|
|
1113
|
+
)
|
|
1114
|
+
self._actor = self._future.result()
|
|
1115
|
+
|
|
1116
|
+
def set(self, host, port):
|
|
1117
|
+
self._actor.set(host, port).result()
|
|
1118
|
+
|
|
1119
|
+
def get(self):
|
|
1120
|
+
host = self._actor.host
|
|
1121
|
+
port = self._actor.port
|
|
1122
|
+
if host is None and port is None:
|
|
1123
|
+
return dict()
|
|
1124
|
+
else:
|
|
1125
|
+
return dict(host=host, port=port)
|
|
@@ -10,7 +10,7 @@ from pyfemtet.opt import FEMOpt
|
|
|
10
10
|
from pyfemtet._message import encoding as ENCODING
|
|
11
11
|
|
|
12
12
|
|
|
13
|
-
def
|
|
13
|
+
def remove_extra_data_from_csv(csv_path, encoding=ENCODING):
|
|
14
14
|
|
|
15
15
|
with open(csv_path, mode="r", encoding=encoding, newline="\n") as f:
|
|
16
16
|
reader = csv.reader(f, delimiter=",")
|
|
@@ -59,32 +59,39 @@ def _get_obj_from_csv(csv_path, encoding=ENCODING):
|
|
|
59
59
|
reader = csv.reader(f, delimiter=",")
|
|
60
60
|
meta = reader.__next__()
|
|
61
61
|
obj_indices = np.where(np.array(meta) == "obj")[0]
|
|
62
|
-
out = df.iloc[:, obj_indices]
|
|
62
|
+
out: pd.DataFrame = df.iloc[:, obj_indices]
|
|
63
|
+
out = out.dropna(axis=0)
|
|
63
64
|
return out, columns
|
|
64
65
|
|
|
65
66
|
|
|
66
|
-
def is_equal_result(ref_path, dif_path, log_path):
|
|
67
|
+
def is_equal_result(ref_path, dif_path, log_path=None, threashold=0.05):
|
|
67
68
|
"""Check the equality of two result csv files."""
|
|
68
69
|
ref_df, ref_columns = _get_obj_from_csv(ref_path)
|
|
69
70
|
dif_df, dif_columns = _get_obj_from_csv(dif_path)
|
|
70
71
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
72
|
+
if log_path is not None:
|
|
73
|
+
with open(log_path, "a", newline="\n", encoding=ENCODING) as f:
|
|
74
|
+
f.write("\n\n===== 結果の分析 =====\n\n")
|
|
75
|
+
f.write(f" \tref\tdif\n")
|
|
76
|
+
f.write(f"---------------------\n")
|
|
77
|
+
f.write(f"len(col)\t{len(ref_columns)}\t{len(dif_columns)}\n")
|
|
78
|
+
f.write(f"len(df) \t{len(ref_df)}\t{len(dif_df)}\n")
|
|
79
|
+
try:
|
|
80
|
+
difference = (
|
|
81
|
+
np.abs(ref_df.values - dif_df.values) / np.abs(dif_df.values)
|
|
82
|
+
).mean()
|
|
83
|
+
f.write(f"diff \t{int(difference*100)}%\n")
|
|
84
|
+
except Exception:
|
|
85
|
+
f.write(f"diff \tcannot calc\n")
|
|
86
|
+
|
|
87
|
+
else:
|
|
88
|
+
difference = (
|
|
79
89
|
np.abs(ref_df.values - dif_df.values) / np.abs(dif_df.values)
|
|
80
|
-
|
|
81
|
-
f.write(f"diff \t{int(difference*100)}%\n")
|
|
82
|
-
except Exception:
|
|
83
|
-
f.write(f"diff \tcannot calc\n")
|
|
90
|
+
).mean()
|
|
84
91
|
|
|
85
92
|
assert len(ref_columns) == len(dif_columns), "結果 csv の column 数が異なります。"
|
|
86
93
|
assert len(ref_df) == len(dif_df), "結果 csv の row 数が異なります。"
|
|
87
|
-
assert difference <=
|
|
94
|
+
assert difference <= threashold*100, f"前回の結果との平均差異が {int(difference)}% で {int(threashold*100)}% を超えています。"
|
|
88
95
|
|
|
89
96
|
|
|
90
97
|
def _get_simplified_df_values(csv_path, exclude_columns=None):
|
|
@@ -21,7 +21,9 @@ else:
|
|
|
21
21
|
FemtetWithNXInterface = type('FemtetWithNXInterface', (FemtetInterface,), {})
|
|
22
22
|
ExcelInterface = type('FemtetInterface', (NotAvailableForWindows,), {})
|
|
23
23
|
|
|
24
|
-
from pyfemtet.opt.interface._surrogate import
|
|
24
|
+
from pyfemtet.opt.interface._surrogate._base import SurrogateModelInterfaceBase
|
|
25
|
+
from pyfemtet.opt.interface._surrogate._singletaskgp import PoFBoTorchInterface
|
|
26
|
+
|
|
25
27
|
|
|
26
28
|
__all__ =[
|
|
27
29
|
'FEMInterface',
|
|
@@ -30,5 +32,6 @@ __all__ =[
|
|
|
30
32
|
'FemtetWithSolidworksInterface',
|
|
31
33
|
'FemtetWithNXInterface',
|
|
32
34
|
'ExcelInterface',
|
|
35
|
+
'SurrogateModelInterfaceBase',
|
|
33
36
|
'PoFBoTorchInterface',
|
|
34
37
|
]
|
|
@@ -17,6 +17,7 @@ class SurrogateModelInterfaceBase(FEMInterface, ABC):
|
|
|
17
17
|
self,
|
|
18
18
|
history_path: str = None,
|
|
19
19
|
history: History = None,
|
|
20
|
+
override_objective: bool = True,
|
|
20
21
|
):
|
|
21
22
|
|
|
22
23
|
self.history: History
|
|
@@ -25,6 +26,7 @@ class SurrogateModelInterfaceBase(FEMInterface, ABC):
|
|
|
25
26
|
self.obj: dict[str, float] = dict()
|
|
26
27
|
self.df_prm: pd.DataFrame
|
|
27
28
|
self.df_obj: pd.DataFrame
|
|
29
|
+
self.override_objective: bool = override_objective
|
|
28
30
|
|
|
29
31
|
# history_path が与えられた場合、history をコンストラクトする
|
|
30
32
|
if history_path is not None:
|
|
@@ -57,27 +59,25 @@ class SurrogateModelInterfaceBase(FEMInterface, ABC):
|
|
|
57
59
|
FEMInterface.__init__(
|
|
58
60
|
self,
|
|
59
61
|
history=history, # コンストラクト済み history を渡せば並列計算時も何もしなくてよい
|
|
62
|
+
override_objective=self.override_objective
|
|
60
63
|
)
|
|
61
64
|
|
|
62
65
|
def filter_feasible(self, x: np.ndarray, y: np.ndarray, return_feasibility=False):
|
|
63
66
|
feasible_idx = np.where(~np.isnan(y.sum(axis=1)))
|
|
64
67
|
if return_feasibility:
|
|
65
68
|
# calculated or not
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
infeasible_idx = np.where(~self.history.get_df()['feasible'].values)
|
|
70
|
-
y[infeasible_idx] = .0
|
|
71
|
-
return x, y.reshape((-1, 1))
|
|
69
|
+
feas = np.zeros((len(y), 1), dtype=float)
|
|
70
|
+
feas[feasible_idx] = 1.
|
|
71
|
+
return x, feas
|
|
72
72
|
else:
|
|
73
73
|
return x[feasible_idx], y[feasible_idx]
|
|
74
74
|
|
|
75
75
|
def _setup_after_parallel(self, *args, **kwargs):
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
76
|
+
if self.override_objective:
|
|
77
|
+
opt: AbstractOptimizer = kwargs['opt']
|
|
78
|
+
obj: Objective
|
|
79
|
+
for obj_name, obj in opt.objectives.items():
|
|
80
|
+
obj.fun = lambda obj_name_=obj_name: self.obj[obj_name_]
|
|
81
81
|
|
|
82
82
|
def update_parameter(self, parameters: pd.DataFrame, with_warning=False) -> Optional[List[str]]:
|
|
83
83
|
for i, row in parameters.iterrows():
|
|
@@ -27,8 +27,8 @@ class PoFBoTorchInterface(SurrogateModelInterfaceBase):
|
|
|
27
27
|
def train_f(self):
|
|
28
28
|
# df そのまま用いて training する
|
|
29
29
|
x, y = self.filter_feasible(self.df_prm.values, self.df_obj.values, return_feasibility=True)
|
|
30
|
-
if y.min() == 1:
|
|
31
|
-
self.model_f.predict = lambda *args, **kwargs: (1., 0.001)
|
|
30
|
+
if y.min() == 1: # feasible values only
|
|
31
|
+
self.model_f.predict = lambda *args, **kwargs: (1., 0.001) # mean, std
|
|
32
32
|
self.model_f.fit(x, y)
|
|
33
33
|
|
|
34
34
|
def _setup_after_parallel(self, *args, **kwargs):
|
|
@@ -64,7 +64,8 @@ class PoFBoTorchInterface(SurrogateModelInterfaceBase):
|
|
|
64
64
|
raise SolveError(Msg.INFO_POF_IS_LESS_THAN_THRESHOLD)
|
|
65
65
|
|
|
66
66
|
# 実際の計算(mean は history.obj_names 順)
|
|
67
|
-
|
|
67
|
+
_mean, _std = self.model.predict(np.array([x]))
|
|
68
|
+
mean = _mean[0]
|
|
68
69
|
|
|
69
70
|
# 目的関数の更新
|
|
70
71
|
self.obj = {obj_name: value for obj_name, value in zip(self.history.obj_names, mean)}
|
|
@@ -42,16 +42,16 @@ class SingleTaskGPModel(PredictionModelBase):
|
|
|
42
42
|
def set_bounds_from_history(self, history, df=None):
|
|
43
43
|
from pyfemtet.opt._femopt_core import History
|
|
44
44
|
history: History
|
|
45
|
-
|
|
45
|
+
meta_column: str
|
|
46
46
|
|
|
47
47
|
if df is None:
|
|
48
48
|
df = history.get_df()
|
|
49
49
|
|
|
50
50
|
columns = df.columns
|
|
51
|
-
|
|
51
|
+
|
|
52
52
|
target_columns = [
|
|
53
|
-
col for col,
|
|
54
|
-
if
|
|
53
|
+
col for col, meta_column in zip(columns, history.meta_columns)
|
|
54
|
+
if meta_column == 'prm_lb' or meta_column == 'prm_ub'
|
|
55
55
|
]
|
|
56
56
|
|
|
57
57
|
bounds_buff = df.iloc[0][target_columns].values # 2*len(prm_names) array
|
|
@@ -85,6 +85,8 @@ class SingleTaskGPModel(PredictionModelBase):
|
|
|
85
85
|
fit_gpytorch_mll(mll)
|
|
86
86
|
|
|
87
87
|
def predict(self, x: np.ndarray) -> tuple[np.ndarray, np.ndarray]:
|
|
88
|
+
assert len(x.shape) >= 2
|
|
89
|
+
|
|
88
90
|
X = tensor(x)
|
|
89
91
|
|
|
90
92
|
post = self.gp.posterior(X)
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
from dash.development.base_component import Component
|
|
3
3
|
|
|
4
4
|
# application
|
|
5
|
+
from flask import Flask
|
|
5
6
|
from dash import Dash
|
|
6
7
|
import webbrowser
|
|
7
8
|
|
|
@@ -20,6 +21,7 @@ from pyfemtet.opt.visualization._wrapped_components import html, dcc, dbc
|
|
|
20
21
|
from abc import ABC, abstractmethod
|
|
21
22
|
import logging
|
|
22
23
|
import psutil
|
|
24
|
+
import json
|
|
23
25
|
from pyfemtet.logger import get_module_logger, get_dash_logger
|
|
24
26
|
|
|
25
27
|
logger = get_module_logger('opt.monitor', __name__)
|
|
@@ -132,15 +134,19 @@ class SidebarApplicationBase:
|
|
|
132
134
|
# define app
|
|
133
135
|
self.title = title if title is not None else 'App'
|
|
134
136
|
self.subtitle = subtitle if title is not None else ''
|
|
137
|
+
self.server = Flask(__name__)
|
|
135
138
|
self.app = Dash(
|
|
136
139
|
__name__,
|
|
137
140
|
external_stylesheets=[dash_bootstrap_components.themes.BOOTSTRAP],
|
|
138
141
|
title=title,
|
|
139
142
|
update_title=None,
|
|
143
|
+
server=self.server,
|
|
140
144
|
)
|
|
141
145
|
self.pages = dict()
|
|
142
146
|
self.nav_links = dict()
|
|
143
147
|
self.page_objects = []
|
|
148
|
+
self.host = None
|
|
149
|
+
self.port = None
|
|
144
150
|
|
|
145
151
|
def add_page(self, page: AbstractPage, order: int = None):
|
|
146
152
|
page.set_application(self)
|
|
@@ -191,7 +197,7 @@ class SidebarApplicationBase:
|
|
|
191
197
|
className="p-3 bg-light rounded-3",
|
|
192
198
|
)
|
|
193
199
|
|
|
194
|
-
def run(self, host='localhost', port=None, debug=False):
|
|
200
|
+
def run(self, host='localhost', port=None, debug=False, host_record=None):
|
|
195
201
|
self._setup_layout()
|
|
196
202
|
port = port or self.DEFAULT_PORT
|
|
197
203
|
# port を検証
|
|
@@ -201,6 +207,11 @@ class SidebarApplicationBase:
|
|
|
201
207
|
webbrowser.open(f'http://localhost:{str(port)}')
|
|
202
208
|
else:
|
|
203
209
|
webbrowser.open(f'http://{host}:{str(port)}')
|
|
210
|
+
self.host = host
|
|
211
|
+
self.port = port
|
|
212
|
+
if host_record is not None:
|
|
213
|
+
host_record.set(self.host, self.port)
|
|
214
|
+
|
|
204
215
|
self.app.run(debug=debug, host=host, port=port)
|
|
205
216
|
|
|
206
217
|
|
|
@@ -138,18 +138,18 @@ class FemtetControl(AbstractPage):
|
|
|
138
138
|
|
|
139
139
|
# check holding history
|
|
140
140
|
if self.application.history is None:
|
|
141
|
-
return kwargs, Msg.
|
|
141
|
+
return kwargs, Msg.WARN_HISTORY_CSV_NOT_READ
|
|
142
142
|
|
|
143
|
-
# get
|
|
144
|
-
|
|
143
|
+
# get extra_data
|
|
144
|
+
extra_data = self.application.history.meta_columns[0]
|
|
145
145
|
|
|
146
|
-
# check
|
|
147
|
-
if
|
|
146
|
+
# check extra_data exists
|
|
147
|
+
if extra_data == '':
|
|
148
148
|
return kwargs, Msg.WARN_INVALID_METADATA
|
|
149
149
|
|
|
150
|
-
# check the
|
|
150
|
+
# check the extra_data is valid json
|
|
151
151
|
try:
|
|
152
|
-
d = json.loads(
|
|
152
|
+
d = json.loads(extra_data)
|
|
153
153
|
femprj_path = os.path.abspath(d['femprj_path'])
|
|
154
154
|
except (TypeError, json.decoder.JSONDecodeError, KeyError):
|
|
155
155
|
return kwargs, Msg.WARN_INVALID_METADATA
|
|
@@ -447,17 +447,50 @@ class MainGraph(AbstractPage):
|
|
|
447
447
|
Output(self.tooltip.id, "show"),
|
|
448
448
|
Output(self.tooltip.id, "bbox"),
|
|
449
449
|
Output(self.tooltip.id, "children"),
|
|
450
|
-
|
|
451
|
-
|
|
450
|
+
Output(self.tooltip.id, "direction"),
|
|
451
|
+
Input(self.graph.id, "hoverData"),
|
|
452
|
+
State(self.graph.id, "figure"),
|
|
453
|
+
)
|
|
454
|
+
def show_hover(hoverData, figure):
|
|
452
455
|
if hoverData is None:
|
|
453
|
-
return False, no_update, no_update
|
|
456
|
+
return False, no_update, no_update, no_update
|
|
454
457
|
|
|
455
458
|
if self.application.history is None:
|
|
456
459
|
raise PreventUpdate
|
|
457
460
|
|
|
458
|
-
#
|
|
461
|
+
# pt = {'curveNumber': 1, 'pointNumber': 0, 'pointIndex': 0, 'x': 1, 'y': 2369132.929996869, 'bbox': {'x0': 341.5, 'x1': 350.5, 'y0': 235, 'y1': 244}, 'customdata': [1]}
|
|
462
|
+
# bbox = {'x0': 341.5, 'x1': 350.5, 'y0': 235, 'y1': 244} # point の大きさ?
|
|
463
|
+
# figure = {'data': [{'customdata': [[1], [2], [3], [4], [5]], 'marker': {'color': '#6c757d', 'size': 6}, 'mode': 'markers', 'name': 'すべての解', 'x': [1, 2, 3, 4, 5], 'y': [2369132.929996866, 5797829.746579617, 1977631.590419346, 2083867.2403273676, 1539203.6452652698], 'type': 'scatter', 'hoverinfo': 'none'}, {'customdata': [[1], [3], [5]], 'legendgroup': 'optimal', 'line': {'color': '#6c757d', 'width': 1}, 'marker': {'color': '#007bff', 'size': 9}, 'mode': 'markers+lines', 'name': '最適解の推移', 'x': [1, 3, 5], 'y': [2369132.929996866, 1977631.590419346, 1539203.6452652698], 'type': 'scatter', 'hoverinfo': 'none'}, {'legendgroup': 'optimal', 'line': {'color': '#6c757d', 'dash': 'dash', 'width': 0.5}, 'mode': 'lines', 'showlegend': False, 'x': [5, 5], 'y': [1539203.6452652698, 1539203.6452652698], 'type': 'scatter', 'hoverinfo': 'none'}], 'layout': {'template': {'data': {'histogram2dcontour': [{'type': 'histogram2dcontour', 'colorbar': {'outlinewidth': 0, 'ticks': ''}, 'colorscale': [[0, '#0d0887'], [0.1111111111111111, '#46039f'], [0.2222222222222222, '#7201a8'], [0.3333333333333333, '#9c179e'], [0.4444444444444444, '#bd3786'], [0.5555555555555556, '#d8576b'], [0.6666666666666666, '#ed7953'], [0.7777777777777778, '#fb9f3a'], [0.8888888888888888, '#fdca26'], [1, '#f0f921']]}], 'choropleth': [{'type': 'choropleth', 'colorbar': {'outlinewidth': 0, 'ticks': ''}}], 'histogram2d': [{'type': 'histogram2d', 'colorbar': {'outlinewidth': 0, 'ticks': ''}, 'colorscale': [[0, '#0d0887'], [0.1111111111111111, '#46039f'], [0.2222222222222222, '#7201a8'], [0.3333333333333333, '#9c179e'], [0.4444444444444444, '#bd3786'], [0.5555555555555556, '#d8576b'], [0.6666666666666666, '#ed7953'], [0.7777777777777778, '#fb9f3a'], [0.8888888888888888, '#fdca26'], [1, '#f0f921']]}], 'heatmap': [{'type': 'heatmap', 'colorbar': {'outlinewidth': 0, 'ticks': ''}, 'colorscale': [[0, '#0d0887'], [0.1111111111111111, '#46039f'], [0.2222222222222222, '#7201a8'], [0.3333333333333333, '#9c179e'], [0.4444444444444444, '#bd3786'], [0.5555555555555556, '#d8576b'], [0.6666666666666666, '#ed7953'], [0.7777777777777778, '#fb9f3a'], [0.8888888888888888, '#fdca26'], [1, '#f0f921']]}], 'heatmapgl': [{'type': 'heatmapgl', 'colorbar': {'outlinewidth': 0, 'ticks': ''}, 'colorscale': [[0, '#0d0887'], [0.1111111111111111, '#46039f'], [0.2222222222222222, '#7201a8'], [0.3333333333333333, '#9c179e'], [0.4444444444444444, '#bd3786'], [0.5555555555555556, '#d8576b'], [0.6666666666666666, '#ed7953'], [0.7777777777777778, '#fb9f3a'], [0.8888888888888888, '#fdca26'], [1, '#f0f921']]}], 'contourcarpet': [{'type': 'contourcarpet', 'colorbar': {'outlinewidth': 0, 'ticks': ''}}], 'contour': [{'type': 'contour', 'colorbar': {'outlinewidth': 0, 'ticks': ''}, 'colorscale': [[0, '#0d0887'], [0.1111111111111111, '#46039f'], [0.2222222222222222, '#7201a8'], [0.3333333333333333, '#9c179e'], [0.4444444444444444, '#bd3786'], [0.5555555555555556, '#d8576b'], [0.6666666666666666, '#ed7953'], [0.7777777777777778, '#fb9f3a'], [0.8888888888888888, '#fdca26'], [1, '#f0f921']]}], 'surface': [{'type': 'surface', 'colorbar': {'outlinewidth': 0, 'ticks': ''}, 'colorscale': [[0, '#0d0887'], [0.1111111111111111, '#46039f'], [0.2222222222222222, '#7201a8'], [0.3333333333333333, '#9c179e'], [0.4444444444444444, '#bd3786'], [0.5555555555555556, '#d8576b'], [0.6666666666666666, '#ed7953'], [0.7777777777777778, '#fb9f3a'], [0.8888888888888888, '#fdca26'], [1, '#f0f921']]}], 'mesh3d': [{'type': 'mesh3d', 'colorbar': {'outlinewidth': 0, 'ticks': ''}}], 'scatter': [{'fillpattern': {'fillmode': 'overlay', 'size': 10, 'solidity': 0.2}, 'type': 'scatter'}], 'parcoords': [{'type': 'parcoords', 'line': {'colorbar': {'outlinewidth': 0, 'ticks': ''}}}], 'scatterpolargl': [{'type': 'scatterpolargl', 'marker': {'colorbar': {'outlinewidth': 0, 'ticks': ''}}}], 'bar': [{'error_x': {'color': '#2a3f5f'}, 'error_y': {'color': '#2a3f5f'}, 'marker': {'line': {'color': '#E5ECF6', 'width': 0.5}, 'pattern': {'fillmode': 'overlay', 'size': 10, 'solidity': 0.2}}, 'type': 'bar'}], 'scattergeo': [{'type': 'scattergeo', 'marker': {'colorbar': {'outlinewidth': 0, 'ticks': ''}}}], 'scatterpolar': [{'type': 'scatterpolar', 'marker': {'colorbar': {'outlinewidth': 0, 'ticks': ''}}}], 'histogram': [{'marker': {'pattern': {'fillmode': 'overlay', 'size': 10, 'solidity': 0.2}}, 'type': 'histogram'}], 'scattergl': [{'type': 'scattergl', 'marker': {'colorbar': {'outlinewidth': 0, 'ticks': ''}}}], 'scatter3d': [{'type': 'scatter3d', 'line': {'colorbar': {'outlinewidth': 0, 'ticks': ''}}, 'marker': {'colorbar': {'outlinewidth': 0, 'ticks': ''}}}], 'scattermapbox': [{'type': 'scattermapbox', 'marker': {'colorbar': {'outlinewidth': 0, 'ticks': ''}}}], 'scatterternary': [{'type': 'scatterternary', 'marker': {'colorbar': {'outlinewidth': 0, 'ticks': ''}}}], 'scattercarpet': [{'type': 'scattercarpet', 'marker': {'colorbar': {'outlinewidth': 0, 'ticks': ''}}}], 'carpet': [{'aaxis': {'endlinecolor': '#2a3f5f', 'gridcolor': 'white', 'linecolor': 'white', 'minorgridcolor': 'white', 'startlinecolor': '#2a3f5f'}, 'baxis': {'endlinecolor': '#2a3f5f', 'gridcolor': 'white', 'linecolor': 'white', 'minorgridcolor': 'white', 'startlinecolor': '#2a3f5f'}, 'type': 'carpet'}], 'table': [{'cells': {'fill': {'color': '#EBF0F8'}, 'line': {'color': 'white'}}, 'header': {'fill': {'color': '#C8D4E3'}, 'line': {'color': 'white'}}, 'type': 'table'}], 'barpolar': [{'marker': {'line': {'color': '#E5ECF6', 'width': 0.5}, 'pattern': {'fillmode': 'overlay', 'size': 10, 'solidity': 0.2}}, 'type': 'barpolar'}], 'pie': [{'automargin': True, 'type': 'pie'}]}, 'layout': {'autotypenumbers': 'strict', 'colorway': ['#636efa', '#EF553B', '#00cc96', '#ab63fa', '#FFA15A', '#19d3f3', '#FF6692', '#B6E880', '#FF97FF', '#FECB52'], 'font': {'color': '#2a3f5f'}, 'hovermode': 'closest', 'hoverlabel': {'align': 'left'}, 'paper_bgcolor': 'white', 'plot_bgcolor': '#E5ECF6', 'polar': {'bgcolor': '#E5ECF6', 'angularaxis': {'gridcolor': 'white', 'linecolor': 'white', 'ticks': ''}, 'radialaxis': {'gridcolor': 'white', 'linecolor': 'white', 'ticks': ''}}, 'ternary': {'bgcolor': '#E5ECF6', 'aaxis': {'gridcolor': 'white', 'linecolor': 'white', 'ticks': ''}, 'baxis': {'gridcolor': 'white', 'linecolor': 'white', 'ticks': ''}, 'caxis': {'gridcolor': 'white', 'linecolor': 'white', 'ticks': ''}}, 'coloraxis': {'colorbar': {'outlinewidth': 0, 'ticks': ''}}, 'colorscale': {'sequential': [[0, '#0d0887'], [0.1111111111111111, '#46039f'], [0.2222222222222222, '#7201a8'], [0.3333333333333333, '#9c179e'], [0.4444444444444444, '#bd3786'], [0.5555555555555556, '#d8576b'], [0.6666666666666666, '#ed7953'], [0.7777777777777778, '#fb9f3a'], [0.8888888888888888, '#fdca26'], [1, '#f0f921']], 'sequentialminus': [[0, '#0d0887'], [0.1111111111111111, '#46039f'], [0.2222222222222222, '#7201a8'], [0.3333333333333333, '#9c179e'], [0.4444444444444444, '#bd3786'], [0.5555555555555556, '#d8576b'], [0.6666666666666666, '#ed7953'], [0.7777777777777778, '#fb9f3a'], [0.8888888888888888, '#fdca26'], [1, '#f0f921']], 'diverging': [[0, '#8e0152'], [0.1, '#c51b7d'], [0.2, '#de77ae'], [0.3, '#f1b6da'], [0.4, '#fde0ef'], [0.5, '#f7f7f7'], [0.6, '#e6f5d0'], [0.7, '#b8e186'], [0.8, '#7fbc41'], [0.9, '#4d9221'], [1, '#276419']]}, 'xaxis': {'gridcolor': 'white', 'linecolor': 'white', 'ticks': '', 'title': {'standoff': 15}, 'zerolinecolor': 'white', 'automargin': True, 'zerolinewidth': 2}, 'yaxis': {'gridcolor': 'white', 'linecolor': 'white', 'ticks': '', 'title': {'standoff': 15}, 'zerolinecolor': 'white', 'automargin': True, 'zerolinewidth': 2}, 'scene': {'xaxis': {'backgroundcolor': '#E5ECF6', 'gridcolor': 'white', 'linecolor': 'white', 'showbackground': True, 'ticks': '', 'zerolinecolor': 'white', 'gridwidth': 2}, 'yaxis': {'backgroundcolor': '#E5ECF6', 'gridcolor': 'white', 'linecolor': 'white', 'showbackground': True, 'ticks': '', 'zerolinecolor': 'white', 'gridwidth': 2}, 'zaxis': {'backgroundcolor': '#E5ECF6', 'gridcolor': 'white', 'linecolor': 'white', 'showbackground': True, 'ticks': '', 'zerolinecolor': 'white', 'gridwidth': 2}}, 'shapedefaults': {'line': {'color': '#2a3f5f'}}, 'annotationdefaults': {'arrowcolor': '#2a3f5f', 'arrowhead': 0, 'arrowwidth': 1}, 'geo': {'bgcolor': 'white', 'landcolor': '#E5ECF6', 'subunitcolor': 'white', 'showland': True, 'showlakes': True, 'lakecolor': 'white'}, 'title': {'x': 0.05}, 'mapbox': {'style': 'light'}}}, 'title': {'text': '目的関数プロット'}, 'xaxis': {'title': {'text': '成功した解析数'}, 'type': 'linear', 'range': [0.7173255954539959, 5.282674404546004], 'autorange': False}, 'yaxis': {'title': {'text': 'Mises Stress'}, 'type': 'linear', 'range': [1194338.1744483153, 6109662.126322151], 'autorange': False}, 'transition': {'duration': 1000}, 'clickmode': 'event+select'}}
|
|
464
|
+
|
|
465
|
+
# get point location
|
|
459
466
|
pt = hoverData["points"][0]
|
|
460
|
-
|
|
467
|
+
|
|
468
|
+
# get the bounding box of target
|
|
469
|
+
bbox = pt['bbox']
|
|
470
|
+
|
|
471
|
+
# get relative location of point
|
|
472
|
+
xrange = figure['layout']['xaxis']['range']
|
|
473
|
+
# yrange = figure['layout']['yaxis']['range']
|
|
474
|
+
|
|
475
|
+
is_left = pt['x'] < np.mean(xrange)
|
|
476
|
+
|
|
477
|
+
# デフォルトでは Hover が Point に重なり、
|
|
478
|
+
# Hover した瞬間に Un-hover する場合があるので
|
|
479
|
+
# offset を追加
|
|
480
|
+
if is_left:
|
|
481
|
+
direction = 'right'
|
|
482
|
+
bbox['x0'] = bbox['x0'] + 40
|
|
483
|
+
bbox['x1'] = bbox['x1'] + 40
|
|
484
|
+
|
|
485
|
+
else:
|
|
486
|
+
direction = 'left'
|
|
487
|
+
bbox['x0'] = bbox['x0'] + 15
|
|
488
|
+
bbox['x1'] = bbox['x1'] + 15
|
|
489
|
+
|
|
490
|
+
# ついでに縦方向も適当に調整
|
|
491
|
+
bbox['y0'] = bbox['y0'] + 80
|
|
492
|
+
bbox['y1'] = bbox['y1'] + 80
|
|
493
|
+
|
|
461
494
|
|
|
462
495
|
# get row of the history from customdata defined in main_figure
|
|
463
496
|
if 'customdata' not in pt.keys():
|
|
@@ -482,18 +515,20 @@ class MainGraph(AbstractPage):
|
|
|
482
515
|
title_component,
|
|
483
516
|
tbl_component_prm,
|
|
484
517
|
])
|
|
485
|
-
tooltip_layout = html.Div(
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
518
|
+
tooltip_layout = html.Div(
|
|
519
|
+
children=[
|
|
520
|
+
html.Div(img_component, style={'display': 'inline-block', 'margin-right': '10px'}),
|
|
521
|
+
html.Div(description, style={'display': 'inline-block', 'margin-right': '10px'}),
|
|
522
|
+
html.Div(tbl_component_obj, style={'display': 'inline-block', 'margin-right': '10px'}),
|
|
523
|
+
],
|
|
524
|
+
)
|
|
490
525
|
|
|
491
|
-
return True, bbox, tooltip_layout
|
|
526
|
+
return True, bbox, tooltip_layout, direction
|
|
492
527
|
|
|
493
528
|
def create_formatted_parameter(self, row) -> Component:
|
|
494
|
-
|
|
529
|
+
meta_columns = self.application.history.meta_columns
|
|
495
530
|
pd.options.display.float_format = '{:.4e}'.format
|
|
496
|
-
parameters = row.iloc[:, np.where(np.array(
|
|
531
|
+
parameters = row.iloc[:, np.where(np.array(meta_columns) == 'prm')[0]]
|
|
497
532
|
names = parameters.columns
|
|
498
533
|
values = [f'{value:.3e}' for value in parameters.values.ravel()]
|
|
499
534
|
data = pd.DataFrame(dict(
|
|
@@ -506,9 +541,9 @@ class MainGraph(AbstractPage):
|
|
|
506
541
|
return table
|
|
507
542
|
|
|
508
543
|
def create_formatted_objective(self, row) -> Component:
|
|
509
|
-
|
|
544
|
+
meta_columns = self.application.history.meta_columns
|
|
510
545
|
pd.options.display.float_format = '{:.4e}'.format
|
|
511
|
-
objectives = row.iloc[:, np.where(np.array(
|
|
546
|
+
objectives = row.iloc[:, np.where(np.array(meta_columns) == 'obj')[0]]
|
|
512
547
|
names = objectives.columns
|
|
513
548
|
values = [f'{value:.3e}' for value in objectives.values.ravel()]
|
|
514
549
|
data = pd.DataFrame(dict(
|
|
@@ -522,20 +557,21 @@ class MainGraph(AbstractPage):
|
|
|
522
557
|
|
|
523
558
|
def create_image_content_if_femtet(self, trial) -> Component:
|
|
524
559
|
img_url = None
|
|
525
|
-
|
|
526
|
-
if
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
560
|
+
meta_columns = self.application.history.meta_columns
|
|
561
|
+
if meta_columns[0] != '':
|
|
562
|
+
extra_data = json.loads(meta_columns[0])
|
|
563
|
+
if 'femprj_path' in extra_data.keys():
|
|
564
|
+
# get img path
|
|
565
|
+
femprj_path = extra_data['femprj_path']
|
|
566
|
+
model_name = extra_data['model_name']
|
|
567
|
+
femprj_result_dir = femprj_path.replace('.femprj', '.Results')
|
|
568
|
+
img_path = os.path.join(femprj_result_dir, f'{model_name}_trial{trial}.jpg')
|
|
569
|
+
if os.path.exists(img_path):
|
|
570
|
+
# create encoded image
|
|
571
|
+
with open(img_path, 'rb') as f:
|
|
572
|
+
content = f.read()
|
|
573
|
+
encoded_image = base64.b64encode(content).decode('utf-8')
|
|
574
|
+
img_url = 'data:image/jpeg;base64, ' + encoded_image
|
|
539
575
|
return html.Img(src=img_url, style={"width": "200px"}) if img_url is not None else html.Div()
|
|
540
576
|
|
|
541
577
|
def get_fig_by_tab_id(self, tab_id, with_length=False, kwargs: dict = None):
|
|
@@ -547,9 +547,9 @@ class PredictionModelGraph(AbstractPage):
|
|
|
547
547
|
return tuple(ret.values())
|
|
548
548
|
|
|
549
549
|
def create_formatted_parameter(self, row) -> Component:
|
|
550
|
-
|
|
550
|
+
meta_columns = self.application.history.meta_columns
|
|
551
551
|
pd.options.display.float_format = '{:.4e}'.format
|
|
552
|
-
parameters = row.iloc[:, np.where(np.array(
|
|
552
|
+
parameters = row.iloc[:, np.where(np.array(meta_columns) == 'prm')[0]]
|
|
553
553
|
names = parameters.columns
|
|
554
554
|
values = [f'{value:.3e}' for value in parameters.values.ravel()]
|
|
555
555
|
data = pd.DataFrame(dict(
|
|
@@ -563,20 +563,21 @@ class PredictionModelGraph(AbstractPage):
|
|
|
563
563
|
|
|
564
564
|
def create_image_content_if_femtet(self, trial) -> Component:
|
|
565
565
|
img_url = None
|
|
566
|
-
|
|
567
|
-
if
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
566
|
+
meta_columns = self.application.history.meta_columns
|
|
567
|
+
if meta_columns[0] != '':
|
|
568
|
+
extra_data = json.loads(meta_columns[0])
|
|
569
|
+
if 'femprj_path' in extra_data:
|
|
570
|
+
# get img path
|
|
571
|
+
femprj_path = extra_data['femprj_path']
|
|
572
|
+
model_name = extra_data['model_name']
|
|
573
|
+
femprj_result_dir = femprj_path.replace('.femprj', '.Results')
|
|
574
|
+
img_path = os.path.join(femprj_result_dir, f'{model_name}_trial{trial}.jpg')
|
|
575
|
+
if os.path.exists(img_path):
|
|
576
|
+
# create encoded image
|
|
577
|
+
with open(img_path, 'rb') as f:
|
|
578
|
+
content = f.read()
|
|
579
|
+
encoded_image = base64.b64encode(content).decode('utf-8')
|
|
580
|
+
img_url = 'data:image/jpeg;base64, ' + encoded_image
|
|
580
581
|
return html.Img(src=img_url, style={"width": "200px"}) if img_url is not None else html.Div()
|
|
581
582
|
|
|
582
583
|
# def get_fig_by_tab_id(self, tab_id, with_length=False):
|
|
@@ -3,6 +3,7 @@ from time import sleep
|
|
|
3
3
|
from threading import Thread
|
|
4
4
|
|
|
5
5
|
import pandas as pd
|
|
6
|
+
from flask import jsonify
|
|
6
7
|
|
|
7
8
|
from pyfemtet.opt.visualization._base import PyFemtetApplicationBase, logger
|
|
8
9
|
from pyfemtet.opt.visualization._process_monitor.pages import HomePage, WorkerPage, PredictionModelPage, OptunaVisualizerPage
|
|
@@ -80,7 +81,22 @@ class ProcessMonitorApplication(PyFemtetApplicationBase):
|
|
|
80
81
|
if not debug:
|
|
81
82
|
super().setup_callback()
|
|
82
83
|
|
|
83
|
-
|
|
84
|
+
from pyfemtet.opt._femopt_core import OptimizationStatus
|
|
85
|
+
|
|
86
|
+
@self.server.route('/interrupt')
|
|
87
|
+
def some_command():
|
|
88
|
+
|
|
89
|
+
# If the entire_state < INTERRUPTING, set INTERRUPTING
|
|
90
|
+
if self.local_entire_status_int < OptimizationStatus.INTERRUPTING:
|
|
91
|
+
self.local_entire_status_int = OptimizationStatus.INTERRUPTING
|
|
92
|
+
result = {"message": "Interrupting signal emitted successfully."}
|
|
93
|
+
|
|
94
|
+
else:
|
|
95
|
+
result = {"message": "Interrupting signal is already emitted."}
|
|
96
|
+
|
|
97
|
+
return jsonify(result)
|
|
98
|
+
|
|
99
|
+
def start_server(self, host=None, port=None, host_record=None):
|
|
84
100
|
"""Callback の中で使いたい Actor のデータを Application クラスのメンバーとやり取りしつつ、server を落とす関数"""
|
|
85
101
|
|
|
86
102
|
self._should_get_actor_data = True
|
|
@@ -95,6 +111,7 @@ class ProcessMonitorApplication(PyFemtetApplicationBase):
|
|
|
95
111
|
server_thread = Thread(
|
|
96
112
|
target=self.run,
|
|
97
113
|
args=(host, port,),
|
|
114
|
+
kwargs=dict(host_record=host_record),
|
|
98
115
|
daemon=True,
|
|
99
116
|
)
|
|
100
117
|
server_thread.start()
|
|
@@ -188,7 +205,7 @@ def g_debug():
|
|
|
188
205
|
g_application.run(debug=False)
|
|
189
206
|
|
|
190
207
|
|
|
191
|
-
def main(history, status, worker_addresses, worker_status_list, host=None, port=None):
|
|
208
|
+
def main(history, status, worker_addresses, worker_status_list, host=None, port=None, host_record=None):
|
|
192
209
|
g_application = ProcessMonitorApplication(history, status, worker_addresses, worker_status_list)
|
|
193
210
|
|
|
194
211
|
g_home_page = HomePage(Msg.PAGE_TITLE_PROGRESS)
|
|
@@ -202,7 +219,7 @@ def main(history, status, worker_addresses, worker_status_list, host=None, port=
|
|
|
202
219
|
g_application.add_page(g_worker_page, 3)
|
|
203
220
|
g_application.setup_callback()
|
|
204
221
|
|
|
205
|
-
g_application.start_server(host, port)
|
|
222
|
+
g_application.start_server(host, port, host_record)
|
|
206
223
|
|
|
207
224
|
|
|
208
225
|
if __name__ == '__main__':
|
|
@@ -209,11 +209,11 @@ class HomePage(AbstractPage):
|
|
|
209
209
|
Input('debug-button-2', 'n_clicks'),
|
|
210
210
|
prevent_initial_call=True)
|
|
211
211
|
def add_data(*_):
|
|
212
|
-
|
|
212
|
+
meta_columns = self.application.history.meta_columns
|
|
213
213
|
df = self.application.local_data
|
|
214
214
|
|
|
215
215
|
new_row = df.iloc[-2:]
|
|
216
|
-
obj_index = np.where(np.array(
|
|
216
|
+
obj_index = np.where(np.array(meta_columns) == 'obj')[0]
|
|
217
217
|
for idx in obj_index:
|
|
218
218
|
new_row.iloc[:, idx] = np.random.rand(len(new_row))
|
|
219
219
|
|
|
@@ -183,11 +183,11 @@ class HomePage(AbstractPage):
|
|
|
183
183
|
return alerts
|
|
184
184
|
|
|
185
185
|
# get femprj in history csv
|
|
186
|
-
kwargs = self.femtet_control.create_femtet_interface_args()[0] # read
|
|
186
|
+
kwargs = self.femtet_control.create_femtet_interface_args()[0] # read extra_data from history.
|
|
187
187
|
femprj_path = kwargs['femprj_path']
|
|
188
188
|
model_name = kwargs['model_name']
|
|
189
189
|
|
|
190
|
-
# check
|
|
190
|
+
# check extra_data is valid
|
|
191
191
|
if femprj_path is None:
|
|
192
192
|
msg = Msg.ERR_FEMPRJ_IN_CSV_NOT_FOUND
|
|
193
193
|
alerts = self.alert_region.create_alerts(msg, color='danger')
|
|
@@ -283,8 +283,8 @@ class HomePage(AbstractPage):
|
|
|
283
283
|
# get parameter and update model
|
|
284
284
|
df = self.application.history.get_df(valid_only=True)
|
|
285
285
|
row = df[df['trial'] == trial]
|
|
286
|
-
|
|
287
|
-
idx = np.where(
|
|
286
|
+
meta_columns = np.array(self.application.history.meta_columns)
|
|
287
|
+
idx = np.where(meta_columns == 'prm')[0]
|
|
288
288
|
|
|
289
289
|
names = np.array(row.columns)[idx]
|
|
290
290
|
values = np.array(row.iloc[:, idx]).ravel()
|
|
@@ -346,7 +346,7 @@ class HomePage(AbstractPage):
|
|
|
346
346
|
|
|
347
347
|
# check the corresponding between history and Femtet
|
|
348
348
|
# ├ history-side
|
|
349
|
-
kwargs = self.femtet_control.create_femtet_interface_args()[0] # read
|
|
349
|
+
kwargs = self.femtet_control.create_femtet_interface_args()[0] # read extra_data from history.
|
|
350
350
|
femprj_path_history_on_history: str or None = kwargs['femprj_path']
|
|
351
351
|
model_name_on_history: str or None = kwargs['model_name']
|
|
352
352
|
# ├ Femtet-side
|
|
@@ -673,7 +673,7 @@ class Tutorial(AbstractPage):
|
|
|
673
673
|
destination_folder = source_folder.replace('wat_ex14_parametric', 'tutorial')
|
|
674
674
|
shutil.copytree(source_folder, destination_folder, dirs_exist_ok=True)
|
|
675
675
|
|
|
676
|
-
self.application.history.
|
|
676
|
+
self.application.history.meta_columns[0] = json.dumps(
|
|
677
677
|
dict(
|
|
678
678
|
femprj_path=destination_file,
|
|
679
679
|
model_name='Ex14',
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
pyfemtet/__init__.py,sha256=
|
|
1
|
+
pyfemtet/__init__.py,sha256=B72_7DUBCOMnhKCvBwcwiuuCre398QDqqytHa0lXG-Q,21
|
|
2
2
|
pyfemtet/_femtet_config_util/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
3
3
|
pyfemtet/_femtet_config_util/autosave.py,sha256=dNirA9XGuFehas8_Jkj2BW9GOzMbPyhnt1WHcH_ObSU,2070
|
|
4
4
|
pyfemtet/_femtet_config_util/exit.py,sha256=0BWID-tjOkmZwmgPFkcJMkWW39voccz5ARIBWvZbHaw,1877
|
|
@@ -24,12 +24,12 @@ pyfemtet/dispatch_extensions/_impl.py,sha256=yH_yeAnQ-Xi9GfjX-FQt9u3yHnrLYIteRb6
|
|
|
24
24
|
pyfemtet/logger/__init__.py,sha256=UOJ9n_U2xwdTrp0Xgg-N6geySxNzKqTBQlXsaH0kW_w,420
|
|
25
25
|
pyfemtet/logger/_impl.py,sha256=rsAd0HpmveOaLS39ucp3U2OcDhQMWjC5fnVGhbJtWVw,6375
|
|
26
26
|
pyfemtet/opt/__init__.py,sha256=wRR8LbEhb5I6MUgmnCgjB6-tqHlOVxDIo7yPkq0QbBs,758
|
|
27
|
-
pyfemtet/opt/_femopt.py,sha256=
|
|
28
|
-
pyfemtet/opt/_femopt_core.py,sha256=
|
|
27
|
+
pyfemtet/opt/_femopt.py,sha256=ZhwOK1QYwo7Xk67qEOm4biKXzdIW2AUHYvgklBREDm8,40587
|
|
28
|
+
pyfemtet/opt/_femopt_core.py,sha256=kxKh4_TdXR4LBgv8WibPiZ5Pe9apJd5ArBCfnhBwcCQ,38969
|
|
29
29
|
pyfemtet/opt/_test_utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
30
30
|
pyfemtet/opt/_test_utils/control_femtet.py,sha256=8oAl9y5V2n8Nnsgx_ebcZVzwFt1eI3swkdiKg6pg3-M,1085
|
|
31
31
|
pyfemtet/opt/_test_utils/hyper_sphere.py,sha256=nQhw8EIY0DwvcTqrbKhkxiITLZifr4-nG77E-_6ggmA,700
|
|
32
|
-
pyfemtet/opt/_test_utils/record_history.py,sha256=
|
|
32
|
+
pyfemtet/opt/_test_utils/record_history.py,sha256=zsa1w73K7NLBqbj7yuv0fWVJvZtWdiI0eCaUoAn5Bjg,4239
|
|
33
33
|
pyfemtet/opt/advanced_samples/excel_ui/(ref) original_project.femprj,sha256=5OqZfynTpVCrgEIOBOMYuDGaMvepi5lojVNFr1jAsEI,157489
|
|
34
34
|
pyfemtet/opt/advanced_samples/excel_ui/femtet-macro.xlsm,sha256=ckF0SQ0f3IWSW6QoH1IPJdwUUlR7O_AiGC5fi8SI3jA,133137
|
|
35
35
|
pyfemtet/opt/advanced_samples/excel_ui/pyfemtet-core.py,sha256=aF2TWXdbt7dnkeBqqVO6GvIExozjFp0mxx3BX8rpYNc,9879
|
|
@@ -39,7 +39,7 @@ pyfemtet/opt/advanced_samples/surrogate_model/gal_ex13_create_training_data_jp.p
|
|
|
39
39
|
pyfemtet/opt/advanced_samples/surrogate_model/gal_ex13_optimize_with_surrogate.py,sha256=s0b31wuN3iXjb78dt0ro0ZjxHa8uLIH94jRfEuj1EVY,3090
|
|
40
40
|
pyfemtet/opt/advanced_samples/surrogate_model/gal_ex13_optimize_with_surrogate_jp.py,sha256=OAOpHKyMMo1StSqNMqx4saYDn4hiGOKDypyK6uhTILQ,3215
|
|
41
41
|
pyfemtet/opt/advanced_samples/surrogate_model/gal_ex13_parametric.femprj,sha256=iIHH1X-wWBqEYj4cFJXco73LCJXSrYBsSKOD0HxYu60,87599
|
|
42
|
-
pyfemtet/opt/interface/__init__.py,sha256=
|
|
42
|
+
pyfemtet/opt/interface/__init__.py,sha256=na6-elI9-karOqoSxT9LfLQpjBPm1lrUWjow0NYYRP4,1349
|
|
43
43
|
pyfemtet/opt/interface/_base.py,sha256=y0uQ5jdsWbgt5odyqPin7NXcK_IbUwPDcrrkV_JhpRw,2722
|
|
44
44
|
pyfemtet/opt/interface/_excel_interface.py,sha256=s103vePTPXXYiPwGdAEUFgtpvGXtu1nSljDtP4HsmcY,40355
|
|
45
45
|
pyfemtet/opt/interface/_femtet.py,sha256=teALmp66aJ_rrmtEOjCGDG1jGLTZr2AmvMFmuuXRQkw,34634
|
|
@@ -49,9 +49,9 @@ pyfemtet/opt/interface/_femtet_with_nx/_interface.py,sha256=LkaODUSpBLq05uz5Jf-J
|
|
|
49
49
|
pyfemtet/opt/interface/_femtet_with_nx/update_model.py,sha256=P7VH0i_o-X9OUe6AGaLF1fACPeHNrMjcrOBCA3MMrI4,3092
|
|
50
50
|
pyfemtet/opt/interface/_femtet_with_sldworks.py,sha256=rjEgebuP1w1eAFVWw4eRJUq3lsyBcmXlkMjZKIpD0kw,11019
|
|
51
51
|
pyfemtet/opt/interface/_surrogate/__init__.py,sha256=2UT5NuBylyWQJNjg1zsBRCV-MzNCUswTUt6ZuSrYFUM,120
|
|
52
|
-
pyfemtet/opt/interface/_surrogate/_base.py,sha256
|
|
52
|
+
pyfemtet/opt/interface/_surrogate/_base.py,sha256=bQMoztVq1b-3BW5Z1V-dSROplMHutrblDI289j0cC-E,3001
|
|
53
53
|
pyfemtet/opt/interface/_surrogate/_chaospy.py,sha256=gL72bCgs1AY_EZdJtcifSC-apwsZzp4zsWYxcpVKvtw,1969
|
|
54
|
-
pyfemtet/opt/interface/_surrogate/_singletaskgp.py,sha256=
|
|
54
|
+
pyfemtet/opt/interface/_surrogate/_singletaskgp.py,sha256=ojZHsxGxSc8ZJqJQ_uMHvpK98TPUsHzXP0q4tmM0YPQ,2471
|
|
55
55
|
pyfemtet/opt/optimizer/__init__.py,sha256=Ia6viowECkG0IFXtFef0tJ4jDKsoDzJLqMJ9xLFH2LQ,543
|
|
56
56
|
pyfemtet/opt/optimizer/_base.py,sha256=j8aQc3fGehZTJT9ETf9cr3VWYs2FYk1F8fO3f7QyKAU,13099
|
|
57
57
|
pyfemtet/opt/optimizer/_optuna/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -64,7 +64,7 @@ pyfemtet/opt/optimizer/_scipy_scalar.py,sha256=rGvrLjrgfYzxK9GA0-r2Hhoaqt6A0TQsT
|
|
|
64
64
|
pyfemtet/opt/optimizer/parameter.py,sha256=YLE9lmYRaZA8isnTPJnbYXpUn6zsJFW4xg03QaSWey8,3950
|
|
65
65
|
pyfemtet/opt/prediction/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
66
66
|
pyfemtet/opt/prediction/_base.py,sha256=dEyEur3IntNokYK8NhPndHb2pWY_A4C1SjEejOTCUGw,2048
|
|
67
|
-
pyfemtet/opt/prediction/single_task_gp.py,sha256=
|
|
67
|
+
pyfemtet/opt/prediction/single_task_gp.py,sha256=t4Vby0Llh7ZcVQ6M5zYqwmmo-NwSXwWRExLtqzmPcu8,3929
|
|
68
68
|
pyfemtet/opt/samples/femprj_sample/ParametricIF.femprj,sha256=9BtDHmc3cdom0Zq33DTdZ0mDAsIUY6i8SRkkg-n7GO0,442090
|
|
69
69
|
pyfemtet/opt/samples/femprj_sample/ParametricIF.py,sha256=oXzchBZEbH69xacDht5HDnbZzKwapXsn6bp9qihY17Y,707
|
|
70
70
|
pyfemtet/opt/samples/femprj_sample/ParametricIF_test_result.reccsv,sha256=TiOAqEDMub6SCGYClBv1JvQxphDOY3iIdr_pMmGgJ9M,2859
|
|
@@ -116,18 +116,18 @@ pyfemtet/opt/samples/femprj_sample_jp/wat_ex14_parametric_jp.femprj,sha256=dMwQM
|
|
|
116
116
|
pyfemtet/opt/samples/femprj_sample_jp/wat_ex14_parametric_jp.py,sha256=vMy-KUP1wEMV9Rt6yXjkE40Fcs1t1cpQK-nQJK8hHao,2284
|
|
117
117
|
pyfemtet/opt/samples/femprj_sample_jp/wat_ex14_parametric_parallel_jp.py,sha256=4X0cl3YWpYarcNBCH79mrlyFuKUYSqvnGzokEbv9ILk,2335
|
|
118
118
|
pyfemtet/opt/visualization/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
119
|
-
pyfemtet/opt/visualization/_base.py,sha256=
|
|
119
|
+
pyfemtet/opt/visualization/_base.py,sha256=b1oWPsCTFmoHRjFWhysmpE3VmaB7e-FNq6V9eMTZRz8,7934
|
|
120
120
|
pyfemtet/opt/visualization/_complex_components/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
121
121
|
pyfemtet/opt/visualization/_complex_components/alert_region.py,sha256=sX8xqT4NqhACagK4YgumF4ResrTqhOKQ8dN4q58shI8,2106
|
|
122
|
-
pyfemtet/opt/visualization/_complex_components/control_femtet.py,sha256=
|
|
122
|
+
pyfemtet/opt/visualization/_complex_components/control_femtet.py,sha256=sY0YH56MgDWtfFfEkFsfzpr0VbP8dRT0KrhhGzeRiRE,6227
|
|
123
123
|
pyfemtet/opt/visualization/_complex_components/main_figure_creator.py,sha256=Wt_aL6srMNW-84LeZ86_OtljzmFoF9v0yklVpPAgNDE,9480
|
|
124
|
-
pyfemtet/opt/visualization/_complex_components/main_graph.py,sha256=
|
|
125
|
-
pyfemtet/opt/visualization/_complex_components/pm_graph.py,sha256=
|
|
124
|
+
pyfemtet/opt/visualization/_complex_components/main_graph.py,sha256=WbV0oW6nUS734688Zd4H1OpDrBBWJEu6u4u7lqoqnSQ,31975
|
|
125
|
+
pyfemtet/opt/visualization/_complex_components/pm_graph.py,sha256=FnxerXoddflukSj_BdhjK7jBl83qSDFsTUcQzs8Nij8,25153
|
|
126
126
|
pyfemtet/opt/visualization/_complex_components/pm_graph_creator.py,sha256=f-ikYAPChazqyRQ0Y-tKrYrMBHzFHJJ4uV6QXBEBRKI,7304
|
|
127
127
|
pyfemtet/opt/visualization/_create_wrapped_components.py,sha256=9AltJHr1DM6imZfpNp867rC-uAYqQ-emdgTLChKDrl8,2513
|
|
128
128
|
pyfemtet/opt/visualization/_process_monitor/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
129
|
-
pyfemtet/opt/visualization/_process_monitor/application.py,sha256=
|
|
130
|
-
pyfemtet/opt/visualization/_process_monitor/pages.py,sha256
|
|
129
|
+
pyfemtet/opt/visualization/_process_monitor/application.py,sha256=8ShNMPWrD_1IHyPz2a63tlzENQg7by3kg4pdXSuv0_4,8659
|
|
130
|
+
pyfemtet/opt/visualization/_process_monitor/pages.py,sha256=-G-zNvYS6HDXrwX0lQlInlJn3rZPr1-Rh4AAAOudmuY,15147
|
|
131
131
|
pyfemtet/opt/visualization/_wrapped_components/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
132
132
|
pyfemtet/opt/visualization/_wrapped_components/dbc.py,sha256=iSh4QRmLIQMfiAWowG1ThXLPhmKluRYOYPcdDFVI0t0,42162
|
|
133
133
|
pyfemtet/opt/visualization/_wrapped_components/dcc.py,sha256=-Iw6MjFQmvJ__KcddPhFDqui6lk2ixB2U2tZH_Il5pA,17500
|
|
@@ -136,9 +136,9 @@ pyfemtet/opt/visualization/_wrapped_components/str_enum.py,sha256=NZqbh2jNEAckvJ
|
|
|
136
136
|
pyfemtet/opt/visualization/result_viewer/.gitignore,sha256=ryvb4aqbbsHireHWlPQfxxqDHQJo6YkVYhE9imKt0b8,6
|
|
137
137
|
pyfemtet/opt/visualization/result_viewer/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
138
138
|
pyfemtet/opt/visualization/result_viewer/application.py,sha256=WcHBx_J5eNLKSaprpk9BGifwhO04oN8FiNGYTWorrXA,1691
|
|
139
|
-
pyfemtet/opt/visualization/result_viewer/pages.py,sha256=
|
|
140
|
-
pyfemtet-0.8.
|
|
141
|
-
pyfemtet-0.8.
|
|
142
|
-
pyfemtet-0.8.
|
|
143
|
-
pyfemtet-0.8.
|
|
144
|
-
pyfemtet-0.8.
|
|
139
|
+
pyfemtet/opt/visualization/result_viewer/pages.py,sha256=MZAjzbuq0toZrR-iJhElM3A12_jHVCTt65gz1kdNPbw,32193
|
|
140
|
+
pyfemtet-0.8.6.dist-info/LICENSE,sha256=sVQBhyoglGJUu65-BP3iR6ujORI6YgEU2Qm-V4fGlOA,1485
|
|
141
|
+
pyfemtet-0.8.6.dist-info/METADATA,sha256=Nygc04MFehj-ZvJ5e3KuWq3CL2C94_tbTezHQdp5ubg,3509
|
|
142
|
+
pyfemtet-0.8.6.dist-info/WHEEL,sha256=IYZQI976HJqqOpQU6PHkJ8fb3tMNBFjg-Cn-pwAbaFM,88
|
|
143
|
+
pyfemtet-0.8.6.dist-info/entry_points.txt,sha256=ZfYqRaoiPtuWqFi2_msccyrVF0LurMn-IHlYamAegZo,104
|
|
144
|
+
pyfemtet-0.8.6.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|