From 3664c1b571d52ccb7b4f492687783d38d9db9953 Mon Sep 17 00:00:00 2001 From: Lorenzo Vecchietti <58366962+lorenzovecchietti@users.noreply.github.com> Date: Wed, 6 Dec 2023 15:00:16 +0100 Subject: [PATCH] Monitors and datasets import/export improvements (#3917) * Make monitors and datasets import/export through configurations valid for json validation * fix ut --- _unittest/test_01_configuration_files.py | 23 ++++ pyaedt/generic/configurations.py | 137 +++++++++++++---------- pyaedt/modeler/cad/Primitives3D.py | 62 +++++----- pyaedt/modeler/modeler3d.py | 24 ++-- 4 files changed, 148 insertions(+), 98 deletions(-) diff --git a/_unittest/test_01_configuration_files.py b/_unittest/test_01_configuration_files.py index af2f4de02d5..b2e940adabe 100644 --- a/_unittest/test_01_configuration_files.py +++ b/_unittest/test_01_configuration_files.py @@ -1,4 +1,5 @@ # standard imports +import json import os import time @@ -208,6 +209,28 @@ def test_04a_icepak(self, icepak_a, aedtapp, add_app): out = app.configurations.import_config(conf_file) assert isinstance(out, dict) assert app.configurations.results.global_import_success + # backward compatibility + with open(conf_file, "r") as f: + old_dict_format = json.load(f) + old_dict_format["monitor"] = old_dict_format.pop("monitors") + old_mon_dict = {} + for mon in old_dict_format["monitor"]: + old_mon_dict[mon["Name"]] = mon + old_mon_dict[mon["Name"]].pop("Name") + old_dict_format["monitor"] = old_mon_dict + old_dataset_dict = {} + for dat in old_dict_format["datasets"]: + old_dataset_dict[dat["Name"]] = dat + old_dataset_dict[dat["Name"]].pop("Name") + old_dict_format["datasets"] = old_dataset_dict + old_conf_file = conf_file + ".old.json" + with open(old_conf_file, "w") as f: + json.dump(old_dict_format, f) + app = add_app(application=Icepak, project_name="new_proj_Ipk_a_test2", just_open=True) + app.modeler.import_3d_cad(file_path) + out = app.configurations.import_config(old_conf_file) + assert isinstance(out, dict) + assert app.configurations.results.global_import_success app.close_project(save_project=False) @pytest.mark.skipif( diff --git a/pyaedt/generic/configurations.py b/pyaedt/generic/configurations.py index 1b0163bade4..1d32f3c69ec 100644 --- a/pyaedt/generic/configurations.py +++ b/pyaedt/generic/configurations.py @@ -965,7 +965,8 @@ def _update_parametrics(self, name, props): return False @pyaedt_function_handler() - def _update_datasets(self, name, data_dict): + def _update_datasets(self, data_dict): + name = data_dict["Name"] is_project_dataset = False if name.startswith("$"): is_project_dataset = True @@ -1088,8 +1089,14 @@ def import_config(self, config_file, *args): if self.options.import_datasets and dict_in.get("datasets", None): self.results.import_datasets = True - for k, v in dict_in["datasets"].items(): - self._update_datasets(k, v) + if not isinstance(dict_in["datasets"], list): # backward compatibility + dataset_list = [] + for k, v in dict_in["datasets"].items(): + v["Name"] = k + dataset_list.append(v) + dict_in["datasets"] = dataset_list + for dataset in dict_in["datasets"]: + self._update_datasets(dataset) if self.options.import_boundaries and dict_in.get("boundaries", None): self.results.import_boundaries = True @@ -1272,24 +1279,27 @@ def _export_mesh_operations(self, dict_out): def _export_datasets(self, dict_out): if self._app.project_datasets or self._app.design_datasets: if dict_out.get("datasets", None) is None: - dict_out["datasets"] = {} + dict_out["datasets"] = [] for dataset_dict in [self._app.project_datasets, self._app.design_datasets]: for k, obj in dataset_dict.items(): if k not in dict_out.get("material datasets", []): - dict_out["datasets"][k] = { - "v": obj.v, - "vunit": obj.vunit, - "x": obj.x, - "xunit": obj.xunit, - "y": obj.y, - "yunit": obj.yunit, - "z": obj.z, - "zunit": obj.zunit, - } + dict_out["datasets"].append( + { + "Name": k, + "v": obj.v, + "vunit": obj.vunit, + "x": obj.x, + "xunit": obj.xunit, + "y": obj.y, + "yunit": obj.yunit, + "z": obj.z, + "zunit": obj.zunit, + } + ) @pyaedt_function_handler() def _export_monitor(self, dict_out): - dict_monitor = {} + dict_monitors = [] native_parts = [ part.name for udc_name, udc in self._app.modeler.user_defined_components.items() @@ -1298,33 +1308,33 @@ def _export_monitor(self, dict_out): ] if self._app.monitor.all_monitors != {}: for mon_name in self._app.monitor.all_monitors: - dict_monitor[mon_name] = { + dict_monitor = { key: val for key, val in self._app.monitor.all_monitors[mon_name].properties.items() if key not in ["Name", "Object"] } - if dict_monitor[mon_name]["Geometry Assignment"] in native_parts: - dict_monitor[mon_name]["Native Assignment"] = [ + dict_monitor["Name"] = mon_name + if dict_monitor["Geometry Assignment"] in native_parts: + dict_monitor["Native Assignment"] = [ name for name, dict_comp in self._app.modeler.user_defined_components.items() - if dict_monitor[mon_name]["Geometry Assignment"] + if dict_monitor["Geometry Assignment"] in [part.name for part_id, part in dict_comp.parts.items()] ][0] - if dict_monitor[mon_name]["Type"] == "Face": - dict_monitor[mon_name]["Area Assignment"] = self._app.modeler.get_face_area( - dict_monitor[mon_name]["ID"] - ) - elif dict_monitor[mon_name]["Type"] == "Surface": - dict_monitor[mon_name]["Area Assignment"] = self._app.modeler.get_face_area( - self._app.modeler.get_object_from_name(dict_monitor[mon_name]["ID"]).faces[0].id + if dict_monitor["Type"] == "Face": + dict_monitor["Area Assignment"] = self._app.modeler.get_face_area(dict_monitor["ID"]) + elif dict_monitor["Type"] == "Surface": + dict_monitor["Area Assignment"] = self._app.modeler.get_face_area( + self._app.modeler.get_object_from_name(dict_monitor["ID"]).faces[0].id ) - elif dict_monitor[mon_name]["Type"] == "Object": - bb = self._app.modeler.get_object_from_name([dict_monitor[mon_name]["ID"]][0]).bounding_box - dict_monitor[mon_name]["Location"] = [(bb[i] + bb[i + 3]) / 2 for i in range(3)] - dict_monitor[mon_name]["Volume Assignment"] = self._app.modeler.get_object_from_name( - dict_monitor[mon_name]["ID"] + elif dict_monitor["Type"] == "Object": + bb = self._app.modeler.get_object_from_name([dict_monitor["ID"]][0]).bounding_box + dict_monitor["Location"] = [(bb[i] + bb[i + 3]) / 2 for i in range(3)] + dict_monitor["Volume Assignment"] = self._app.modeler.get_object_from_name( + dict_monitor["ID"] ).volume - dict_out["monitor"] = dict_monitor + dict_monitors.append(dict_monitor) + dict_out["monitors"] = dict_monitors @pyaedt_function_handler() def _export_materials(self, dict_out): @@ -1618,58 +1628,57 @@ def update_monitor(self, m_case, m_object, m_quantity, m_name): @pyaedt_function_handler() def _monitor_assignment_finder(self, dict_in, monitor_obj, exclude_set): - if dict_in["monitor"][monitor_obj].get("Native Assignment", None): + idx = dict_in["monitors"].index(monitor_obj) + if monitor_obj.get("Native Assignment", None): objects_to_check = [obj for _, obj in self._app.modeler.objects.items()] objects_to_check = list(set(objects_to_check) - exclude_set) - if dict_in["monitor"][monitor_obj]["Type"] == "Face": + if monitor_obj["Type"] == "Face": for obj in objects_to_check: for f in obj.faces: if ( - GeometryOperators.v_norm( - GeometryOperators.v_sub(f.center, dict_in["monitor"][monitor_obj]["Location"]) - ) + GeometryOperators.v_norm(GeometryOperators.v_sub(f.center, monitor_obj["Location"])) <= 1e-12 - and abs(f.area - dict_in["monitor"][monitor_obj]["Area Assignment"]) <= 1e-12 + and abs(f.area - monitor_obj["Area Assignment"]) <= 1e-12 ): - dict_in["monitor"][monitor_obj]["ID"] = f.id + monitor_obj["ID"] = f.id + dict_in["monitors"][idx] = monitor_obj return - elif dict_in["monitor"][monitor_obj]["Type"] == "Surface": + elif monitor_obj["Type"] == "Surface": for obj in objects_to_check: if len(obj.faces) == 1: for f in obj.faces: if ( - GeometryOperators.v_norm( - GeometryOperators.v_sub(f.center, dict_in["monitor"][monitor_obj]["Location"]) - ) + GeometryOperators.v_norm(GeometryOperators.v_sub(f.center, monitor_obj["Location"])) <= 1e-12 - and abs(f.area - dict_in["monitor"][monitor_obj]["Area Assignment"]) <= 1e-12 + and abs(f.area - monitor_obj["Area Assignment"]) <= 1e-12 ): - dict_in["monitor"][monitor_obj]["ID"] = obj.name + monitor_obj["ID"] = obj.name + dict_in["monitors"][idx] = monitor_obj return - elif dict_in["monitor"][monitor_obj]["Type"] == "Object": + elif monitor_obj["Type"] == "Object": for obj in objects_to_check: bb = obj.bounding_box if ( GeometryOperators.v_norm( GeometryOperators.v_sub( - [(bb[i] + bb[i + 3]) / 2 for i in range(3)], dict_in["monitor"][monitor_obj]["Location"] + [(bb[i] + bb[i + 3]) / 2 for i in range(3)], monitor_obj["Location"] ) ) <= 1e-12 - and abs(obj.volume - dict_in["monitor"][monitor_obj]["Volume Assignment"]) <= 1e-12 + and abs(obj.volume - monitor_obj["Volume Assignment"]) <= 1e-12 ): - dict_in["monitor"][monitor_obj]["ID"] = obj.id + monitor_obj["ID"] = obj.id + dict_in["monitors"][idx] = monitor_obj return - elif dict_in["monitor"][monitor_obj]["Type"] == "Vertex": + elif monitor_obj["Type"] == "Vertex": for obj in objects_to_check: for v in obj.vertices: if ( - GeometryOperators.v_norm( - GeometryOperators.v_sub(v.position, dict_in["monitor"][monitor_obj]["Location"]) - ) + GeometryOperators.v_norm(GeometryOperators.v_sub(v.position, monitor_obj["Location"])) <= 1e-12 ): - dict_in["monitor"][monitor_obj]["ID"] = v.id + monitor_obj["ID"] = v.id + dict_in["monitors"][idx] = monitor_obj return @pyaedt_function_handler() @@ -1723,16 +1732,24 @@ def import_config(self, config_file, *args): result_native_component = False dict_in = Configurations.import_config(self, config_file) - if self.options.import_monitor and dict_in.get("monitor", None): + if self.options.import_monitor and dict_in.get("monitor", None): # backward compatibility + dict_in["monitors"] = dict_in.pop("monitor") + if self.options.import_monitor and dict_in.get("monitors", None): + if not isinstance(dict_in["monitors"], list): # backward compatibility + mon_list = [] + for k, v in dict_in["monitors"].items(): + v["Name"] = k + mon_list.append(v) + dict_in["monitors"] = mon_list self.results.import_monitor = True - for monitor_obj in dict_in["monitor"]: + for monitor_obj in dict_in["monitors"]: self._monitor_assignment_finder(dict_in, monitor_obj, exclude_set) - m_type = dict_in["monitor"][monitor_obj]["Type"] - m_obj = dict_in["monitor"][monitor_obj]["ID"] + m_type = monitor_obj["Type"] + m_obj = monitor_obj["ID"] if m_type == "Point": - m_obj = dict_in["monitor"][monitor_obj]["Location"] + m_obj = monitor_obj["Location"] if not self.update_monitor( - m_type, m_obj, dict_in["monitor"][monitor_obj]["Quantity"], monitor_obj + m_type, m_obj, monitor_obj["Quantity"], monitor_obj["Name"] ): # pragma: no cover self.results.import_monitor = False try: diff --git a/pyaedt/modeler/cad/Primitives3D.py b/pyaedt/modeler/cad/Primitives3D.py index 29d29d9e97f..b38cf080f67 100644 --- a/pyaedt/modeler/cad/Primitives3D.py +++ b/pyaedt/modeler/cad/Primitives3D.py @@ -1452,7 +1452,8 @@ def insert_3d_component( auxiliary_dict = comp_file + ".json" aux_dict = json.load(open(auxiliary_dict, "r")) if aux_dict.get("datasets", None): - for key, val in aux_dict["datasets"].items(): + for dat in aux_dict["datasets"]: + key = dat["Name"] if key.startswith("$"): is_project_dataset = True dsname = key[1:] @@ -1461,15 +1462,15 @@ def insert_3d_component( dsname = key self._app.create_dataset( dsname, - val["x"], - val["y"], - val["z"], - val["v"], + dat["x"], + dat["y"], + dat["z"], + dat["v"], is_project_dataset, - val["xunit"], - val["yunit"], - val["zunit"], - val["vunit"], + dat["xunit"], + dat["yunit"], + dat["zunit"], + dat["vunit"], ) udm_obj = self._create_user_defined_component(new_object_name) if name and not auxiliary_dict: @@ -1497,11 +1498,14 @@ def insert_3d_component( temp_dict = {} temp_dict["native components"] = copy.deepcopy(aux_dict["native components"]) temp_dict["coordinatesystems"] = copy.deepcopy(aux_dict["coordinatesystems"]) - temp_dict["monitor"] = {} - for mon_name in list(aux_dict["monitor"].keys()): - if aux_dict["monitor"][mon_name].get("Native Assignment", None): - temp_dict["monitor"][udm_obj.name + "_" + mon_name] = aux_dict["monitor"][mon_name] - del aux_dict["monitor"][mon_name] + temp_dict["monitors"] = {} + to_remove = [] + for mon in aux_dict["monitors"]: + if mon.get("Native Assignment", None): + temp_dict["monitors"][udm_obj.name + "_" + mon["Name"]] = mon + to_remove.append(mon) + for mon in to_remove: + aux_dict["monitors"].remove(mon) self._app.configurations.options.unset_all_import() self._app.configurations.options.import_native_components = True self._app.configurations.options.import_monitor = True @@ -1521,7 +1525,7 @@ def insert_3d_component( for cs in set(self._app.modeler.coordinate_systems) - old_cs: if cs.ref_cs == "Global": cs.ref_cs = targetCS - if aux_dict.get("monitor", None): + if aux_dict.get("monitors", None): temp_proj_name = self._app._generate_unique_project_name() ipkapp_temp = Icepak(projectname=os.path.join(self._app.toolkit_directory, temp_proj_name)) ipkapp_temp.delete_design(ipkapp_temp.design_name) @@ -1557,12 +1561,12 @@ def insert_3d_component( + "}" ) except KeyError: # TODO: fix reading AEDT - for key, val in part["Operations"]["Operation"]["OperationIdentity"].items(): + for key, mon in part["Operations"]["Operation"]["OperationIdentity"].items(): if i in key: keyarr = key.split("(") dict_str = ( "{" - + "{}: {}".format(keyarr[1], val.replace(")", "")).replace("'", '"') + + "{}: {}".format(keyarr[1], mon.replace(")", "")).replace("'", '"') + "}" ) break @@ -1584,38 +1588,38 @@ def insert_3d_component( mapping_dict["ReferenceCoordSystemName"] = cs_dict[mapping_dict["ReferenceCoordSystemID"]] else: mapping_dict["ReferenceCoordSystemName"] = "Global" - for key, val in aux_dict["monitor"].items(): - key = udm_obj.name + "_" + key - m_case = val["Type"] + for mon in aux_dict["monitors"]: + key = udm_obj.name + "_" + mon["Name"] + m_case = mon["Type"] if m_case == "Point": cs_old = self._app.odesign.SetActiveEditor("3D Modeler").GetActiveCoordinateSystem() self._app.modeler.set_working_coordinate_system(targetCS) self._app.monitor.assign_point_monitor( - val["Location"], monitor_quantity=val["Quantity"], monitor_name=key + mon["Location"], monitor_quantity=mon["Quantity"], monitor_name=key ) self._app.modeler.set_working_coordinate_system(cs_old) elif m_case == "Face": self._app.monitor.assign_face_monitor( - mapping_dict["FaceKeyIDMap"][str(val["ID"])], - monitor_quantity=val["Quantity"], + mapping_dict["FaceKeyIDMap"][str(mon["ID"])], + monitor_quantity=mon["Quantity"], monitor_name=key, ) elif m_case == "Vertex": self._app.monitor.assign_point_monitor_to_vertex( - mapping_dict["VertexKeyIDMap"][str(val["ID"])], - monitor_quantity=val["Quantity"], + mapping_dict["VertexKeyIDMap"][str(mon["ID"])], + monitor_quantity=mon["Quantity"], monitor_name=key, ) elif m_case == "Surface": self._app.monitor.assign_surface_monitor( - self._app.modeler.objects[mapping_dict["BodyKeyIDMap"][str(val["ID"])]].name, - monitor_quantity=val["Quantity"], + self._app.modeler.objects[mapping_dict["BodyKeyIDMap"][str(mon["ID"])]].name, + monitor_quantity=mon["Quantity"], monitor_name=key, ) elif m_case == "Object": self._app.monitor.assign_point_monitor_in_object( - self._app.modeler.objects[mapping_dict["BodyKeyIDMap"][str(val["ID"])]].name, - monitor_quantity=val["Quantity"], + self._app.modeler.objects[mapping_dict["BodyKeyIDMap"][str(mon["ID"])]].name, + monitor_quantity=mon["Quantity"], monitor_name=key, ) if name: diff --git a/pyaedt/modeler/modeler3d.py b/pyaedt/modeler/modeler3d.py index 96de3e5da06..7a0baba4bb5 100644 --- a/pyaedt/modeler/modeler3d.py +++ b/pyaedt/modeler/modeler3d.py @@ -333,19 +333,25 @@ def create_3dcomponent( config_dict = json.load(f) out_dict = {} if monitor_objects: - out_dict["monitor"] = config_dict["monitor"] - for i in list(out_dict["monitor"]): - if i not in monitor_objects: - del out_dict["monitor"][i] + out_dict["monitors"] = config_dict["monitors"] + to_remove = [] + for i, mon in enumerate(out_dict["monitors"]): + if mon["Name"] not in monitor_objects: + to_remove.append(mon) else: - if out_dict["monitor"][i]["Type"] in ["Object", "Surface"]: + if mon["Type"] in ["Object", "Surface"]: self._app.modeler.refresh_all_ids() - out_dict["monitor"][i]["ID"] = self._app.modeler.get_obj_id(out_dict["monitor"][i]["ID"]) + out_dict["monitors"][i]["ID"] = self._app.modeler.get_obj_id(mon["ID"]) + for mon in to_remove: + out_dict["monitors"].remove(mon) if datasets: out_dict["datasets"] = config_dict["datasets"] - for i in list(out_dict["datasets"]): - if i not in datasets: - del out_dict["datasets"][i] + to_remove = [] + for dat in out_dict["datasets"]: + if dat["Name"] not in datasets: + to_remove.append(dat) + for dat in to_remove: + out_dict["datasets"].remove(dat) out_dict["datasets"] = config_dict["datasets"] if native_components: out_dict["native components"] = config_dict["native components"]