morphopt 4.0.4__tar.gz → 4.0.5__tar.gz
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.
- {morphopt-4.0.4 → morphopt-4.0.5}/PKG-INFO +2 -2
- {morphopt-4.0.4 → morphopt-4.0.5}/pyproject.toml +2 -2
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/constants.py +0 -7
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/optcore/modelparams/parts/box_part.py +2 -2
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/ui/application/editing.py +29 -3
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/ui/application/fields.py +5 -1
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/ui/application/part_sets.py +8 -3
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/ui/application/quickstart.py +2 -4
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/ui/application/updaters.py +14 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/ui/codegen/generator.py +16 -6
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/ui/locales/en-US.json +2 -1
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/ui/locales/zh-CN.json +2 -1
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/ui/model/base_nodes.py +1 -1
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/ui/model/configuration.py +12 -4
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/ui/model/fields.py +1 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/ui/model/node_types/__init__.py +0 -2
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/ui/model/node_types/cad.py +0 -27
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/ui/model/node_types/parts.py +3 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/ui/model/problem.py +94 -36
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/ui/model/registry.py +0 -2
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/ui/visualization/geometry.py +1 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/ui/visualization/scene.py +13 -3
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/ui/widgets/definition_actions.py +42 -19
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/ui/widgets/observation_pages.py +28 -1
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/ui/widgets/param_form.py +1 -1
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/ui/widgets/plot_style.py +5 -11
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/ui/widgets/preview_renderer.py +22 -4
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/ui/widgets/quickstart.py +3 -2
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt.egg-info/PKG-INFO +2 -2
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt.egg-info/requires.txt +1 -1
- {morphopt-4.0.4 → morphopt-4.0.5}/README.md +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/setup.cfg +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/__init__.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/codesign/__init__.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/codesign/constraints.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/codesign/offset_boundary_part.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/codesign/update_offset_boundary_part.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/opt_runner.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/optcore/__init__.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/optcore/controller.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/optcore/history.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/optcore/modelparams/__init__.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/optcore/modelparams/base_model_component.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/optcore/modelparams/baseparam.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/optcore/modelparams/fea/__init__.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/optcore/modelparams/fea/base_component.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/optcore/modelparams/fea/body_force.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/optcore/modelparams/fea/boundary_condition.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/optcore/modelparams/fea/contact.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/optcore/modelparams/fea/couple.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/optcore/modelparams/fea/point_load.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/optcore/modelparams/fea/pressure.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/optcore/modelparams/fea/reference_point.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/optcore/modelparams/fea/spring.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/optcore/modelparams/feaparams.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/optcore/modelparams/geometry.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/optcore/modelparams/materials/__init__.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/optcore/modelparams/materials/base_material.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/optcore/modelparams/materials/homogeneous_material.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/optcore/modelparams/materials/models.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/optcore/modelparams/materialsparams.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/optcore/modelparams/params.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/optcore/modelparams/parts/__init__.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/optcore/modelparams/parts/base_part.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/optcore/modelparams/parts/cad_part.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/optcore/modelparams/parts/inp_part.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/optcore/objfunc.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/optcore/protocal.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/optcore/quadrature.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/optcore/solver.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/optcore/updaters.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/postprocess/__init__.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/postprocess/exporters.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/postprocess/fields.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/postprocess/native.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/shapeopt/__init__.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/shapeopt/boundary_part.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/shapeopt/objectivefuncs/__init__.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/shapeopt/objectivefuncs/basefuncs.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/shapeopt/objectivefuncs/boundarys.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/shapeopt/objectivefuncs/distancesurface.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/shapeopt/objectivefuncs/shapederivative.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/shapeopt/objectivefuncs/surfacefairness.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/shapeopt/objectivefuncs/volumemaximization.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/shapeopt/surfaces/__init__.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/shapeopt/surfaces/base_constraints.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/shapeopt/surfaces/base_surface.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/shapeopt/surfaces/brep_surface.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/shapeopt/surfaces/bsp_constraints.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/shapeopt/surfaces/bsp_surface.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/shapeopt/surfaces/cpgeo_constraints.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/shapeopt/surfaces/cpgeo_surface.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/shapeopt/surfaces/mesh_surface.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/shapeopt/surfaces/nurbs_face.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/shapeopt/update_boundary_part.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/simp/__init__.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/simp/objectivefuncs/__init__.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/simp/objectivefuncs/basefuncs.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/simp/objectivefuncs/boundarys.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/simp/objectivefuncs/densityfield.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/simp/objectivefuncs/sensitivity.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/simp/objectivefuncs/volfrac.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/simp/simpmaterial.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/simp/update_simpmaterial.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/taskoptmization.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/ui/__init__.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/ui/__main__.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/ui/app.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/ui/application/__init__.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/ui/application/cad.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/ui/application/completion.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/ui/application/definitions.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/ui/application/devices.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/ui/application/edit_history.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/ui/application/editor_routing.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/ui/application/expressions.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/ui/application/finite_element.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/ui/application/load_cases.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/ui/application/result_fields.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/ui/application/results.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/ui/application/runs.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/ui/application/surface_export.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/ui/application/validation.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/ui/application/values.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/ui/application_icon.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/ui/assets/morphopt.svg +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/ui/cad_worker.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/ui/codegen/__init__.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/ui/codegen/assets.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/ui/codegen/custom_classes.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/ui/codegen/workspace.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/ui/fea_worker.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/ui/i18n.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/ui/launcher.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/ui/mainwindow.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/ui/model/__init__.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/ui/model/chamberlayout.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/ui/model/loaders.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/ui/model/material_models.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/ui/model/node_types/custom_code.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/ui/model/node_types/loads.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/ui/model/node_types/materials.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/ui/model/node_types/objectives.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/ui/model/node_types/penalties.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/ui/model/node_types/structural.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/ui/model/node_types/surfaces.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/ui/model/node_types/symmetry.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/ui/observe_panel.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/ui/presentation/__init__.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/ui/presentation/edit_history.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/ui/presentation/history.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/ui/presentation/labels.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/ui/presentation/navigation.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/ui/refresh.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/ui/schemes/__init__.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/ui/schemes/base.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/ui/schemes/snippets.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/ui/surface_export_worker.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/ui/theme/__init__.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/ui/theme/manager.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/ui/theme/palette.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/ui/theme/styles/__init__.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/ui/theme/styles/base.qss +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/ui/theme/styles/controls.qss +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/ui/theme/styles/inputs.qss +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/ui/theme/stylesheet.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/ui/theme/themes/__init__.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/ui/theme/themes/dark.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/ui/theme/themes/light.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/ui/visualization/__init__.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/ui/visualization/assets.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/ui/visualization/loads.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/ui/widgets/__init__.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/ui/widgets/asset_browser.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/ui/widgets/case_deletion.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/ui/widgets/codeeditor.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/ui/widgets/collection_controls.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/ui/widgets/controller_editor.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/ui/widgets/custom_classes.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/ui/widgets/definition_manager.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/ui/widgets/edit_history.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/ui/widgets/editor.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/ui/widgets/editor_pages.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/ui/widgets/elided_label.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/ui/widgets/file_dialogs.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/ui/widgets/finite_element.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/ui/widgets/helper_editor.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/ui/widgets/history_dialogs.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/ui/widgets/language_selector.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/ui/widgets/load_cases.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/ui/widgets/model_tree.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/ui/widgets/objective_editor.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/ui/widgets/result_path.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/ui/widgets/run_dialogs.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/ui/widgets/solver_editor.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/ui/widgets/source_view.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/ui/widgets/surface_export.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/ui/widgets/template_insert_dialog.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/ui/widgets/theme_selector.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/ui/widgets/updater_editor.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/ui/widgets/values.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/ui/widgets/viewer.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/ui/widgets/workspace_objective.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/ui/workbench.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/utils/__init__.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/utils/gradient_check.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt/utils/history_read.py +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt.egg-info/SOURCES.txt +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt.egg-info/dependency_links.txt +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt.egg-info/entry_points.txt +0 -0
- {morphopt-4.0.4 → morphopt-4.0.5}/src/morphopt.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: morphopt
|
|
3
|
-
Version: 4.0.
|
|
3
|
+
Version: 4.0.5
|
|
4
4
|
Summary: A morphing optimization framework using PyTorch and torchfea.
|
|
5
5
|
Requires-Python: >=3.12
|
|
6
6
|
Description-Content-Type: text/markdown
|
|
@@ -17,7 +17,7 @@ Requires-Dist: cadquery-ocp>=8.0.1.1.0
|
|
|
17
17
|
Requires-Dist: tabulate>=0.9.0
|
|
18
18
|
Requires-Dist: imageio>=2.37.3
|
|
19
19
|
Requires-Dist: bspmap>=1.0.3
|
|
20
|
-
Requires-Dist: torchfea>=1.1.
|
|
20
|
+
Requires-Dist: torchfea>=1.1.3
|
|
21
21
|
Requires-Dist: trimesh>=4.11.5
|
|
22
22
|
Requires-Dist: networkx>=3.6.1
|
|
23
23
|
Requires-Dist: scipy>=1.17.1
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "morphopt"
|
|
3
|
-
version = "4.0.
|
|
3
|
+
version = "4.0.5"
|
|
4
4
|
description = "A morphing optimization framework using PyTorch and torchfea."
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
requires-python = ">=3.12"
|
|
@@ -18,7 +18,7 @@ dependencies = [
|
|
|
18
18
|
"tabulate>=0.9.0",
|
|
19
19
|
"imageio>=2.37.3",
|
|
20
20
|
"bspmap>=1.0.3",
|
|
21
|
-
"torchfea>=1.1.
|
|
21
|
+
"torchfea>=1.1.3",
|
|
22
22
|
"trimesh>=4.11.5",
|
|
23
23
|
"networkx>=3.6.1",
|
|
24
24
|
"scipy>=1.17.1",
|
|
@@ -80,10 +80,10 @@ class BoxPart(BasePart):
|
|
|
80
80
|
elems_index=torch.arange(len(cells), device=part.nodes.device),
|
|
81
81
|
elems=torch.as_tensor(cells, device=part.nodes.device),
|
|
82
82
|
),
|
|
83
|
-
name="
|
|
83
|
+
name="C3D8",
|
|
84
84
|
)
|
|
85
85
|
if self.mesh_order == 2:
|
|
86
|
-
part.convert_linear_to_quadratic_elements(["
|
|
86
|
+
part.convert_linear_to_quadratic_elements(["C3D8"], ["C3D8"])
|
|
87
87
|
|
|
88
88
|
node_coordinates = part.nodes.detach().cpu().numpy()
|
|
89
89
|
bounds = np.array(
|
|
@@ -152,7 +152,20 @@ def set_node_field(node: Node, key: str, value, problem: ProblemDefinition | Non
|
|
|
152
152
|
if isinstance(node, FEAComponentNode) and key in {*INSTANCE_REFERENCE_FIELDS, *REFERENCE_POINT_FIELDS}:
|
|
153
153
|
return problem.set_component_reference(node, key, value)
|
|
154
154
|
if key == "part_name" and isinstance(node, MaterialNode):
|
|
155
|
-
|
|
155
|
+
previous_part = node.part
|
|
156
|
+
if not problem.set_material_part(node, value):
|
|
157
|
+
return False
|
|
158
|
+
if node.is_updatable and node.part is not previous_part:
|
|
159
|
+
from ..visualization.geometry import PreviewGeometry
|
|
160
|
+
from ..visualization.scene import MessageItem
|
|
161
|
+
|
|
162
|
+
scene = PreviewGeometry().build(problem, "part", node.part)
|
|
163
|
+
bounds = (
|
|
164
|
+
None if any(isinstance(item, MessageItem) for item in scene.items)
|
|
165
|
+
else scene.bounds
|
|
166
|
+
)
|
|
167
|
+
node.bounding_box = list(bounds) if bounds is not None else [0.0] * 6
|
|
168
|
+
return True
|
|
156
169
|
node.set_field(key, value)
|
|
157
170
|
return True
|
|
158
171
|
|
|
@@ -266,13 +279,26 @@ class CustomClassSession:
|
|
|
266
279
|
self._replace_uses(old, name)
|
|
267
280
|
return True
|
|
268
281
|
|
|
282
|
+
def dependent_classes(self, node: CustomClassNode) -> list[CustomClassNode]:
|
|
283
|
+
"""Classes whose inheritance chain includes the selected custom class."""
|
|
284
|
+
names = {node.name}
|
|
285
|
+
while True:
|
|
286
|
+
children = {custom.name for custom in self.problem.custom_classes
|
|
287
|
+
if custom.base_class in names}
|
|
288
|
+
if children <= names:
|
|
289
|
+
break
|
|
290
|
+
names.update(children)
|
|
291
|
+
return [custom for custom in self.problem.custom_classes
|
|
292
|
+
if custom is not node and custom.name in names]
|
|
293
|
+
|
|
269
294
|
def remove(
|
|
270
295
|
self, node: CustomClassNode | MethodOverrideNode | CustomFunctionNode
|
|
271
296
|
) -> CustomClassNode | None:
|
|
272
297
|
from ..model.problem import CustomClassNode
|
|
273
298
|
if isinstance(node, CustomClassNode):
|
|
274
|
-
self.
|
|
275
|
-
|
|
299
|
+
for custom in [node, *self.dependent_classes(node)]:
|
|
300
|
+
self.problem.custom_classes.remove(custom)
|
|
301
|
+
self._replace_uses(custom.name, "")
|
|
276
302
|
return None
|
|
277
303
|
owner = next(custom for custom in self.problem.custom_classes if node in custom.members)
|
|
278
304
|
owner.remove_child(node)
|
|
@@ -119,11 +119,15 @@ class SnippetInputs:
|
|
|
119
119
|
self.problem = problem
|
|
120
120
|
|
|
121
121
|
def values(self, source: str) -> list:
|
|
122
|
+
catalog = PartSetCatalog(self.problem)
|
|
122
123
|
providers = {
|
|
123
124
|
"load_steps": lambda: list(self.problem.steps.step_values) if self.problem.steps else [],
|
|
124
125
|
"instances": self.problem.instance_names,
|
|
125
126
|
"reference_points": self.problem.reference_point_names,
|
|
126
|
-
"elements":
|
|
127
|
+
"elements": lambda: list(dict.fromkeys(
|
|
128
|
+
name for part in self.problem.parts()
|
|
129
|
+
for name in catalog.for_part(part).elements
|
|
130
|
+
)),
|
|
127
131
|
"force_loads": lambda: [
|
|
128
132
|
node.name
|
|
129
133
|
for node in self.problem.fea_components()
|
|
@@ -91,8 +91,11 @@ class PartSetCatalog:
|
|
|
91
91
|
*metadata.get("node_sets", {}))
|
|
92
92
|
)
|
|
93
93
|
return PartSets(
|
|
94
|
-
nodes=tuple(names) + end_nodes + tuple(f"{name}_nodes" for name in faces) + tuple(node_sets),
|
|
95
|
-
surfaces=tuple(
|
|
94
|
+
nodes=("all", "surface_all") + tuple(names) + end_nodes + tuple(f"{name}_nodes" for name in faces) + tuple(node_sets),
|
|
95
|
+
surfaces=tuple(dict.fromkeys([
|
|
96
|
+
"extern", part.exterior_surface or "extern", *names, *faces, *surface_sets,
|
|
97
|
+
])),
|
|
98
|
+
elements=("C3D4", "C3D6") if isinstance(part, OffsetBoundaryPartNode) else ("C3D4",),
|
|
96
99
|
)
|
|
97
100
|
|
|
98
101
|
@staticmethod
|
|
@@ -100,7 +103,7 @@ class PartSetCatalog:
|
|
|
100
103
|
return PartSets(
|
|
101
104
|
nodes=("all",) + tuple(f"nodes_{axis}{side}" for axis in "xyz" for side in ("min", "max")),
|
|
102
105
|
surfaces=(part.exterior_surface or "extern",) + tuple(f"surface_{axis}{side}" for axis in "xyz" for side in ("min", "max")),
|
|
103
|
-
elements=("
|
|
106
|
+
elements=("C3D8",),
|
|
104
107
|
)
|
|
105
108
|
|
|
106
109
|
@staticmethod
|
|
@@ -109,6 +112,8 @@ class PartSetCatalog:
|
|
|
109
112
|
return PartSets(
|
|
110
113
|
nodes=("all", "surface_all") + tuple(f"{name}_nodes" for name in names),
|
|
111
114
|
surfaces=tuple(dict.fromkeys([part.exterior_surface or "extern", *names])),
|
|
115
|
+
# Quadratic conversion preserves the element block's name.
|
|
116
|
+
elements=("C3D4",),
|
|
112
117
|
)
|
|
113
118
|
|
|
114
119
|
@staticmethod
|
|
@@ -578,7 +578,7 @@ def _topology(options, geometry, loads, materials):
|
|
|
578
578
|
loads.add_component(FEAComponentNode.create("ConcentratedForce", name="tip_force", rp_name="RP_tip"))
|
|
579
579
|
materials.add_material(MaterialNode.create(
|
|
580
580
|
"SIMP_BSPFieldMaterials", name="density", part_name="body",
|
|
581
|
-
elementname="
|
|
581
|
+
elementname="C3D8", material_model="NeoHookeanLnJ", mu=options.mu,
|
|
582
582
|
kappa=options.kappa, mumax=options.mu, kappamax=options.kappa,
|
|
583
583
|
bounding_box=[0., options.total_length, 0., options.height, 0., options.depth],
|
|
584
584
|
degree=CONSTANT.UI.QUICKSTART.GENERATION.SIMP_DEGREE,
|
|
@@ -604,7 +604,7 @@ def _topology(options, geometry, loads, materials):
|
|
|
604
604
|
{"type": "VolFrac", "params": {
|
|
605
605
|
"volfrac_min": options.volume_fraction, "volfrac_max": options.volume_fraction,
|
|
606
606
|
"penalty": CONSTANT.UI.QUICKSTART.GENERATION.SIMP_VOLUME_FRACTION_PENALTY,
|
|
607
|
-
"elementname": "
|
|
607
|
+
"elementname": "C3D8",
|
|
608
608
|
}},
|
|
609
609
|
],
|
|
610
610
|
}],
|
|
@@ -693,8 +693,6 @@ class ObjectiveDraft:
|
|
|
693
693
|
return len(self.objectives) - 1
|
|
694
694
|
|
|
695
695
|
def remove(self, index: int) -> None:
|
|
696
|
-
if len(self.objectives) <= CONSTANT.UI.QUICKSTART.LIMITS.OBJECTIVE_MIN_COUNT:
|
|
697
|
-
raise ValueError(localized_message("ui.errors.quickstart.keep_at_least_one_objective_term"))
|
|
698
696
|
self.objectives.pop(index)
|
|
699
697
|
|
|
700
698
|
def set_method(self, method: str) -> None:
|
|
@@ -135,6 +135,18 @@ class UpdaterItems:
|
|
|
135
135
|
) if custom.name not in taken)
|
|
136
136
|
return choices
|
|
137
137
|
|
|
138
|
+
def default_element_name(self) -> str:
|
|
139
|
+
"""Use the material's block, or the sole block of its owning Part."""
|
|
140
|
+
from .part_sets import PartSetCatalog
|
|
141
|
+
|
|
142
|
+
material = self.problem.config_material_node(self.config)
|
|
143
|
+
if material is None:
|
|
144
|
+
return ""
|
|
145
|
+
if material.elementname:
|
|
146
|
+
return material.elementname
|
|
147
|
+
elements = PartSetCatalog(self.problem).for_part(material.part).elements
|
|
148
|
+
return elements[0] if len(elements) == 1 else ""
|
|
149
|
+
|
|
138
150
|
def add(self, item_type: str, custom_class: str = "") -> bool:
|
|
139
151
|
item = symmetry_item(item_type, self.surfaces) if self.category == "geometry_symmetry" else updater_item(
|
|
140
152
|
item_type,
|
|
@@ -143,6 +155,8 @@ class UpdaterItems:
|
|
|
143
155
|
)
|
|
144
156
|
if item is None:
|
|
145
157
|
return False
|
|
158
|
+
if self.group == "materials" and item_type == "VolFrac":
|
|
159
|
+
item["params"]["elementname"] = self.default_element_name()
|
|
146
160
|
self.config.setdefault(self.key, []).append(item)
|
|
147
161
|
return True
|
|
148
162
|
|
|
@@ -562,8 +562,8 @@ def generate_base_source(
|
|
|
562
562
|
|
|
563
563
|
Code-launched runs never open an observer window; results are watched by
|
|
564
564
|
the MorphOpt UI's in-window observer (disk polling per iteration).
|
|
565
|
-
``for_class_catalog`` emits inert objective methods
|
|
566
|
-
also works while
|
|
565
|
+
``for_class_catalog`` emits inert objective methods and updater classes so
|
|
566
|
+
editor class discovery also works while terms are still being defined.
|
|
567
567
|
"""
|
|
568
568
|
if asset_paths is None:
|
|
569
569
|
asset_paths, _ = collect_python_assets(problem)
|
|
@@ -672,7 +672,7 @@ def generate_base_source(
|
|
|
672
672
|
a("")
|
|
673
673
|
|
|
674
674
|
# -------- Updater -----------------------------------------------------
|
|
675
|
-
_emit_updater(a, problem, template, upd_device)
|
|
675
|
+
_emit_updater(a, problem, template, upd_device, for_class_catalog=for_class_catalog)
|
|
676
676
|
|
|
677
677
|
# -------- main --------------------------------------------------------
|
|
678
678
|
a("")
|
|
@@ -800,7 +800,7 @@ def _emit_part_classes(
|
|
|
800
800
|
a(" def define_instance(self) -> None:")
|
|
801
801
|
instances = part.instances
|
|
802
802
|
if not instances:
|
|
803
|
-
a("
|
|
803
|
+
a(" pass")
|
|
804
804
|
for instance in instances:
|
|
805
805
|
a("")
|
|
806
806
|
pose = (
|
|
@@ -1155,6 +1155,8 @@ def _emit_updater(
|
|
|
1155
1155
|
problem: ProblemDefinition,
|
|
1156
1156
|
template: SchemeTemplate,
|
|
1157
1157
|
device: str,
|
|
1158
|
+
*,
|
|
1159
|
+
for_class_catalog: bool = False,
|
|
1158
1160
|
) -> None:
|
|
1159
1161
|
from .custom_classes import updater_class_name
|
|
1160
1162
|
|
|
@@ -1203,10 +1205,10 @@ def _emit_updater(
|
|
|
1203
1205
|
if target.type == "OffsetBoundaryPart"
|
|
1204
1206
|
else GEOMETRY_UPDATER_BASE
|
|
1205
1207
|
)
|
|
1206
|
-
_emit_nested_updater(a, class_name, base, config, problem)
|
|
1208
|
+
_emit_nested_updater(a, class_name, base, config, problem, for_class_catalog=for_class_catalog)
|
|
1207
1209
|
a("")
|
|
1208
1210
|
for class_name, config in zip(material_classes, mat_cfgs):
|
|
1209
|
-
_emit_nested_updater(a, class_name, MATERIAL_UPDATER_BASE, config, problem)
|
|
1211
|
+
_emit_nested_updater(a, class_name, MATERIAL_UPDATER_BASE, config, problem, for_class_catalog=for_class_catalog)
|
|
1210
1212
|
a("")
|
|
1211
1213
|
|
|
1212
1214
|
|
|
@@ -1272,6 +1274,8 @@ def _emit_nested_updater(
|
|
|
1272
1274
|
base: str,
|
|
1273
1275
|
cfg,
|
|
1274
1276
|
problem: ProblemDefinition,
|
|
1277
|
+
*,
|
|
1278
|
+
for_class_catalog: bool = False,
|
|
1275
1279
|
) -> None:
|
|
1276
1280
|
"""Emit one sub-updater class.
|
|
1277
1281
|
|
|
@@ -1299,6 +1303,12 @@ def _emit_nested_updater(
|
|
|
1299
1303
|
f"max_step_length={_render_value(cfg.get('max_step_length', defaults.MAX_STEP_LENGTH), problem)})"
|
|
1300
1304
|
)
|
|
1301
1305
|
|
|
1306
|
+
if for_class_catalog:
|
|
1307
|
+
a("")
|
|
1308
|
+
a(" def define_objective(self) -> None:")
|
|
1309
|
+
a(" pass")
|
|
1310
|
+
return
|
|
1311
|
+
|
|
1302
1312
|
body: list[str] = []
|
|
1303
1313
|
# NOTE: the model stores the lists under ``objective_functions`` / ``constraints``
|
|
1304
1314
|
# while the catalogue (UPDATER_CATALOG) is keyed ``objectives`` / ``constraints``.
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
{
|
|
2
|
+
"ui.component.delete_dependencies_title": "Delete bound objects",
|
|
3
|
+
"ui.component.delete_dependencies_message": "Deleting “{component}” will also delete these bound objects:\n{dependencies}\nContinue?",
|
|
2
4
|
"ui.schema.fields.control_point_spacing.label": "Target control point spacing",
|
|
3
5
|
"ui.schema.fields.design_faces.label": "Design faces",
|
|
4
6
|
"ui.assets.brep_metadata": "BREP topology and sets",
|
|
@@ -762,7 +764,6 @@
|
|
|
762
764
|
"ui.schema.catalog.cad_operation.fuse.label": "Fuse",
|
|
763
765
|
"ui.schema.catalog.cad_operation.cut.label": "Cut",
|
|
764
766
|
"ui.schema.catalog.cad_operation.intersect.label": "Intersect",
|
|
765
|
-
"ui.schema.catalog.cad_operation.fragment.label": "Fragment",
|
|
766
767
|
"ui.schema.catalog.cad_operation.translate.label": "Translate",
|
|
767
768
|
"ui.schema.catalog.cad_operation.rotate.label": "Rotate",
|
|
768
769
|
"ui.schema.catalog.cad_operation.dilate.label": "Scale",
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
{
|
|
2
|
+
"ui.component.delete_dependencies_title": "删除绑定对象",
|
|
3
|
+
"ui.component.delete_dependencies_message": "删除“{component}”将同时删除以下绑定对象:\n{dependencies}\n是否继续?",
|
|
2
4
|
"ui.schema.fields.control_point_spacing.label": "控制点目标间距",
|
|
3
5
|
"ui.schema.fields.design_faces.label": "参与更新的面",
|
|
4
6
|
"ui.assets.brep_metadata": "BREP 拓扑与集合",
|
|
@@ -762,7 +764,6 @@
|
|
|
762
764
|
"ui.schema.catalog.cad_operation.fuse.label": "融合",
|
|
763
765
|
"ui.schema.catalog.cad_operation.cut.label": "切除",
|
|
764
766
|
"ui.schema.catalog.cad_operation.intersect.label": "相交",
|
|
765
|
-
"ui.schema.catalog.cad_operation.fragment.label": "碎片分割",
|
|
766
767
|
"ui.schema.catalog.cad_operation.translate.label": "平移",
|
|
767
768
|
"ui.schema.catalog.cad_operation.rotate.label": "旋转",
|
|
768
769
|
"ui.schema.catalog.cad_operation.dilate.label": "缩放",
|
|
@@ -427,7 +427,7 @@ class PartNode(TypedNode):
|
|
|
427
427
|
super().__init__(
|
|
428
428
|
kind=kind, name=name, params=data, children=children
|
|
429
429
|
)
|
|
430
|
-
if not self.instances:
|
|
430
|
+
if not self.instances and children is None:
|
|
431
431
|
from .node_types.structural import InstanceNode
|
|
432
432
|
|
|
433
433
|
self.add_instance(InstanceNode(name=f"{self.assembly_name or 'part'}-1"))
|
|
@@ -84,21 +84,29 @@ def materials_updater_config(
|
|
|
84
84
|
max_step_iter: int = 50,
|
|
85
85
|
max_step_length: float = CONSTANT.KERNEL.SIMP_UPDATE.MAX_STEP_LENGTH,
|
|
86
86
|
if_update: bool | list[bool] = True,
|
|
87
|
-
objective_functions: tuple =
|
|
88
|
-
constraints: tuple =
|
|
87
|
+
objective_functions: tuple | None = None,
|
|
88
|
+
constraints: tuple | None = None,
|
|
89
89
|
) -> dict:
|
|
90
90
|
"""Config of one material sub-optimizer.
|
|
91
91
|
|
|
92
92
|
``material_name`` is the material definition it updates; an empty name
|
|
93
93
|
means "the only design-carrying material in the model".
|
|
94
|
+
New configs include sensitivity, variable bounds and volume fraction.
|
|
95
|
+
Explicitly empty collections remain empty.
|
|
94
96
|
"""
|
|
95
97
|
return {
|
|
96
98
|
"material_name": str(material_name or ""),
|
|
97
99
|
"max_step_iter": int(max_step_iter),
|
|
98
100
|
"max_step_length": float(max_step_length),
|
|
99
101
|
"if_update": if_update,
|
|
100
|
-
"objective_functions": list(objective_functions)
|
|
101
|
-
|
|
102
|
+
"objective_functions": list(objective_functions) if objective_functions is not None else [
|
|
103
|
+
updater_objective("Sensitivity"),
|
|
104
|
+
],
|
|
105
|
+
"constraints": list(constraints) if constraints is not None else [
|
|
106
|
+
updater_constraint("MinValue"),
|
|
107
|
+
updater_constraint("MaxValue"),
|
|
108
|
+
updater_constraint("VolFrac"),
|
|
109
|
+
],
|
|
102
110
|
}
|
|
103
111
|
|
|
104
112
|
|
|
@@ -6,7 +6,6 @@ from .cad import (
|
|
|
6
6
|
CutOperationNode,
|
|
7
7
|
CylinderOperationNode,
|
|
8
8
|
DilateOperationNode,
|
|
9
|
-
FragmentOperationNode,
|
|
10
9
|
FuseOperationNode,
|
|
11
10
|
IntersectOperationNode,
|
|
12
11
|
MirrorOperationNode,
|
|
@@ -127,7 +126,6 @@ __all__ = (
|
|
|
127
126
|
"FairnessPenaltyNode",
|
|
128
127
|
"MeshSurfaceNode",
|
|
129
128
|
"BREPSurfaceNode",
|
|
130
|
-
"FragmentOperationNode",
|
|
131
129
|
"FuseOperationNode",
|
|
132
130
|
"GeometryNode",
|
|
133
131
|
"HelperFunctionNode",
|
|
@@ -418,33 +418,6 @@ class IntersectOperationNode(CADOperationNode):
|
|
|
418
418
|
)
|
|
419
419
|
|
|
420
420
|
|
|
421
|
-
class FragmentOperationNode(CADOperationNode):
|
|
422
|
-
"""UI definition of Fragment."""
|
|
423
|
-
|
|
424
|
-
type_name: ClassVar[str] = "Fragment"
|
|
425
|
-
backend_class: ClassVar[str] = "Fragment"
|
|
426
|
-
label_key: ClassVar[str] = "ui.schema.catalog.cad_operation.fragment.label"
|
|
427
|
-
group: ClassVar[str] = "boolean"
|
|
428
|
-
operation_kind: ClassVar[str] = "fragment"
|
|
429
|
-
Defaults = CONSTANT.UI.SCHEMA_FIELDS.CAD_OPERATIONS.FRAGMENT
|
|
430
|
-
object_id: str
|
|
431
|
-
tool_id: str
|
|
432
|
-
fields: ClassVar[tuple[FieldSpec, ...]] = (
|
|
433
|
-
FieldSpec(
|
|
434
|
-
"object_id",
|
|
435
|
-
"ui.schema.fields.object_id.label.object_id",
|
|
436
|
-
"combo",
|
|
437
|
-
Defaults.OBJECT_ID.DEFAULT,
|
|
438
|
-
),
|
|
439
|
-
FieldSpec(
|
|
440
|
-
"tool_id",
|
|
441
|
-
"ui.schema.fields.tool_id.label.tool_id",
|
|
442
|
-
"combo",
|
|
443
|
-
Defaults.TOOL_ID.DEFAULT,
|
|
444
|
-
),
|
|
445
|
-
)
|
|
446
|
-
|
|
447
|
-
|
|
448
421
|
class TranslateOperationNode(CADOperationNode):
|
|
449
422
|
"""UI definition of Translate."""
|
|
450
423
|
|
|
@@ -87,6 +87,7 @@ class BoundaryPartNode(PartNode):
|
|
|
87
87
|
Defaults.MESH_ORDER.DEFAULT,
|
|
88
88
|
doc_key="ui.schema.fields.mesh_order.help.element_order_of_the_generated_mesh",
|
|
89
89
|
choices=Defaults.MESH_ORDER.CHOICES,
|
|
90
|
+
editable=False,
|
|
90
91
|
),
|
|
91
92
|
FieldSpec(
|
|
92
93
|
"exterior_surface",
|
|
@@ -210,6 +211,7 @@ class BoxPartNode(PartNode):
|
|
|
210
211
|
Defaults.MESH_ORDER.DEFAULT,
|
|
211
212
|
doc_key="ui.schema.fields.mesh_order.help.text",
|
|
212
213
|
choices=Defaults.MESH_ORDER.CHOICES,
|
|
214
|
+
editable=False,
|
|
213
215
|
),
|
|
214
216
|
FieldSpec(
|
|
215
217
|
"exterior_surface",
|
|
@@ -308,6 +310,7 @@ class CADPartNode(PartNode):
|
|
|
308
310
|
Defaults.MESH_ORDER.DEFAULT,
|
|
309
311
|
doc_key="ui.schema.fields.mesh_order.help.text",
|
|
310
312
|
choices=Defaults.MESH_ORDER.CHOICES,
|
|
313
|
+
editable=False,
|
|
311
314
|
),
|
|
312
315
|
FieldSpec(
|
|
313
316
|
"exterior_surface",
|
|
@@ -8,6 +8,7 @@ from __future__ import annotations
|
|
|
8
8
|
|
|
9
9
|
from collections.abc import Iterator
|
|
10
10
|
from copy import deepcopy
|
|
11
|
+
import re
|
|
11
12
|
|
|
12
13
|
from ...constants import CONSTANT
|
|
13
14
|
from ..i18n import localized_message
|
|
@@ -715,6 +716,26 @@ class ProblemDefinition:
|
|
|
715
716
|
)
|
|
716
717
|
)
|
|
717
718
|
position = owner.surfaces.index(surface)
|
|
719
|
+
for component in self.fea_components():
|
|
720
|
+
for field, attr in INSTANCE_REFERENCE_FIELDS.items():
|
|
721
|
+
if getattr(component, attr) not in owner.instances:
|
|
722
|
+
continue
|
|
723
|
+
suffix = field.removeprefix("instance_name")
|
|
724
|
+
for key in ("surface_name" + suffix, "set_nodes_name" + suffix):
|
|
725
|
+
if not component.has_field(key):
|
|
726
|
+
continue
|
|
727
|
+
name = component.get_field(key) or ""
|
|
728
|
+
if re.fullmatch(r"face_\d+(_nodes)?", name):
|
|
729
|
+
component.set_field(key, "")
|
|
730
|
+
continue
|
|
731
|
+
match = re.fullmatch(r"surface_(\d+)_(.+)", name)
|
|
732
|
+
if match is None:
|
|
733
|
+
continue
|
|
734
|
+
index = int(match[1])
|
|
735
|
+
if index == position:
|
|
736
|
+
component.set_field(key, "")
|
|
737
|
+
elif index > position:
|
|
738
|
+
component.set_field(key, f"surface_{index - 1}_{match[2]}")
|
|
718
739
|
self._remove_surface_state(owner, position)
|
|
719
740
|
owner.remove_child(surface)
|
|
720
741
|
self.align_surface_dependent_state()
|
|
@@ -799,7 +820,7 @@ class ProblemDefinition:
|
|
|
799
820
|
return added
|
|
800
821
|
|
|
801
822
|
def remove_instance(self, instance: InstanceNode) -> None:
|
|
802
|
-
"""Remove
|
|
823
|
+
"""Remove an Instance and clear its optional references."""
|
|
803
824
|
owner = self.owner_of_instance(instance)
|
|
804
825
|
if owner is None:
|
|
805
826
|
raise ValueError(
|
|
@@ -807,17 +828,20 @@ class ProblemDefinition:
|
|
|
807
828
|
"ui.errors.problem.the_instance_is_not_part_of_this_problem"
|
|
808
829
|
)
|
|
809
830
|
)
|
|
810
|
-
if len(owner.instances) <= 1:
|
|
811
|
-
raise ValueError(
|
|
812
|
-
localized_message(
|
|
813
|
-
"ui.errors.problem.a_part_must_keep_at_least_one_instance"
|
|
814
|
-
)
|
|
815
|
-
)
|
|
816
831
|
owner.remove_child(instance)
|
|
817
832
|
for component in self.fea_components():
|
|
833
|
+
if (component.has_field("obj_name") and component.obj_name == instance.name
|
|
834
|
+
and component.obj_type in ("auto", "instance")):
|
|
835
|
+
component.obj_name = ""
|
|
818
836
|
for field, attr in INSTANCE_REFERENCE_FIELDS.items():
|
|
819
837
|
if getattr(component, attr) is instance:
|
|
820
838
|
component.set_reference(field, None)
|
|
839
|
+
suffix = field.removeprefix("instance_name")
|
|
840
|
+
for key in ("surface_name" + suffix, "set_nodes_name" + suffix,
|
|
841
|
+
"element_name" + suffix):
|
|
842
|
+
if component.has_field(key):
|
|
843
|
+
component.set_field(key, "")
|
|
844
|
+
self._clear_objective_reference("instance_name", instance.name)
|
|
821
845
|
|
|
822
846
|
def move_instance(self, instance: InstanceNode, offset: int) -> bool:
|
|
823
847
|
"""Move an Instance in its Part's declaration order."""
|
|
@@ -850,8 +874,8 @@ class ProblemDefinition:
|
|
|
850
874
|
)
|
|
851
875
|
return part.add_cad_operation(operation)
|
|
852
876
|
|
|
853
|
-
def
|
|
854
|
-
"""
|
|
877
|
+
def cad_operation_dependents(self, operation: CADOperationNode) -> list[CADOperationNode]:
|
|
878
|
+
"""Return all features transitively dependent on this operation."""
|
|
855
879
|
owner = self.owner_of_cad_operation(operation)
|
|
856
880
|
if owner is None:
|
|
857
881
|
raise ValueError(
|
|
@@ -859,22 +883,34 @@ class ProblemDefinition:
|
|
|
859
883
|
"ui.errors.problem.the_cad_operation_is_not_part_of_this_problem"
|
|
860
884
|
)
|
|
861
885
|
)
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
owner.
|
|
886
|
+
removed = {operation.operation_id}
|
|
887
|
+
while True:
|
|
888
|
+
dependent_ids = {
|
|
889
|
+
item.operation_id for item in owner.operations
|
|
890
|
+
if removed.intersection((item.object_id, item.tool_id, item.input_id))
|
|
891
|
+
}
|
|
892
|
+
if dependent_ids <= removed:
|
|
893
|
+
break
|
|
894
|
+
removed.update(dependent_ids)
|
|
895
|
+
return [item for item in owner.operations
|
|
896
|
+
if item is not operation and item.operation_id in removed]
|
|
897
|
+
|
|
898
|
+
def remove_cad_operation(self, operation: CADOperationNode) -> None:
|
|
899
|
+
"""Remove a CAD feature and its dependent features after UI confirmation."""
|
|
900
|
+
dependents = self.cad_operation_dependents(operation)
|
|
901
|
+
owner = self.owner_of_cad_operation(operation)
|
|
902
|
+
for item in [operation, *dependents]:
|
|
903
|
+
owner.remove_child(item)
|
|
904
|
+
for component in self.fea_components():
|
|
905
|
+
for field, attr in INSTANCE_REFERENCE_FIELDS.items():
|
|
906
|
+
if getattr(component, attr) not in owner.instances:
|
|
907
|
+
continue
|
|
908
|
+
suffix = field.removeprefix("instance_name")
|
|
909
|
+
for key in ("surface_name" + suffix, "set_nodes_name" + suffix):
|
|
910
|
+
if component.has_field(key) and re.fullmatch(
|
|
911
|
+
r"face_\d+(_nodes)?", component.get_field(key) or ""
|
|
912
|
+
):
|
|
913
|
+
component.set_field(key, "")
|
|
878
914
|
|
|
879
915
|
def move_cad_operation(self, operation: CADOperationNode, offset: int) -> bool:
|
|
880
916
|
"""Move one CAD feature without disturbing other Part children."""
|
|
@@ -1007,17 +1043,21 @@ class ProblemDefinition:
|
|
|
1007
1043
|
if material.part is part:
|
|
1008
1044
|
material.part = None
|
|
1009
1045
|
material._part_name = ""
|
|
1046
|
+
material.elementname = ""
|
|
1047
|
+
if self.updater is not None:
|
|
1048
|
+
for config in self.updater.materials:
|
|
1049
|
+
if config.get("target") is material:
|
|
1050
|
+
for item in config.get("constraints", []):
|
|
1051
|
+
if "elementname" in item.get("params", {}):
|
|
1052
|
+
item["params"]["elementname"] = ""
|
|
1010
1053
|
if self.updater is not None:
|
|
1011
1054
|
self.updater.geometry[:] = [
|
|
1012
1055
|
config
|
|
1013
1056
|
for config in self.updater.geometry
|
|
1014
1057
|
if config.get("target") is not part
|
|
1015
1058
|
]
|
|
1016
|
-
for instance in part.instances:
|
|
1017
|
-
|
|
1018
|
-
for field, attr in INSTANCE_REFERENCE_FIELDS.items():
|
|
1019
|
-
if getattr(load, attr) is instance:
|
|
1020
|
-
load.set_reference(field, None)
|
|
1059
|
+
for instance in list(part.instances):
|
|
1060
|
+
self.remove_instance(instance)
|
|
1021
1061
|
geometry.remove_child(part)
|
|
1022
1062
|
self.align_surface_dependent_state()
|
|
1023
1063
|
self._refresh_surface_flags()
|
|
@@ -1088,12 +1128,6 @@ class ProblemDefinition:
|
|
|
1088
1128
|
"ui.errors.problem.material_is_not_part_of_this_problem"
|
|
1089
1129
|
)
|
|
1090
1130
|
)
|
|
1091
|
-
if len(section.assignments) <= 1:
|
|
1092
|
-
raise ValueError(
|
|
1093
|
-
localized_message(
|
|
1094
|
-
"ui.errors.problem.a_problem_must_keep_at_least_one_material"
|
|
1095
|
-
)
|
|
1096
|
-
)
|
|
1097
1131
|
section.remove_child(material)
|
|
1098
1132
|
if self.updater is not None:
|
|
1099
1133
|
self.updater.materials[:] = [
|
|
@@ -1155,9 +1189,33 @@ class ProblemDefinition:
|
|
|
1155
1189
|
item for item in self.objective.jacobian_needed if item is not component
|
|
1156
1190
|
]
|
|
1157
1191
|
for load in self.fea_components():
|
|
1192
|
+
if load.has_field("obj_name") and load.obj_name == component.name:
|
|
1193
|
+
load.obj_name = ""
|
|
1158
1194
|
for field, attr in REFERENCE_POINT_FIELDS.items():
|
|
1159
1195
|
if getattr(load, attr) is component:
|
|
1160
1196
|
load.set_reference(field, None)
|
|
1197
|
+
if component.type == "ReferencePoint":
|
|
1198
|
+
self._clear_objective_reference("reference_point_name", component.name)
|
|
1199
|
+
else:
|
|
1200
|
+
for key in ("force_load_name", "moment_load_name"):
|
|
1201
|
+
self._clear_objective_reference(key, component.name)
|
|
1202
|
+
if self.objective is not None:
|
|
1203
|
+
for term in self.objective.objective_terms:
|
|
1204
|
+
if term.get("type") != "workspace":
|
|
1205
|
+
continue
|
|
1206
|
+
for entry in term.get("inputs", []):
|
|
1207
|
+
entry["parameters"] = [pair for pair in entry["parameters"]
|
|
1208
|
+
if pair[0] != component.name]
|
|
1209
|
+
term["inputs"] = [entry for entry in term.get("inputs", [])
|
|
1210
|
+
if entry["parameters"]]
|
|
1211
|
+
|
|
1212
|
+
def _clear_objective_reference(self, key: str, name: str) -> None:
|
|
1213
|
+
"""Clear explicit objective and metric references to a deleted object."""
|
|
1214
|
+
if self.objective is None:
|
|
1215
|
+
return
|
|
1216
|
+
for term in [*self.objective.objective_terms, *self.objective.metrics_terms]:
|
|
1217
|
+
if term.get(key) == name:
|
|
1218
|
+
term[key] = ""
|
|
1161
1219
|
|
|
1162
1220
|
def rename_definition(
|
|
1163
1221
|
self,
|