def on_ok(self): """ Saves the dialog settings on the data structure. """ info_dialog( __("This will apply the initials properties to all objects with mkfluid = " ) + str(self.target_mk)) if self.has_initials_selector.currentIndex() == 1: # Initials false Case.the().get_mk_based_properties(ObjectType.FLUID, self.target_mk).initials = None else: # Initials true # Structure: InitialsProperty Object force_vector: list = [ float(self.initials_vector_input_x.text()), float(self.initials_vector_input_y.text()), float(self.initials_vector_input_z.text()) ] Case.the().get_mk_based_properties( ObjectType.FLUID, self.target_mk).initials = InitialsProperty( mk=self.target_mk, force=force_vector, initials_type=self.initials_type_selector.currentIndex(), v1=float(self.initials_velocities_v1_input.text()), v2=float(self.initials_velocities_v2_input.text()), v3=float(self.initials_velocities_v3_input.text()), z1=float(self.initials_velocities_z1_input.text()), z2=float(self.initials_velocities_z2_input.text()), z3=float(self.initials_velocities_z3_input.text())) self.accept()
def on_ok(self): """ Composes floating options and saves them into the appropriate data structure. """ info_dialog(__("This will apply the floating properties to all objects with mkbound = ") + str(self.target_mk)) if self.is_floating_selector.currentIndex() == 1: # Remove Floating Case.the().get_mk_based_properties(ObjectType.BOUND, self.target_mk).float_property = None self.accept() return # Floating is true fp = FloatProperty() # FloatProperty to be inserted fp.mk = self.target_mk fp.mass_density_type = self.floating_props_massrhop_selector.currentIndex() fp.mass_density_value = float(self.floating_props_massrhop_input.text()) fp.gravity_center = list() if self.floating_center_auto.isChecked() else [float(self.floating_center_input_x.text()), float(self.floating_center_input_y.text()), float(self.floating_center_input_z.text())] fp.inertia = list() if self.floating_inertia_auto.isChecked() else [float(self.floating_inertia_input_x.text()), float(self.floating_inertia_input_y.text()), float(self.floating_inertia_input_z.text())] fp.initial_linear_velocity = list() if self.floating_velini_auto.isChecked() else [float(self.floating_velini_input_x.text()), float(self.floating_velini_input_y.text()), float(self.floating_velini_input_z.text())] fp.initial_angular_velocity = list() if self.floating_omegaini_auto.isChecked() else [float(self.floating_omegaini_input_x.text()), float(self.floating_omegaini_input_y.text()), float(self.floating_omegaini_input_z.text())] fp.translation_restriction = list() if self.floating_translation_auto.isChecked() else [int(self.floating_translation_input_x.currentIndex()), int(self.floating_translation_input_y.currentIndex()), int(self.floating_translation_input_z.currentIndex())] fp.rotation_restriction = list() if self.floating_rotation_auto.isChecked() else [int(self.floating_rotation_input_x.currentIndex()), int(self.floating_rotation_input_y.currentIndex()), int(self.floating_rotation_input_z.currentIndex())] fp.material = "" if self.floating_material_auto.isChecked() else str(self.floating_material_line_edit.text()) Case.the().get_mk_based_properties(ObjectType.BOUND, self.target_mk).float_property = fp self.accept()
def on_file_browse(self): """ Opens a file browser dialog and sets the path on the widget. """ filename, _ = QtGui.QFileDialog.getOpenFileName( self, __("Open file"), Case.the().info.last_used_directory) Case.the().info.update_last_used_directory(filename) self.filename_input.setText(filename)
def refresh(self) -> None: """ Deletes everything and refreshes contents with the current simulation objects. """ self.clear_table_contents() num_objects_in_simulation: int = Case.the( ).number_of_objects_in_simulation() self.set_table_row_count(num_objects_in_simulation) current_row = 0 for sim_object in Case.the().objects: if sim_object.name == CASE_LIMITS_OBJ_NAME: continue target_widget = ObjectOrderWidget(index=current_row, object_mk=sim_object.obj_mk, mktype=sim_object.type, object_name=get_fc_object( sim_object.name).Label, parent=self) if current_row == 0: target_widget.disable_up() if current_row == num_objects_in_simulation - 1: target_widget.disable_down() self.set_table_cell_widget(current_row, 0, target_widget) current_row += 1
def on_browse(self): """ Opens a file dialog to select a file to use. """ file_name, _ = QtGui.QFileDialog().getOpenFileName( self, "Select file to use", Case.the().info.last_used_directory) Case.the().info.update_last_used_directory(file_name) self.accinput_datafile_input.setText(file_name)
def selection_monitor(properties_widget, designsphysics_dock): """ Watches and fixes unwanted changes in the current selection. """ time.sleep(2.0) while True: try: if not valid_document_environment(): log("Invalid document environment found. Disabling case-related tools." ) designsphysics_dock.adapt_to_no_case() time.sleep(1.0) continue if not FreeCADGui.Selection.getSelection(): properties_widget.configure_to_no_selection() enforce_case_limits_restrictions(Case.the().mode3d) enforce_fillbox_restrictions() # Adjust damping properties when freecad related properties change for name, damping_zone in Case.the().damping_zones.items(): if FreeCAD.ActiveDocument: damping_group = FreeCAD.ActiveDocument.getObject(name) if len(damping_group.OutList) == 2: damping_zone.overlimit = damping_group.OutList[ 1].Length.Value / DIVIDER time.sleep(0.5) except AttributeError: time.sleep(1.0)
def on_mkgroup_change(self, value): """ Defines what happens when MKGroup is changed. """ new_value: int = value old_value: int = self.last_mk_value # First we do what the user want Case.the().get_simulation_object( FreeCADGui.Selection.getSelection()[0].Name).obj_mk = new_value self.last_mk_value = new_value # Then we check that it is sensible orphan_mkbasedproperties: list = Case.the( ).get_orphan_mkbasedproperties() if orphan_mkbasedproperties: response = ok_cancel_dialog( __("Changing MK value"), __("By doing this you will loose all MK configuration for the previous MK: {}. Are you sure you want to do this?" ).format(old_value)) if response == QtGui.QMessageBox.Ok: debug( "Changing from mk {} to {} caused orphan mkbasedproperties. Deleting..." .format(old_value, new_value)) Case.the().delete_orphan_mkbasedproperties() else: self.mkgroup_prop.setValue(old_value)
def on_mgrid_accept(self): """ MeasureTool point grid accept button behaviour.""" Case.the().info.measuretool_grid = list() for self.mgrid_row in range(0, self.mgrid_table.rowCount()): try: self.current_grid = [ float(self.mgrid_table.item(self.mgrid_row, 0).text()), float(self.mgrid_table.item(self.mgrid_row, 1).text()), float(self.mgrid_table.item(self.mgrid_row, 2).text()), float(self.mgrid_table.item(self.mgrid_row, 3).text()), float(self.mgrid_table.item(self.mgrid_row, 4).text()), float(self.mgrid_table.item(self.mgrid_row, 5).text()), float(self.mgrid_table.item(self.mgrid_row, 6).text()), float(self.mgrid_table.item(self.mgrid_row, 7).text()), float(self.mgrid_table.item(self.mgrid_row, 8).text()), float(self.mgrid_table.item(self.mgrid_row, 9).text()), float(self.mgrid_table.item(self.mgrid_row, 10).text()), float(self.mgrid_table.item(self.mgrid_row, 11).text()) ] Case.the().info.measuretool_grid.append(self.current_grid) except (ValueError, AttributeError): pass # Deletes the list of points (not compatible together) Case.the().info.measuretool_points = list() self.accept()
def _fill_data(self) -> None: """ Fills the data passed on the constructor to the different widgets. """ case = Case.the() floating_mkbasedproperties: list = list( filter(lambda mkp: mkp.float_property, case.mkbasedproperties.values())) self.enabled_selector_combobox.setCurrentIndex( 1 if case.moorings.enabled else 0) self.savevtk_combo.setCurrentIndex( 0 if case.moorings.saveoptions.savevtk_moorings else 1) self.savepointscsv_combo.setCurrentIndex( 0 if case.moorings.saveoptions.savecsv_points else 1) self.savepointsvtk_combo.setCurrentIndex( 0 if case.moorings.saveoptions.savevtk_points else 1) self.floating_selection_table.setRowCount( len(floating_mkbasedproperties)) self.configuration_method_combo.setCurrentIndex({ MooringsConfigurationMethod.EMBEDDED: 0, MooringsConfigurationMethod.FROM_XML: 1 }[case.moorings.configuration_method]) self.xml_file_selection_edit.setText(case.moorings.moordyn_xml) for index, mkprop in enumerate(floating_mkbasedproperties): target_widget: MooringsCompatibleFloatingWidget = MooringsCompatibleFloatingWidget( mkprop.mk - MKFLUID_LIMIT in case.moorings.moored_floatings, ObjectType.BOUND, mkprop.mk - MKFLUID_LIMIT) # Offset the mk to convert in mkbound self.floating_selection_table.setCellWidget( index, 0, target_widget)
def on_new_wave_generator(self, action): """ Creates a movement on the project. """ self.notice_label.setText( "") # Reset the notice label if a valid change is made if __("Movement") in action.text(): self.on_new_movement() return if __("Regular wave generator (Piston)") in action.text(): to_add = SpecialMovement(name="Regular Wave Generator (Piston)", generator=RegularPistonWaveGen()) if __("Irregular wave generator (Piston)") in action.text(): to_add = SpecialMovement(name="Irregular Wave Generator (Piston)", generator=IrregularPistonWaveGen()) if __("Regular wave generator (Flap)") in action.text(): to_add = SpecialMovement(name="Regular Wave Generator (Flap)", generator=RegularFlapWaveGen()) if __("Irregular wave generator (Flap)") in action.text(): to_add = SpecialMovement(name="Irregular Wave Generator (Flap)", generator=IrregularFlapWaveGen()) if __("Linear motion from a file") in action.text(): to_add = SpecialMovement(name="Linear motion from a file", generator=FileGen()) if __("Rotation from a file") in action.text(): to_add = SpecialMovement(name="Rotation from a file", generator=RotationFileGen()) Case.the().info.global_movements.append(to_add) self.check_movement_compatibility(to_add) self.movements_selected.append(to_add) self.refresh_movements_table()
def get_objects_info(self) -> str: """ Returns an HTML string with information about the objects in the case. """ each_object_info: list = list() obj: SimulationObject = None for obj in Case.the().objects: if obj.name == CASE_LIMITS_OBJ_NAME: continue is_floating_text: str = "Yes" if Case.the( ).get_mk_based_properties(obj.type, obj.obj_mk).float_property else "No" has_initials_text: str = "Yes" if Case.the( ).get_mk_based_properties(obj.type, obj.obj_mk).initials else "No" to_append = "<li>" to_append += "<b>{}</b> ({})<br>".format( get_fc_object(obj.name).Label, obj.name) to_append += "Type: {type} (MK{type}: <b>{mk}</b> ; MK: <b>{real_mk}</b>)<br/>".format( type=str(obj.type).capitalize(), mk=str(obj.obj_mk), real_mk=str(obj.obj_mk + MKFLUID_OFFSET if obj.type == ObjectType.FLUID else obj.obj_mk + MKFLUID_LIMIT)) to_append += "Fill mode: {}<br/>".format( str(obj.fillmode).capitalize()) to_append += "Floating: {}<br/>".format(is_floating_text) to_append += "Initials: {}</li><br/>".format(has_initials_text) to_append += "</li>" each_object_info.append(to_append) return "<ul>{}</ul>".format( "".join(each_object_info) if each_object_info else "No objects were added to the case.")
def on_save_case(self, save_as=None): """ Defines what happens when save case button is clicked. Saves a freecad scene definition, and a dump of dsph data for the case.""" if Case.the().was_not_saved() or save_as: save_name, _ = QtGui.QFileDialog.getSaveFileName( self, __("Save Case"), Case.the().info.last_used_directory) Case.the().info.update_last_used_directory(save_name) else: save_name = Case.the().path if not save_name: return Case.the().info.needs_to_run_gencase = True save_case(save_name, Case.the()) save_current_freecad_document(Case.the().path) if Case.the().has_materials() and Case.the( ).execution_parameters.rigidalgorithm not in (2, 3): warning_dialog( __("Properties and Material information wasn't written. See details for more info." ), __("The case being saved has some properties/materials defined in one of its MKs.\n" "However, the solid-solid interaction on the execution parameters must be set to DEM or CHRONO for this feature to work." )) self.need_refresh.emit()
def on_outformat_changed(self, index): if index == 1: self.moment_group_box.setChecked(Case.the().custom.moment_checked) self.cfces_plot.setChecked(Case.the().custom.cfces_plot) else: self.moment_group_box.setChecked(False) self.cfces_plot.setChecked(False)
def on_browse(self): """ Opens a file browser to select the external velocity data, then parses it and fills the dialog with the information. """ filename, _ = QtGui.QFileDialog.getOpenFileName( self, __("Open a file from the serie"), Case.the().info.last_used_directory, "External velocity data (*_x*_y*.csv)") Case.the().info.update_last_used_directory(filename) if not filename: return basename: str = path.basename(filename) folder: str = path.dirname(filename) filename_filtered = "{}/{}".format(folder, basename.split("_x")[0]) self.veldata_filevelx_input.setText(str(filename_filtered)) serie_filenames = glob.glob("{}*.csv".format(filename_filtered)) self.temp_mlpiston2d.veldata = list() for serie_filename in serie_filenames: serie_filename = serie_filename.replace("\\", "/") self.temp_mlpiston2d.veldata.append( MLPiston2DVeldata(serie_filename, 0, 0)) self.veldata_files_label.setText( __("The serie has {} files").format( len(self.temp_mlpiston2d.veldata))) self.veldata_posy_input.setText(",".join( [str(x.posy) for x in self.temp_mlpiston2d.veldata])) self.veldata_timedataini_input.setText(",".join( [str(x.timedataini) for x in self.temp_mlpiston2d.veldata]))
def __init__(self, parent=None): super().__init__(parent=parent) self.setWindowTitle(__("Special")) self.setMinimumWidth(200) self.sp_window_layout = QtGui.QVBoxLayout() self.sp_damping_button = QtGui.QPushButton(__("Damping Zone")) self.sp_inlet_button = QtGui.QPushButton(__("Inlet/Outlet")) self.sp_chrono_button = QtGui.QPushButton(__("Project Chrono")) self.sp_multilayeredmb_button = QtGui.QPushButton( __("Multi-layered Piston")) self.sp_multilayeredmb_menu = QtGui.QMenu() self.sp_multilayeredmb_menu.addAction(__("1 Dimension")) self.sp_multilayeredmb_menu.addAction(__("2 Dimensions")) self.sp_multilayeredmb_button.setMenu(self.sp_multilayeredmb_menu) self.sp_relaxationzone_button = QtGui.QPushButton( __("Relaxation Zone")) self.sp_relaxationzone_menu = QtGui.QMenu() self.sp_relaxationzone_menu.addAction(__("Regular waves")) self.sp_relaxationzone_menu.addAction(__("Irregular waves")) self.sp_relaxationzone_menu.addAction(__("External Input")) self.sp_relaxationzone_menu.addAction(__("Uniform velocity")) self.sp_relaxationzone_button.setMenu(self.sp_relaxationzone_menu) self.sp_accinput_button = QtGui.QPushButton(__("Acceleration Inputs")) self.sp_moorings_button = QtGui.QPushButton(__("Moorings")) self.sp_damping_button.clicked.connect(self.on_damping_option) self.sp_inlet_button.clicked.connect(self.on_inlet_option) self.sp_chrono_button.clicked.connect(self.on_chrono_option) self.sp_multilayeredmb_menu.triggered.connect( self.on_multilayeredmb_menu) self.sp_relaxationzone_menu.triggered.connect( self.on_relaxationzone_menu) self.sp_accinput_button.clicked.connect(self.on_accinput_button) self.sp_moorings_button.clicked.connect(self.on_moorings_button) # Add buttons to the special window self.sp_window_layout.addWidget(self.sp_inlet_button) self.sp_window_layout.addWidget(self.sp_accinput_button) self.sp_window_layout.addWidget(self.sp_chrono_button) self.sp_window_layout.addWidget(self.sp_moorings_button) self.sp_window_layout.addWidget(self.sp_damping_button) self.sp_window_layout.addWidget(self.sp_multilayeredmb_button) self.sp_window_layout.addWidget(self.sp_relaxationzone_button) self.setLayout(self.sp_window_layout) if not Case.the().executable_paths.supports_chrono(): self.sp_chrono_button.hide() if not Case.the().executable_paths.supports_moorings( ) and not ApplicationSettings.the().force_moordyn_support_enabled: self.sp_moorings_button.hide() self.exec_()
def on_browse(self): """ Opens a file browser and sets the path for the file on the dialog. """ filename, _ = QtGui.QFileDialog.getOpenFileName( self, __("Open file"), Case.the().info.last_used_directory, "External velocity data (*.csv)") Case.the().info.update_last_used_directory(filename) self.filevelx_input.setText(filename)
def on_movement_name_change(self, row, column): """ Changes the name of a movement on the project. """ target_item = self.movement_list_table.item(row, column) if target_item is not None and Case.the( ).info.global_movements[row].name != target_item.text(): # Reset the notice label if a valid change is made self.notice_label.setText("") Case.the().info.global_movements[row].name = target_item.text()
def on_remove_object_from_sim(self): """ Defines what happens when pressing the remove objects from simulation button. """ for each in FreeCADGui.Selection.getSelection(): if each.Name == "Case_Limits": continue Case.the().remove_object(each.Name) self.need_refresh.emit()
def on_damping_option(self): """ Defines damping button behaviour""" damping_group_name = setup_damping_environment() Case.the().add_damping_group(damping_group_name) DampingConfigDialog(damping_group_name, Case.the(), parent=get_fc_main_window()) self.accept()
def on_mtool_export(self): """ Export button behaviour.""" export_parameters = dict() export_parameters["save_mode"] = self.outformat_combobox.currentIndex() export_parameters["save_vars"] = "-all" if self.mtool_types_chk_all.isChecked(): export_parameters["save_vars"] = "+all" else: if self.mtool_types_chk_vel.isChecked(): export_parameters["save_vars"] += ",+vel" if self.mtool_types_chk_rhop.isChecked(): export_parameters["save_vars"] += ",+rhop" if self.mtool_types_chk_press.isChecked(): export_parameters["save_vars"] += ",+press" if self.mtool_types_chk_mass.isChecked(): export_parameters["save_vars"] += ",+mass" if self.mtool_types_chk_vol.isChecked(): export_parameters["save_vars"] += ",+vol" if self.mtool_types_chk_idp.isChecked(): export_parameters["save_vars"] += ",+idp" if self.mtool_types_chk_ace.isChecked(): export_parameters["save_vars"] += ",+ace" if self.mtool_types_chk_vor.isChecked(): export_parameters["save_vars"] += ",+vor" if self.mtool_types_chk_kcorr.isChecked(): export_parameters["save_vars"] += ",+kcorr" if export_parameters[ "save_vars"] == "-all" and not self.mtool_calculate_elevation.isChecked( ): export_parameters["save_vars"] = "+all" export_parameters[ "calculate_water_elevation"] = self.mtool_calculate_elevation.isChecked( ) if self.mtool_file_name_text.text(): export_parameters["filename"] = self.mtool_file_name_text.text() else: export_parameters["filename"] = "MeasurePart" if self.mtool_parameters_text.text(): export_parameters[ "additional_parameters"] = self.mtool_parameters_text.text() else: export_parameters["additional_parameters"] = "" if not Case.the().info.measuretool_points and not Case.the( ).info.measuretool_grid: error_dialog( __("No points or grid are defined to execute MeasureTool"), __("Please define either list of points or a grid of points to continue. MeasureTool won't be executed." )) else: measuretool_export(export_parameters, Case.the(), self.post_processing_widget) self.accept()
def on_accinput_button(self): """ Acceleration input button behaviour.""" accinput_dialog = AccelerationInputDialog( Case.the().acceleration_input, parent=get_fc_main_window()) result = accinput_dialog.exec_() if result == QtGui.QDialog.Accepted: Case.the().acceleration_input = accinput_dialog.get_result() self.accept()
def on_new_movement(self): """ Creates a movement on the project. """ self.notice_label.setText( "") # Reset the notice label if a valid change is made to_add = Movement(name="New Movement") Case.the().info.global_movements.append(to_add) self.movements_selected.append(to_add) self.check_movement_compatibility(to_add) self.refresh_movements_table()
def on_dsph_sim_finished(exit_code): """ Simulation finish handler. Defines what happens when the process finishes.""" # Reads output from the .out file and completes the progress bar output = "" with open(Case.the().path + "/" + Case.the().name + "_out/Run.out", "r", encoding="utf-8") as run_file: output = "".join(run_file.readlines()) run_dialog.set_detail_text(str(output)) run_dialog.run_complete() run_fs_watcher.removePath(Case.the().path + "/" + Case.the().name + "_out/") if exit_code == 0: # Simulation went correctly Case.the().info.is_simulation_done = True Case.the().info.needs_to_run_gencase = False self.simulation_complete.emit(True) else: # In case of an error Case.the().info.needs_to_run_gencase = True if "exception" in str(output).lower(): log("There was an error on the execution. Opening an error dialog for that." ) run_dialog.hide() self.simulation_complete.emit(False) error_dialog( __("An error occurred during execution. Make sure that parameters exist and are properly defined. " "You can also check your execution device (update the driver of your GPU). Read the details for more information." ), str(output)) save_case(Case.the().path, Case.the())
def _on_ok(self) -> None: """ Reacts to the ok button being pressed. """ if self.enabled_selector_combobox.currentIndex() == 1: Case.the().moorings.enabled = True Case.the( ).moorings.saveoptions.savecsv_points = self.savepointscsv_combo.currentIndex( ) == 0 Case.the( ).moorings.saveoptions.savevtk_moorings = self.savevtk_combo.currentIndex( ) == 0 Case.the( ).moorings.saveoptions.savevtk_points = self.savepointsvtk_combo.currentIndex( ) == 0 Case.the().moorings.configuration_method = { 0: MooringsConfigurationMethod.EMBEDDED, 1: MooringsConfigurationMethod.FROM_XML }[self.configuration_method_combo.currentIndex()] Case.the( ).moorings.moordyn_xml = self.xml_file_selection_edit.text() moored_floatings = Case.the().moorings.moored_floatings for row_num in range(0, self.floating_selection_table.rowCount()): target_widget: MooringsCompatibleFloatingWidget = self.floating_selection_table.cellWidget( row_num, 0) if target_widget.use_checkbox.isChecked( ) and target_widget.mkbound not in moored_floatings: moored_floatings.append(target_widget.mkbound) if not target_widget.use_checkbox.isChecked( ) and target_widget.mkbound in moored_floatings: moored_floatings.remove(target_widget.mkbound) Case.the().moorings.moordyn_configuration = deepcopy( self.moordyn_parameters_data) else: Case.the().moorings = MooringsConfiguration() self.accept()
def box_delete(self, box_id): """ Box delete button behaviour. Tries to find the box for which the button was pressed and deletes it.""" box_to_remove = None for box in Case.the().flowtool_boxes: if box.id == box_id: box_to_remove = box if box_to_remove is not None: Case.the().flowtool_boxes.remove(box_to_remove) self.refresh_boxlist()
def on_add_geo(self): """ Add STL file. Opens a file opener and allows the user to set parameters for the import process """ self.need_refresh.emit() file_name, _ = QtGui.QFileDialog().getOpenFileName( get_fc_main_window(), __("Select GEO to import"), Case.the().info.last_used_directory, "STL Files (*.stl);;PLY Files (*.ply);;VTK Files (*.vtk)") Case.the().info.update_last_used_directory(file_name) if not file_name: return AddGEODialog(file_name, parent=get_fc_main_window())
def geo_dialog_browse(self): """ Defines the browse button behaviour.""" file_name_temp, _ = QtGui.QFileDialog().getOpenFileName( get_fc_main_window(), __("Select GEO to import"), Case.the().info.last_used_directory, "STL Files (*.stl);;PLY Files (*.ply);;VTK Files (*.vtk)") Case.the().info.update_last_used_directory(file_name_temp) if file_name_temp: self.geo_file_path.setText(file_name_temp) self.raise_() self.activateWindow() self.geo_button_ok.setFocus()
def on_add_sinu_rect(self): """ Adds a RectSinuMotion to the timeline of the selected movement. """ self.notice_label.setText( "") # Reset the notice label if a valid change is made if self.movement_list_table.selectedIndexes(): if self.movement_list_table.selectedIndexes()[0].row() != len( Case.the().info.global_movements): Case.the().info.global_movements[ self.movement_list_table.selectedIndexes() [0].row()].add_motion(RectSinuMotion()) self.on_movement_selected( self.movement_list_table.selectedIndexes()[0].row(), None)
def on_objtype_change(self, index): """ Defines what happens when type of object is changed """ selection = FreeCADGui.Selection.getSelection()[0] selectiongui = FreeCADGui.ActiveDocument.getObject(selection.Name) simulation_object = Case.the().get_simulation_object(selection.Name) mk_properties = Case.the().get_mk_based_properties( simulation_object.type, simulation_object.obj_mk) if self.objtype_prop.itemText(index).lower() == "bound": self.mkgroup_prop.setRange(0, 240) if simulation_object.type != ObjectType.BOUND: self.mkgroup_prop.setValue( int(Case.the().get_first_mk_not_used(ObjectType.BOUND))) try: selectiongui.ShapeColor = (0.80, 0.80, 0.80) selectiongui.Transparency = 0 except AttributeError: # Can't change attributes pass self.floatstate_prop.setEnabled(True) self.initials_prop.setEnabled(False) self.set_mkgroup_text("{} <a href='{}'>?</a>".format( __("MKBound"), HelpURL.BASIC_CONCEPTS)) elif self.objtype_prop.itemText(index).lower() == "fluid": self.mkgroup_prop.setRange(0, MKFLUID_LIMIT - MKFLUID_OFFSET - 1) if simulation_object.type != ObjectType.FLUID: self.mkgroup_prop.setValue( int(Case.the().get_first_mk_not_used(ObjectType.FLUID))) try: selectiongui.ShapeColor = (0.00, 0.45, 1.00) selectiongui.Transparency = 30 except AttributeError: # Can't change attributes pass # Remove floating properties if it is changed to fluid if mk_properties.float_property is not None: mk_properties.float_property = None # Remove motion properties if it is changed to fluid if mk_properties.has_movements(): mk_properties.remove_all_movements() self.floatstate_prop.setEnabled(False) self.initials_prop.setEnabled(True) self.set_mkgroup_text("{} <a href='{}'>?</a>".format( __("MKFluid"), HelpURL.BASIC_CONCEPTS)) # Update simulation object type simulation_object.type = ObjectType.FLUID if index == 0 else ObjectType.BOUND self.last_mk_value = int(self.mkgroup_prop.value()) self.need_refresh.emit()
def on_fs_change(): """ Executed each time the filesystem changes. This updates the percentage of the simulation and its details.""" run_file_data = "" with open(Case.the().path + "/" + Case.the().name + "_out/Run.out", "r", encoding="utf-8") as run_file: run_file_data = run_file.readlines() # Fill details window run_dialog.set_detail_text("".join(run_file_data)) # Set percentage scale based on timemax for l in run_file_data: if Case.the().execution_parameters.timemax == -1: if "TimeMax=" in l: Case.the().execution_parameters.timemax = float( l.split("=")[1]) current_value: float = 0.0 totalpartsout: int = 0 last_estimated_time = None # Update execution metrics last_part_lines = list( filter( lambda x: "Part_" in x and "stored" not in x and " " in x, run_file_data)) if last_part_lines: current_value = (float(last_part_lines[-1].split(None)[1]) * float(100)) / float( Case.the().execution_parameters.timemax) else: current_value = None # Update particles out last_particles_out_lines = list( filter(lambda x: "(total: " in x and "Particles out:" in x, run_file_data)) if last_particles_out_lines: totalpartsout = int(last_particles_out_lines[-1].split( "(total: ")[1].split(")")[0]) try: last_estimated_time = str(" ".join( last_part_lines[-1].split(None)[-2:])) except IndexError: last_estimated_time = None # Update run dialog run_dialog.run_update(current_value, totalpartsout, last_estimated_time)