diff --git a/MagnetiCalc-DefaultProject.ini b/MagnetiCalc-DefaultProject.ini index 9d1f4f7..4409458 100644 --- a/MagnetiCalc-DefaultProject.ini +++ b/MagnetiCalc-DefaultProject.ini @@ -1,5 +1,5 @@ [DEFAULT] -version = MagnetiCalc v1.12.0 +version = MagnetiCalc v1.12.1 backend_type = 1 auto_calculation = True num_cores = 0 diff --git a/README.md b/README.md index d104677..16a44d9 100644 --- a/README.md +++ b/README.md @@ -125,16 +125,14 @@ Installation will currently fail for Python 3.9+ due to missing dependencies. On some systems, it may be necessary to install the latest [Microsoft Visual C++ Redistributable](https://docs.microsoft.com/en-us/cpp/windows/latest-supported-vc-redist?view=msvc-170) first. -#### macOS +#### macOS with Apple Silicon (M1) On Apple Silicon, make sure to enable [Open Using Rosetta](https://www.courier.com/blog/tips-and-tricks-to-setup-your-apple-m1-for-development/) for the Terminal app before installing and starting MagnetiCalc. -*Note:* Might be unstable. - ### Option A: Automatic install via pip This will install or upgrade MagnetiCalc (and its dependencies) to the user site-packages directory and start it from there. -#### Linux & macOS +#### Linux & macOS (Intel) ```shell python3 -m pip install magneticalc --upgrade python3 -m magneticalc @@ -146,6 +144,13 @@ python -m pip install --upgrade magneticalc python -m magneticalc ``` +#### macOS with Apple Silicon (M1) +*Note:* On Apple Silicon, JIT must be disabled due to incomplete support, resulting in slow calculations. +```shell +python3 -m pip install magneticalc --upgrade +export NUMBA_DISABLE_JIT=1 && python3 -m magneticalc +``` + #### Juptyer Notebook & Jupyter Lab From within a [Jupyter](https://jupyter.org/) Notebook, MagnetiCalc can be installed (upgraded) and run like this: @@ -229,14 +234,24 @@ provides basic functions for importing/exporting data programmatically: The data is wrapped in a [`MagnetiCalc_Data`](magneticalc/MagnetiCalc_Data.py) object which provides convenience functions for accessing, transforming and reshaping the data: + * `.get_wire_list()` returns a list of all 3D points of the wire. + * `.get_wire()` returns the raveled wire points as three arrays. + * `.get_current()` returns the wire current. * `.get_dimension()` returns the sampling volume dimension as a 3-tuple. - * `.get_axes(reduce=True)` returns the axis ticks of the sampling volume. * `.get_axes_list()` returns a list of all 3D points of the sampling volume. + * `.get_axes()` returns the raveled sampling volume coordinates as three arrays. + * `.get_axes(reduce=True)` returns the axis ticks of the sampling volume. * `.get_a_field_list()` returns a list of all 3D vectors of the - A-Field. + A-field. + * `.get_a_field()` returns the raveled + A-field + coordinates as three arrays. * `.get_a_field(as_3d=True)` returns a 3D field for each component of the - A-Field, + A-field, indexed over the reduced axes. + + Analogously, use the `.get_b_field_list()` and `.get_b_field()` functions + to get the B-field. License ------- @@ -295,11 +310,8 @@ ToDo * Fix unnecessary shading of VisPy markers. **Code Quality** -* Add debug output where it is missing. -* Add type hints where they are missing. * Add unit tests. * Use the [`@property` decorator](https://stackoverflow.com/a/36943813/2035671) for accessing data where applicable. -* Merge sparse `*_Types.py` modules with higher-level classes if possible. **Design** * Replace plain `QMessageBox` dialogs with nice-looking custom dialogs where possible. diff --git a/docs/Screenshot.png b/docs/Screenshot.png deleted file mode 100644 index 68521d9..0000000 Binary files a/docs/Screenshot.png and /dev/null differ diff --git a/docs/Video-Thumb.png b/docs/Video-Thumb.png deleted file mode 100644 index 6c05590..0000000 Binary files a/docs/Video-Thumb.png and /dev/null differ diff --git a/docs/classIndex.html b/docs/classIndex.html index a2b89f0..5cd5120 100644 --- a/docs/classIndex.html +++ b/docs/classIndex.html @@ -27,7 +27,7 @@

Class Hierarchy

+
  • collections.abc.MutableMapping
  • magneticalc.API.API - API class.
  • magneticalc.Assert_Dialog.Assert_Dialog - Assert_Dialog class.
  • magneticalc.Backend_CUDA.Backend_CUDA - Implements the Biot-Savart law for calculating the magnetic flux density (B-field) and vector potential (A-field). Backend: JIT + CUDA.
  • magneticalc.Backend_JIT.Backend_JIT - Implements the Biot-Savart law for calculating the magnetic flux density (B-field) and vector potential (A-field). Backend: JIT.
  • magneticalc.Config.Config - Config class.
  • magneticalc.Config_Group.Config_Collection - Config_Collection class.
  • magneticalc.Constants.Constants - Constants class.
  • magneticalc.Constraint.Constraint - Constraint class.
  • magneticalc.Debug.Debug - Debug class.
  • magneticalc.Field.Field - Field class.
  • magneticalc.Menu.Menu - Menu class.
  • magneticalc.Metric.Metric - Provides different metrics, used for mapping some field vector properties to some color and alpha range.
  • magneticalc.Metric_Presets.Metric_Presets - Metric_Presets class.
  • magneticalc.Model.Model - Model class.
  • magneticalc.ModelAccess.ModelAccess - Model access class.
  • magneticalc.Parameters.Parameters - Parameters class.
  • magneticalc.Perspective_Presets.Perspective_Presets - Perspective_Presets class.
  • magneticalc.QLayouted.QLayouted - QLayouted class.
  • magneticalc.QSaveAction.QSaveAction - QSaveAction class.
  • magneticalc.SamplingVolume.SamplingVolume - Sampling volume class.
  • magneticalc.Statusbar.Statusbar - Statusbar class.
  • magneticalc.Theme.Theme - Theme class.
  • magneticalc.Version.Version - Version class.
  • magneticalc.Wire.Wire - Wire class.
  • magneticalc.Wire_Presets.Wire_Presets - Wire_Presets class.
  • object
  • PyQt5.QtCore.QThread
  • PyQt5.QtWidgets.QDialog
  • PyQt5.QtWidgets.QFrame
  • PyQt5.QtWidgets.QGroupBox
  • PyQt5.QtWidgets.QHBoxLayout
  • PyQt5.QtWidgets.QLabel
  • PyQt5.QtWidgets.QMainWindow
  • PyQt5.QtWidgets.QMessageBox
  • PyQt5.QtWidgets.QScrollArea
  • PyQt5.QtWidgets.QSlider
  • PyQt5.QtWidgets.QSpinBox
  • PyQt5.QtWidgets.QTableWidget
  • PyQt5.QtWidgets.QTextBrowser
  • vispy.scene.SceneCanvas
  • diff --git a/docs/index.html b/docs/index.html index c664db3..08c4482 100644 --- a/docs/index.html +++ b/docs/index.html @@ -52,7 +52,7 @@

    This documentation was automatically generated by pydoctor - at 2022-01-02 09:06:24. + at 2022-01-03 23:22:21.

    diff --git a/docs/magneticalc.API.API.html b/docs/magneticalc.API.API.html index f31ae63..02730bf 100644 --- a/docs/magneticalc.API.API.html +++ b/docs/magneticalc.API.API.html @@ -205,7 +205,7 @@

    magneticalc.API.API class documentation
    - API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-02 09:06:24. + API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-03 23:22:21.
    diff --git a/docs/magneticalc.API.html b/docs/magneticalc.API.html index 6d42c32..8be3d33 100644 --- a/docs/magneticalc.API.html +++ b/docs/magneticalc.API.html @@ -66,7 +66,7 @@

    magneticalc.API module documentation
    - API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-02 09:06:24. + API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-03 23:22:21.
    diff --git a/docs/magneticalc.About_Dialog.About_Dialog.html b/docs/magneticalc.About_Dialog.About_Dialog.html index 6520c10..b85c62c 100644 --- a/docs/magneticalc.About_Dialog.About_Dialog.html +++ b/docs/magneticalc.About_Dialog.About_Dialog.html @@ -99,12 +99,7 @@

    magneticalc.About_Dialog.About_Dialog( - - - Instance Variable - layout - Undocumented - + Method install_layout @@ -129,6 +124,11 @@

    magneticalc.About_Dialog.About_Dialog(addButtons Adds buttons. + + + Instance Variable + _layout + Undocumented @@ -193,7 +193,7 @@

    magneticalc.About_Dialog.About_Dialog(API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-02 09:06:24. + API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-03 23:22:21. diff --git a/docs/magneticalc.About_Dialog.html b/docs/magneticalc.About_Dialog.html index c0703c0..045d7d4 100644 --- a/docs/magneticalc.About_Dialog.html +++ b/docs/magneticalc.About_Dialog.html @@ -66,7 +66,7 @@

    magneticalc.About_Dialog module documenta
    - API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-02 09:06:24. + API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-03 23:22:21.
    diff --git a/docs/magneticalc.Assert_Dialog.Assert_Dialog.html b/docs/magneticalc.Assert_Dialog.Assert_Dialog.html index 7869bc5..292c0ab 100644 --- a/docs/magneticalc.Assert_Dialog.Assert_Dialog.html +++ b/docs/magneticalc.Assert_Dialog.Assert_Dialog.html @@ -53,20 +53,10 @@

    magneticalc.Assert_Dialog.Assert_Dialog cl Method __init__ Shows a user dialog if an assertion failed. Intended for beta-testing. This allows the user to either quit or resume (possibly resulting in unstable behaviour). Furthermore, it provides a link for filing an issue on GitHub (partially pre-filled). - + Instance Variable - assertion - Undocumented - - - Instance Variable - message - Undocumented - - - Instance Variable - dialog + _dialog Undocumented @@ -96,48 +86,16 @@

    magneticalc.Assert_Dialog.Assert_Dialog cl

    Shows a user dialog if an assertion failed. Intended for beta-testing. This allows the user to either quit or resume (possibly resulting in unstable behaviour). Furthermore, it provides a link for filing an issue on GitHub (partially pre-filled).

    ParametersassertionBoolean
    messageError message
    -
    - - - - - - - -
    - assertion = - -
    -
    - -
    Undocumented
    -
    -
    - - - - - - - -
    - message = - -
    -
    - -
    Undocumented
    -
    -
    +
    - + - +
    - dialog = + _dialog =
    @@ -148,7 +106,7 @@

    magneticalc.Assert_Dialog.Assert_Dialog cl

    - API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-02 09:06:24. + API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-03 23:22:21.
    diff --git a/docs/magneticalc.Assert_Dialog.html b/docs/magneticalc.Assert_Dialog.html index 4edd6ea..9c716a9 100644 --- a/docs/magneticalc.Assert_Dialog.html +++ b/docs/magneticalc.Assert_Dialog.html @@ -66,7 +66,7 @@

    magneticalc.Assert_Dialog module document
    - API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-02 09:06:24. + API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-03 23:22:21.
    diff --git a/docs/magneticalc.Backend_CUDA.Backend_CUDA.html b/docs/magneticalc.Backend_CUDA.Backend_CUDA.html index 0b82eff..553c022 100644 --- a/docs/magneticalc.Backend_CUDA.Backend_CUDA.html +++ b/docs/magneticalc.Backend_CUDA.Backend_CUDA.html @@ -53,11 +53,6 @@

    magneticalc.Backend_CUDA.Backend_CUDA clas Method __init__ Initializes the class attributes. - - - Instance Variable - field_type - Undocumented Static Method @@ -75,6 +70,11 @@

    magneticalc.Backend_CUDA.Backend_CUDA clas Calculates the field at every point of the sampling volume. + Instance Variable + _field_type + Undocumented + + Instance Variable _distance_limit Undocumented @@ -136,16 +136,16 @@

    magneticalc.Backend_CUDA.Backend_CUDA clas

    Initializes the class attributes.

    Parametersfield_typeField type
    distance_limitDistance limit (mitigating divisions by zero)
    length_scaleLength scale (m)
    dcWire current (A)
    current_elementsOrdered list of current elements (pairs: [element center, element direction])
    sampling_volume_pointsOrdered list of sampling volume points
    sampling_volume_permeabilitiesOrdered list of sampling volume's relative permeabilities µ_r
    progress_callbackProgress callback
    -
    +
    - + - +
    - field_type = + _field_type =
    @@ -325,7 +325,7 @@

    magneticalc.Backend_CUDA.Backend_CUDA clas

    - API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-02 09:06:24. + API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-03 23:22:21.
    diff --git a/docs/magneticalc.Backend_CUDA.html b/docs/magneticalc.Backend_CUDA.html index 6d280dc..a133716 100644 --- a/docs/magneticalc.Backend_CUDA.html +++ b/docs/magneticalc.Backend_CUDA.html @@ -66,7 +66,7 @@

    magneticalc.Backend_CUDA module documenta
    - API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-02 09:06:24. + API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-03 23:22:21.
    diff --git a/docs/magneticalc.Backend_JIT.Backend_JIT.html b/docs/magneticalc.Backend_JIT.Backend_JIT.html index 56a4bc7..432e43e 100644 --- a/docs/magneticalc.Backend_JIT.Backend_JIT.html +++ b/docs/magneticalc.Backend_JIT.Backend_JIT.html @@ -53,11 +53,6 @@

    magneticalc.Backend_JIT.Backend_JIT class Method __init__ Initializes the class attributes. - - - Instance Variable - field_type - Undocumented Static Method @@ -70,6 +65,11 @@

    magneticalc.Backend_JIT.Backend_JIT class Calculates the field at every point of the sampling volume. + Instance Variable + _field_type + Undocumented + + Instance Variable _distance_limit Undocumented @@ -131,16 +131,16 @@

    magneticalc.Backend_JIT.Backend_JIT class

    Initializes the class attributes.

    Parametersfield_typeField type
    distance_limitDistance limit (mitigating divisions by zero)
    length_scaleLength scale (m)
    dcWire current (A)
    current_elementsOrdered list of current elements (pairs: [element center, element direction])
    sampling_volume_pointsOrdered list of sampling volume points
    sampling_volume_permeabilitiesOrdered list of sampling volume's relative permeabilities µ_r
    progress_callbackProgress callback
    -
    +
    - + - +
    - field_type = + _field_type =
    @@ -268,7 +268,7 @@

    magneticalc.Backend_JIT.Backend_JIT class
    - @staticmethod
    @jit(nopython=True, parallel=True)
    + @staticmethod
    @ConditionalDecorator(get_jit_enabled(), jit, nopython=True, parallel=True)
    def worker(field_type, distance_limit, length_scale, current_elements, sampling_volume_point): @@ -301,7 +301,7 @@

    magneticalc.Backend_JIT.Backend_JIT class

    - API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-02 09:06:24. + API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-03 23:22:21.

    diff --git a/docs/magneticalc.Backend_JIT.html b/docs/magneticalc.Backend_JIT.html index 345ef51..235770b 100644 --- a/docs/magneticalc.Backend_JIT.html +++ b/docs/magneticalc.Backend_JIT.html @@ -66,7 +66,7 @@

    magneticalc.Backend_JIT module documentat

    - API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-02 09:06:24. + API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-03 23:22:21.
    diff --git a/docs/magneticalc.Backend_Types.html b/docs/magneticalc.Backend_Types.html index 90c6998..763a16d 100644 --- a/docs/magneticalc.Backend_Types.html +++ b/docs/magneticalc.Backend_Types.html @@ -103,7 +103,7 @@

    magneticalc.Backend_Types module document
    - API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-02 09:06:24. + API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-03 23:22:21.
    diff --git a/docs/magneticalc.CalculationThread.CalculationThread.html b/docs/magneticalc.CalculationThread.CalculationThread.html index 1ae4382..748383f 100644 --- a/docs/magneticalc.CalculationThread.CalculationThread.html +++ b/docs/magneticalc.CalculationThread.CalculationThread.html @@ -48,37 +48,7 @@

    magneticalc.CalculationThread.CalculationThread( - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + @@ -128,6 +98,36 @@

    magneticalc.CalculationThread.CalculationThread(Method

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Class Variableprogress_updateUndocumented
    Class Variablewire_validUndocumented
    Class Variablesampling_volume_validUndocumented
    Class Variablefield_validUndocumented
    Class Variablemetric_validUndocumented
    Class Variableparameters_validUndocumented
    Method __init__on_parameters_valid Gets called when the parameters were successfully calculated.
    Class Variable_progress_updateUndocumented
    Class Variable_wire_validUndocumented
    Class Variable_sampling_volume_validUndocumented
    Class Variable_field_validUndocumented
    Class Variable_metric_validUndocumented
    Class Variable_parameters_validUndocumented
    @@ -137,96 +137,96 @@

    magneticalc.CalculationThread.CalculationThread( -
    +
    - + - +
    - progress_update = + _progress_update =
    Undocumented
    -
    +
    - + - +
    - wire_valid = + _wire_valid =
    Undocumented
    -
    +
    - + - +
    - sampling_volume_valid = + _sampling_volume_valid =
    Undocumented
    -
    +
    - + - +
    - field_valid = + _field_valid =
    Undocumented
    -
    +
    - + - +
    - metric_valid = + _metric_valid =
    Undocumented
    -
    +
    - + - +
    - parameters_valid = + _parameters_valid =
    @@ -421,7 +421,7 @@

    magneticalc.CalculationThread.CalculationThread(
    - API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-02 09:06:24. + API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-03 23:22:21.

    diff --git a/docs/magneticalc.CalculationThread.html b/docs/magneticalc.CalculationThread.html index 1f18c8e..9e552f4 100644 --- a/docs/magneticalc.CalculationThread.html +++ b/docs/magneticalc.CalculationThread.html @@ -66,7 +66,7 @@

    magneticalc.CalculationThread module docu

    - API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-02 09:06:24. + API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-03 23:22:21.
    diff --git a/docs/magneticalc.CheckForUpdates_Dialog.CheckForUpdates_Dialog.html b/docs/magneticalc.CheckForUpdates_Dialog.CheckForUpdates_Dialog.html index df25368..d962a66 100644 --- a/docs/magneticalc.CheckForUpdates_Dialog.CheckForUpdates_Dialog.html +++ b/docs/magneticalc.CheckForUpdates_Dialog.CheckForUpdates_Dialog.html @@ -89,12 +89,7 @@

    magneticalc.CheckForUpdates_Dialog.CheckForUpdates_Dialo

    - - - - - - + @@ -119,6 +114,11 @@

    magneticalc.CheckForUpdates_Dialog.CheckForUpdates_Dialo

    + + + + +
    Instance VariablelayoutUndocumented
    Method install_layoutMethod addButtons Adds buttons.
    Instance Variable_layoutUndocumented
    @@ -151,7 +151,7 @@

    magneticalc.CheckForUpdates_Dialog.CheckForUpdates_Dialo
    - API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-02 09:06:24. + API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-03 23:22:21.
    diff --git a/docs/magneticalc.CheckForUpdates_Dialog.html b/docs/magneticalc.CheckForUpdates_Dialog.html index 2bc9745..593f4a3 100644 --- a/docs/magneticalc.CheckForUpdates_Dialog.html +++ b/docs/magneticalc.CheckForUpdates_Dialog.html @@ -66,7 +66,7 @@

    magneticalc.CheckForUpdates_Dialog module
    - API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-02 09:06:24. + API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-03 23:22:21.
    diff --git a/docs/magneticalc.Comparison_Types.html b/docs/magneticalc.Comparison_Types.html new file mode 100644 index 0000000..af05c94 --- /dev/null +++ b/docs/magneticalc.Comparison_Types.html @@ -0,0 +1,162 @@ + + + + + magneticalc.Comparison_Types : API documentation + + + + + + + + + +
    + +
    + +
    + + + +
    + +
    + +
    +

    Comparison_Types module.

    +
    + +
    + + + + + + + + + + + + + + + + + + + + + + + +
    VariableCOMPARISON_TYPE_IN_RANGEUndocumented
    VariableComparison_Types_Str_MapUndocumented
    Functioncomparison_type_to_strConverts a comparison type to a comparison string.
    Functioncomparison_type_from_strConverts a comparison string to a comparison type.
    + + + +
    + +
    + +
    + + + + + + + +
    + COMPARISON_TYPE_IN_RANGE = + +
    +
    + +
    Undocumented
    (type: int) +
    +
    + + + + + + + +
    + Comparison_Types_Str_Map = + +
    +
    + +
    Undocumented
    +
    +
    + + + + + + + +
    + + def + comparison_type_to_str(comparison_type): + +
    +
    + + +

    Converts a comparison type to a comparison string.

    Parameterscomparison_typeComparison type
    ReturnsComparison string, or None if comparison type is invalid
    +
    +
    + + + + + + + +
    + + def + comparison_type_from_str(comparison_str): + +
    +
    + + +

    Converts a comparison string to a comparison type.

    Parameterscomparison_strComparison string @return Comparison type, or None if comparison string is invalid
    +
    +
    + +
    +
    + API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-03 23:22:21. +
    + +
    + + + + + \ No newline at end of file diff --git a/docs/magneticalc.ConditionalDecorator.ConditionalDecorator.html b/docs/magneticalc.ConditionalDecorator.ConditionalDecorator.html new file mode 100644 index 0000000..fe1426c --- /dev/null +++ b/docs/magneticalc.ConditionalDecorator.ConditionalDecorator.html @@ -0,0 +1,183 @@ + + + + + magneticalc.ConditionalDecorator.ConditionalDecorator : API documentation + + + + + + + + + +
    + +
    + +
    + + + +
    + +
    + +
    +

    ConditionalDecorator class.

    +
    + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Method__init__Initializes a conditional decorator.
    Instance VariableconditionUndocumented
    Instance Variabledecorating_funcUndocumented
    Instance Variabledecorating_argsUndocumented
    Method__call__Gets called when a function is to be decorated.
    + + + +
    + +
    + +
    + + + + + + + +
    + + def + __init__(self, condition, decorating_func, **decorating_args): + +
    +
    + + +

    Initializes a conditional decorator.

    ParametersconditionCondition
    decorating_funcDecorating function
    decorating_argsArguments to decorating function
    +
    +
    + + + + + + + +
    + condition = + +
    +
    + +
    Undocumented
    +
    +
    + + + + + + + +
    + decorating_func = + +
    +
    + +
    Undocumented
    +
    +
    + + + + + + + +
    + decorating_args = + +
    +
    + +
    Undocumented
    +
    +
    + + + + + + + +
    + + def + __call__(self, func): + +
    +
    + + +

    Gets called when a function is to be decorated.

    ParametersfuncFunction to be decorated
    ReturnsDecorated function
    +
    +
    + +
    +
    + API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-03 23:22:21. +
    + +
    + + + + + \ No newline at end of file diff --git a/docs/magneticalc.ConditionalDecorator.html b/docs/magneticalc.ConditionalDecorator.html new file mode 100644 index 0000000..8f8459a --- /dev/null +++ b/docs/magneticalc.ConditionalDecorator.html @@ -0,0 +1,77 @@ + + + + + magneticalc.ConditionalDecorator : API documentation + + + + + + + + + +
    + +
    + +
    + + + +
    + +
    + +
    +

    ConditionalDecorator module.

    +
    + +
    + + + + + + + + +
    ClassConditionalDecoratorConditionalDecorator class.
    + + + +
    + +
    + + + +
    +
    + API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-03 23:22:21. +
    + +
    + + + + + \ No newline at end of file diff --git a/docs/magneticalc.Config.Config.html b/docs/magneticalc.Config.Config.html index dbfe7b5..089a4af 100644 --- a/docs/magneticalc.Config.Config.html +++ b/docs/magneticalc.Config.Config.html @@ -46,7 +46,7 @@

    magneticalc.Config.Config class documentat
    - +
    @@ -60,11 +60,6 @@

    magneticalc.Config.Config class documentat

    - - - - - @@ -316,22 +311,6 @@

    magneticalc.Config.Config class documentat
    - - - - - - -
    - DebugGetters = - -
    -
    - -
    Undocumented
    (type: bool) -
    -
    - @@ -1105,13 +1084,13 @@

    magneticalc.Config.Config class documentat
    -

    If "values" is None, reads and returns all key-values in "types". Note: The actual keys saved in the configuration file are prefixed with "prefix", and suffixed with "suffix".

    If "values" is not None, writes and returns all key-values in "types". Note: In this case, "values" must have the same keys as "types.

    Undocumented
    Class VariableDebugGettersUndocumented
    Class Variable DefaultWirePreset Undocumented
    ParametersprefixPrefix
    suffixSuffix
    typesKey:Type (Dictionary)
    valuesKey:Value (Dictionary) or None
    +

    If "values" is None, reads and returns all key-values in "types". Note: The actual keys saved in the configuration file are prefixed with "prefix", and suffixed with "suffix".

    If "values" is not None, writes and returns all key-values in "types". Note: In this case, "values" must have the same keys as "types".

    ParametersprefixPrefix
    suffixSuffix
    typesKey:Type (Dictionary)
    valuesKey:Value (Dictionary) or None
    - API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-02 09:06:24. + API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-03 23:22:21.
    diff --git a/docs/magneticalc.Config.html b/docs/magneticalc.Config.html index f2e7380..baeab4e 100644 --- a/docs/magneticalc.Config.html +++ b/docs/magneticalc.Config.html @@ -46,9 +46,14 @@

    magneticalc.Config module documentation
    - +
    - + + + + + + @@ -62,11 +67,30 @@

    magneticalc.Config module documentation - +
    + + + + + + + +
    + + def + get_jit_enabled(): + +
    +
    + + +

    Checks if JIT is enabled (or at least not explicitly disabled).

    Functionget_jit_enabledChecks if JIT is enabled (or at least not explicitly disabled).
    Class Config
    ReturnsBoolean
    + +
    - API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-02 09:06:24. + API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-03 23:22:21.
    diff --git a/docs/magneticalc.Config_Group.Config_Collection.html b/docs/magneticalc.Config_Group.Config_Collection.html new file mode 100644 index 0000000..841b361 --- /dev/null +++ b/docs/magneticalc.Config_Group.Config_Collection.html @@ -0,0 +1,348 @@ + + + + + magneticalc.Config_Group.Config_Collection : API documentation + + + + + + + + + +
    + +
    + +
    + + + +
    + +
    + +
    +

    Config_Collection class.

    +
    + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Method__init__Initializes a config collection: A list of groups (dictionaries).
    Instance VariableguiUndocumented
    Instance VariableprefixUndocumented
    Instance VariabletypesUndocumented
    Instance Variablefirst_without_suffixUndocumented
    Methodget_countGets the number of groups in the collection.
    Methodget_groupGets a group from the collection.
    Methodget_all_groupsGets every group in the collection.
    Methodadd_groupAppends a group to the collection.
    Methoddel_groupDeletes a group from the collection.
    MethodsetSets a value for some key in a group of the collection.
    Method_get_suffixGets the suffix for a given group index.
    + + + +
    + +
    + +
    + + + + + + + +
    + + def + __init__(self, gui, prefix, types, first_without_suffix): + +
    +
    + + +
    +
    +
    + + + + + + + +
    + gui = + +
    +
    + +
    Undocumented
    +
    +
    + + + + + + + +
    + prefix = + +
    +
    + +
    Undocumented
    +
    +
    + + + + + + + +
    + types = + +
    +
    + +
    Undocumented
    +
    +
    + + + + + + + +
    + first_without_suffix = + +
    +
    + +
    Undocumented
    +
    +
    + + + + + + + +
    + + def + _get_suffix(self, group_index): + +
    +
    + + +

    Gets the suffix for a given group index.

    Parametersgroup_indexGroup index
    ReturnsString
    +
    +
    + + + + + + + +
    + + def + get_count(self): + +
    +
    + + +

    Gets the number of groups in the collection.

    ReturnsNumber of groups in the collection
    +
    +
    + + + + + + + +
    + + def + get_group(self, group_index): + +
    +
    + + +

    Gets a group from the collection.

    Parametersgroup_indexGroup index
    ReturnsGroup (dictionary)
    +
    +
    + + + + + + + +
    + + def + get_all_groups(self): + +
    +
    + + +

    Gets every group in the collection.

    ReturnsList of groups (dictionaries)
    +
    +
    + + + + + + + +
    + + def + add_group(self, values): + +
    +
    + + +

    Appends a group to the collection.

    ParametersvaluesKey:Value (Dictionary)
    +
    +
    + + + + + + + +
    + + def + del_group(self, group_index): + +
    +
    + + +

    Deletes a group from the collection.

    Parametersgroup_indexGroup index
    +
    +
    + + + + + + + +
    + + def + set(self, group_index, key, value): + +
    +
    + + +

    Sets a value for some key in a group of the collection.

    Parametersgroup_indexGroup index
    keyKey
    valueValue
    +
    +
    + +
    +
    + API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-03 23:22:21. +
    + +
    + + + + + \ No newline at end of file diff --git a/docs/magneticalc.Config_Group.html b/docs/magneticalc.Config_Group.html new file mode 100644 index 0000000..f4c3a24 --- /dev/null +++ b/docs/magneticalc.Config_Group.html @@ -0,0 +1,77 @@ + + + + + magneticalc.Config_Group : API documentation + + + + + + + + + +
    + +
    + +
    + + + +
    + +
    + +
    +

    Config_Collection module.

    +
    + +
    + + + + + + + + +
    ClassConfig_CollectionConfig_Collection class.
    + + + +
    + +
    + + + +
    +
    + API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-03 23:22:21. +
    + +
    + + + + + \ No newline at end of file diff --git a/docs/magneticalc.Constants.Constants.html b/docs/magneticalc.Constants.Constants.html index 4201658..b903871 100644 --- a/docs/magneticalc.Constants.Constants.html +++ b/docs/magneticalc.Constants.Constants.html @@ -46,7 +46,7 @@

    magneticalc.Constants.Constants class docu
    - +
    @@ -82,7 +82,7 @@

    magneticalc.Constants.Constants class docu
    - API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-02 09:06:24. + API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-03 23:22:21.
    diff --git a/docs/magneticalc.Constants.html b/docs/magneticalc.Constants.html index 24730e9..d5b4680 100644 --- a/docs/magneticalc.Constants.html +++ b/docs/magneticalc.Constants.html @@ -46,7 +46,7 @@

    magneticalc.Constants module documentatio
    -

    +
    @@ -66,7 +66,7 @@

    magneticalc.Constants module documentatio
    - API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-02 09:06:24. + API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-03 23:22:21.
    diff --git a/docs/magneticalc.Constraint.Constraint.html b/docs/magneticalc.Constraint.Constraint.html index fec75b1..6a7e404 100644 --- a/docs/magneticalc.Constraint.Constraint.html +++ b/docs/magneticalc.Constraint.Constraint.html @@ -46,22 +46,32 @@

    magneticalc.Constraint.Constraint class do
    -

    +
    - + - + - + + + + + + + + + + + @@ -86,12 +96,12 @@

    magneticalc.Constraint.Constraint class do

    - + - + @@ -114,51 +124,83 @@

    magneticalc.Constraint.Constraint class do
    - + - +
    - Norm_ID_List = + Norm_Types_List =
    -
    Undocumented
    (type: List[str]) +
    Undocumented
    - + - +
    - Comparison_ID_List = + Norm_Types_List_Str =
    -
    Undocumented
    (type: List[str]) +
    Undocumented
    - + - +
    - Norm_ID_List_Degrees = + Norm_Types_Degrees_List =
    -
    Undocumented
    (type: List[str]) +
    Undocumented
    +
    +
    + + + + + + + +
    + Comparison_Types_List = + +
    +
    + +
    Undocumented
    +
    +
    + + + + + + + +
    + Comparison_Types_List_Str = + +
    +
    + +
    Undocumented
    @@ -171,13 +213,13 @@

    magneticalc.Constraint.Constraint class do
    def - __init__(self, norm_id, comparison_id, _min, _max, permeability): + __init__(self, norm_type, comparison_type, _min, _max, permeability):
    -

    Initializes the constraint.

    Class VariableNorm_ID_ListNorm_Types_List Undocumented
    Class VariableComparison_ID_ListNorm_Types_List_Str Undocumented
    Class VariableNorm_ID_List_DegreesNorm_Types_Degrees_ListUndocumented
    Class VariableComparison_Types_ListUndocumented
    Class VariableComparison_Types_List_Str Undocumented
    Instance Variable_norm_id_norm_type Undocumented
    Instance Variable_comparison_id_comparison_type Undocumented
    Parametersnorm_idNorm ID
    comparison_idComparison ID
    _minMinimum value
    _maxMaximum value
    permeabilityRelative permeability µ_r
    +

    Initializes the constraint.

    Parametersnorm_typeNorm type
    comparison_typeComparison type
    _minMinimum value
    _maxMaximum value
    permeabilityRelative permeability µ_r
    @@ -197,14 +239,14 @@

    magneticalc.Constraint.Constraint class do

    - + - +
    - _norm_id = + _norm_type =
    @@ -213,14 +255,14 @@

    magneticalc.Constraint.Constraint class do

    - + - +
    - _comparison_id = + _comparison_type =
    @@ -298,7 +340,7 @@

    magneticalc.Constraint.Constraint class do

    - API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-02 09:06:24. + API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-03 23:22:21.
    diff --git a/docs/magneticalc.Constraint.html b/docs/magneticalc.Constraint.html index 8747a96..3895f3d 100644 --- a/docs/magneticalc.Constraint.html +++ b/docs/magneticalc.Constraint.html @@ -46,7 +46,7 @@

    magneticalc.Constraint module documentati
    - +
    @@ -66,7 +66,7 @@

    magneticalc.Constraint module documentati
    - API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-02 09:06:24. + API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-03 23:22:21.
    diff --git a/docs/magneticalc.Constraint_Editor.Constraint_Editor.html b/docs/magneticalc.Constraint_Editor.Constraint_Editor.html index 93d4c00..45b4610 100644 --- a/docs/magneticalc.Constraint_Editor.Constraint_Editor.html +++ b/docs/magneticalc.Constraint_Editor.Constraint_Editor.html @@ -46,7 +46,7 @@

    magneticalc.Constraint_Editor.Constraint_Editor(
    -

    +
    @@ -80,11 +80,6 @@

    magneticalc.Constraint_Editor.Constraint_Editor(Re-initializes the constraint editor.

    - - - - - @@ -101,13 +96,13 @@

    magneticalc.Constraint_Editor.Constraint_Editor(

    - - + + - + @@ -131,7 +126,7 @@

    magneticalc.Constraint_Editor.Constraint_Editor(

    - + @@ -144,7 +139,7 @@

    magneticalc.Constraint_Editor.Constraint_Editor( Inherited from QDialog2:

    -

    MethodshowShows this dialog.
    Method get_changed Returns the "changed" state of the current session.
    Methodreload_constraintsRe-loads the list of constraints.get_countGets the number of constraints.
    Method get_constraintsReturns the list of constraints.Gets the list of constraints.
    Method
    Instance Variable_constraints_constraint_collection Undocumented
    +
    @@ -158,6 +153,11 @@

    magneticalc.Constraint_Editor.Constraint_Editor(Undocumented

    + + + + + @@ -167,14 +167,9 @@

    magneticalc.Constraint_Editor.Constraint_Editor( Inherited from QLayouted (via QDialog2):

    -

    MethodshowShows this dialog.
    Method showEvent Overrides the showEvent method.
    +
    - - - - - - + @@ -199,6 +194,11 @@

    magneticalc.Constraint_Editor.Constraint_Editor(Method

    + + + + +
    Instance VariablelayoutUndocumented
    Method install_layoutaddButtons Adds buttons.
    Instance Variable_layoutUndocumented
    @@ -277,19 +277,19 @@

    magneticalc.Constraint_Editor.Constraint_Editor(

    - + - +
    - _constraints = + _constraint_collection =
    -
    Undocumented
    (type: List) +
    Undocumented
    @@ -344,25 +344,6 @@

    magneticalc.Constraint_Editor.Constraint_Editor(

    - - - - - - -
    - - def - show(self): - -
    -
    - - -

    Shows this dialog.

    -
    -
    - @@ -420,22 +401,22 @@

    magneticalc.Constraint_Editor.Constraint_Editor(

    - + - +
    def - reload_constraints(self): + get_count(self):
    -

    Re-loads the list of constraints.

    +

    Gets the number of constraints.

    ReturnsNumber of constraints
    -

    Gets called after a row has been deleted from the table.

    ParametersindexRow index
    +

    Gets called after a row has been deleted from the table.

    ParametersrowRow index
    - API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-02 09:06:24. + API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-03 23:22:21.
    diff --git a/docs/magneticalc.Constraint_Editor.html b/docs/magneticalc.Constraint_Editor.html index ed5de8f..99b3008 100644 --- a/docs/magneticalc.Constraint_Editor.html +++ b/docs/magneticalc.Constraint_Editor.html @@ -46,7 +46,7 @@

    magneticalc.Constraint_Editor module docu
    - +
    @@ -66,7 +66,7 @@

    magneticalc.Constraint_Editor module docu
    - API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-02 09:06:24. + API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-03 23:22:21.
    diff --git a/docs/magneticalc.Debug.Debug.html b/docs/magneticalc.Debug.Debug.html index f7047df..8547e35 100644 --- a/docs/magneticalc.Debug.Debug.html +++ b/docs/magneticalc.Debug.Debug.html @@ -46,12 +46,12 @@

    magneticalc.Debug.Debug class documentatio
    -

    +
    - + @@ -69,19 +69,19 @@

    magneticalc.Debug.Debug class documentatio
    - + - +
    - Whitelist = + Blacklist =
    -
    Undocumented
    (type: List[str]) +
    Undocumented
    (type: List)
    @@ -94,19 +94,19 @@

    magneticalc.Debug.Debug class documentatio
    def - __init__(self, obj, text, color=None, force=(False)): + __init__(self, obj, text, color=None, force=(False), success=(False), warning=(False), error=(False)):
    -

    Displays a colorful debug message and the current call hierarchy.

    Class VariableWhitelistBlacklist Undocumented
    ParametersobjClass instance
    textDebug message
    colorColor (may be None)
    forceEnable to override whitelist
    +

    Displays a colorful debug message and the current call hierarchy.

    ParametersobjClass instance
    textDebug message
    colorColor (may be None)
    forceEnable to override whitelist
    successEnable to set color=SuccessColor
    warningEnable to set color=WarningColor and force=True
    errorEnable to set color=ErrorColor and force=True
    - API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-02 09:06:24. + API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-03 23:22:21.
    diff --git a/docs/magneticalc.Debug.html b/docs/magneticalc.Debug.html index 45a22fa..b339e16 100644 --- a/docs/magneticalc.Debug.html +++ b/docs/magneticalc.Debug.html @@ -46,7 +46,7 @@

    magneticalc.Debug module documentation
    - +
    @@ -66,7 +66,7 @@

    magneticalc.Debug module documentation
    - API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-02 09:06:24. + API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-03 23:22:21.
    diff --git a/docs/magneticalc.Display_Widget.Display_Widget.html b/docs/magneticalc.Display_Widget.Display_Widget.html index 170bc14..4db9b28 100644 --- a/docs/magneticalc.Display_Widget.Display_Widget.html +++ b/docs/magneticalc.Display_Widget.Display_Widget.html @@ -46,7 +46,7 @@

    magneticalc.Display_Widget.Display_Widget( -

    +
    @@ -234,14 +234,9 @@

    magneticalc.Display_Widget.Display_Widget( Inherited from QLayouted (via QGroupBox2):

    -

    +
    - - - - - - + @@ -266,6 +261,11 @@

    magneticalc.Display_Widget.Display_Widget(addButtons

    + + + + +
    Instance VariablelayoutUndocumented
    Method install_layoutAdds buttons.
    Instance Variable_layoutUndocumented
    @@ -897,7 +897,7 @@

    magneticalc.Display_Widget.Display_Widget(API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-02 09:06:24. + API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-03 23:22:21.

    diff --git a/docs/magneticalc.Display_Widget.html b/docs/magneticalc.Display_Widget.html index 8f8040e..5b83193 100644 --- a/docs/magneticalc.Display_Widget.html +++ b/docs/magneticalc.Display_Widget.html @@ -46,7 +46,7 @@

    magneticalc.Display_Widget module documen
    - +
    @@ -66,7 +66,7 @@

    magneticalc.Display_Widget module documen
    - API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-02 09:06:24. + API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-03 23:22:21.
    diff --git a/docs/magneticalc.ExportContainer_Dialog.ExportContainer_Dialog.html b/docs/magneticalc.ExportContainer_Dialog.ExportContainer_Dialog.html index 1322ff4..4e526fe 100644 --- a/docs/magneticalc.ExportContainer_Dialog.ExportContainer_Dialog.html +++ b/docs/magneticalc.ExportContainer_Dialog.ExportContainer_Dialog.html @@ -46,7 +46,7 @@

    magneticalc.ExportContainer_Dialog.ExportContainer_Dialo
    -

    +
    @@ -89,7 +89,7 @@

    magneticalc.ExportContainer_Dialog.ExportContainer_Dialo

    Inherited from QDialog2:

    -

    +
    @@ -117,14 +117,9 @@

    magneticalc.ExportContainer_Dialog.ExportContainer_Dialo

    Inherited from QLayouted (via QDialog2):

    -

    +
    - - - - - - + @@ -149,6 +144,11 @@

    magneticalc.ExportContainer_Dialog.ExportContainer_Dialo

    + + + + +
    Instance VariablelayoutUndocumented
    Method install_layoutMethod addButtons Adds buttons.
    Instance Variable_layoutUndocumented
    @@ -280,7 +280,7 @@

    magneticalc.ExportContainer_Dialog.ExportContainer_Dialo

    - API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-02 09:06:24. + API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-03 23:22:21.
    diff --git a/docs/magneticalc.ExportContainer_Dialog.html b/docs/magneticalc.ExportContainer_Dialog.html index be3b404..c9e9059 100644 --- a/docs/magneticalc.ExportContainer_Dialog.html +++ b/docs/magneticalc.ExportContainer_Dialog.html @@ -46,7 +46,7 @@

    magneticalc.ExportContainer_Dialog module
    - +
    @@ -66,7 +66,7 @@

    magneticalc.ExportContainer_Dialog module
    - API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-02 09:06:24. + API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-03 23:22:21.
    diff --git a/docs/magneticalc.Field.Field.html b/docs/magneticalc.Field.Field.html index 8cc9bee..0ea3f08 100644 --- a/docs/magneticalc.Field.Field.html +++ b/docs/magneticalc.Field.Field.html @@ -46,7 +46,7 @@

    magneticalc.Field.Field class documentatio
    -

    +
    @@ -132,7 +132,7 @@

    magneticalc.Field.Field class documentatio

    - +
    Instance Variable _vectorsdef print_array(array): return "np.array([" + ",".join([f"[{p[0]},{p[1]},{p[2]}]" for p in array]) + "])"Undocumented
    @@ -271,7 +271,7 @@

    magneticalc.Field.Field class documentatio

    -

    def print_array(array): return "np.array([" + ",".join([f"[{p[0]},{p[1]},{p[2]}]" for p in array]) + "])"

    element_centers = [element[0] for element in wire.get_elements()] element_directions = [element[1] for element in wire.get_elements()]

    import sys import numpy numpy.set_printoptions(threshold=sys.maxsize)

    print("Total calculations =", self.get_total_calculations()) print("Total skipped calculations =", self.get_total_skipped_calculations()) print("sampling_volume_points =", print_array(sampling_volume.get_points())) print("element_centers =", print_array(element_centers)) print("element_directions =", print_array(element_directions)) print("vectors =", print_array(self._vectors))

    +
    Undocumented
    @@ -341,13 +341,13 @@

    magneticalc.Field.Field class documentatio
    def - get_units(self): + get_units(self, show_gauss=(False)):
    -

    Gets field units.

    ReturnsField units
    +

    Gets field units.

    Parametersshow_gaussEnable to show Gauss instead of Tesla
    ReturnsField units, field factor

    @@ -434,7 +434,7 @@

    magneticalc.Field.Field class documentatio
    - @staticmethod
    @jit(nopython=True, parallel=True)
    + @staticmethod
    @ConditionalDecorator(get_jit_enabled(), jit, nopython=True, parallel=True)
    def get_arrows(sampling_volume_points, field_vectors, line_pairs, head_points, arrow_scale, magnitude_limit): @@ -442,13 +442,13 @@

    magneticalc.Field.Field class documentatio
    -

    Returns the field arrow parameters needed by VispyCanvas.

    Parameterssampling_volume_pointsSampling volume points
    field_vectorsField vectors
    line_pairsArrow line pairs (ordered list of arrow start/stop 3D points)
    head_pointsArrow head points (ordered list of arrow stop 3D points)
    arrow_scaleArrow scale
    magnitude_limitMagnitude limit (mitigating divisions by zero)
    +

    Returns the field arrow parameters needed by VispyCanvas.

    Parameterssampling_volume_pointsSampling volume points
    field_vectorsField vectors
    line_pairsArrow line pairs (ordered list of arrow start/stop 3D points)
    head_pointsArrow head points (ordered list of arrow stop 3D points)
    arrow_scaleArrow scale
    magnitude_limitMagnitude limit (mitigating divisions by zero)
    ReturnsLine pairs, head points

    - API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-02 09:06:24. + API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-03 23:22:21.
    diff --git a/docs/magneticalc.Field.html b/docs/magneticalc.Field.html index a167703..135c794 100644 --- a/docs/magneticalc.Field.html +++ b/docs/magneticalc.Field.html @@ -46,7 +46,7 @@

    magneticalc.Field module documentation
    - +
    @@ -66,7 +66,7 @@

    magneticalc.Field module documentation
    - API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-02 09:06:24. + API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-03 23:22:21.
    diff --git a/docs/magneticalc.Field_Types.html b/docs/magneticalc.Field_Types.html index 3e66b08..427299d 100644 --- a/docs/magneticalc.Field_Types.html +++ b/docs/magneticalc.Field_Types.html @@ -46,7 +46,7 @@

    magneticalc.Field_Types module documentat
    -

    +
    @@ -61,8 +61,13 @@

    magneticalc.Field_Types module documentat

    - + + + + + +
    VariableFIELD_TYPES_STRField_Types_Str_Map Undocumented
    Functionfield_type_to_strConverts a field type to a field string.
    @@ -106,25 +111,44 @@

    magneticalc.Field_Types module documentat

    - + - +
    - FIELD_TYPES_STR = + Field_Types_Str_Map =
    Undocumented
    +
    + + + + + + + +
    + + def + field_type_to_str(field_type): + +
    +
    + + +

    Converts a field type to a field string.

    Parametersfield_typeField type
    ReturnsField string, or None if field type is invalid
    +
    - API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-02 09:06:24. + API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-03 23:22:21.
    diff --git a/docs/magneticalc.Field_Widget.Field_Widget.html b/docs/magneticalc.Field_Widget.Field_Widget.html index 2766463..280f8ae 100644 --- a/docs/magneticalc.Field_Widget.Field_Widget.html +++ b/docs/magneticalc.Field_Widget.Field_Widget.html @@ -46,7 +46,7 @@

    magneticalc.Field_Widget.Field_Widget( - +
    @@ -144,14 +144,9 @@

    magneticalc.Field_Widget.Field_Widget( Inherited from QLayouted (via QGroupBox2):

    -

    +
    - - - - - - + @@ -176,6 +171,11 @@

    magneticalc.Field_Widget.Field_Widget(addButtons

    + + + + +
    Instance VariablelayoutUndocumented
    Method install_layoutAdds buttons.
    Instance Variable_layoutUndocumented
    @@ -498,7 +498,7 @@

    magneticalc.Field_Widget.Field_Widget(API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-02 09:06:24. + API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-03 23:22:21. diff --git a/docs/magneticalc.Field_Widget.html b/docs/magneticalc.Field_Widget.html index abe4763..c65fd0d 100644 --- a/docs/magneticalc.Field_Widget.html +++ b/docs/magneticalc.Field_Widget.html @@ -46,7 +46,7 @@

    magneticalc.Field_Widget module documenta
    - +
    @@ -66,7 +66,7 @@

    magneticalc.Field_Widget module documenta
    - API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-02 09:06:24. + API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-03 23:22:21.
    diff --git a/docs/magneticalc.GUI.GUI.html b/docs/magneticalc.GUI.GUI.html index 74c6800..a46a85f 100644 --- a/docs/magneticalc.GUI.GUI.html +++ b/docs/magneticalc.GUI.GUI.html @@ -46,10 +46,15 @@

    magneticalc.GUI.GUI( -

    +
    + + + + + @@ -148,10 +153,10 @@

    magneticalc.GUI.GUI(interrupt_calculation

    - + - - + + @@ -219,6 +224,22 @@

    magneticalc.GUI.GUI( + + + + + + +
    + MinimumWindowSize = + +
    +
    + +
    Undocumented
    (type: Tuple[int, ...]) +
    +
    + @@ -552,7 +573,7 @@

    magneticalc.GUI.GUI( +

    @@ -784,7 +805,7 @@

    magneticalc.GUI.GUI(API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-02 09:06:24. + API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-03 23:22:21.

    diff --git a/docs/magneticalc.GUI.html b/docs/magneticalc.GUI.html index 1c0940f..1a8930a 100644 --- a/docs/magneticalc.GUI.html +++ b/docs/magneticalc.GUI.html @@ -46,7 +46,7 @@

    magneticalc.GUI module documentation
    -

    Class VariableMinimumWindowSizeUndocumented
    Class Variable DefaultFilename UndocumentedKills any running calculation.
    Static Methodconfirm_saving_unsaved_workMethodconfirm_saving_unsaved_work Confirm saving unsaved work.
    +
    @@ -66,7 +66,7 @@

    magneticalc.GUI module documentation
    - API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-02 09:06:24. + API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-03 23:22:21.
    diff --git a/docs/magneticalc.MagnetiCalc_Data.MagnetiCalc_Data.html b/docs/magneticalc.MagnetiCalc_Data.MagnetiCalc_Data.html index f528e77..b1b3153 100644 --- a/docs/magneticalc.MagnetiCalc_Data.MagnetiCalc_Data.html +++ b/docs/magneticalc.MagnetiCalc_Data.MagnetiCalc_Data.html @@ -46,7 +46,7 @@

    magneticalc.MagnetiCalc_Data.MagnetiCalc_Data(
    -

    +
    @@ -60,6 +60,21 @@

    magneticalc.MagnetiCalc_Data.MagnetiCalc_Data(Undocumented

    + + + + + + + + + + + + + + + @@ -77,7 +92,7 @@

    magneticalc.MagnetiCalc_Data.MagnetiCalc_Data(Method

    - + @@ -125,6 +140,11 @@

    magneticalc.MagnetiCalc_Data.MagnetiCalc_Data(Undocumented

    + + + + + @@ -174,6 +194,63 @@

    magneticalc.MagnetiCalc_Data.MagnetiCalc_Data(
    + + + + + + +
    + + def + get_wire(self): + +
    +
    + + +

    Gets the wire points as three separate 1D arrays (raveled).

    Methodget_wireGets the wire points as three separate 1D arrays (raveled).
    Methodget_wire_listGets the wire points as a single list of 3D points (raveled).
    Methodget_currentGets the wire current.
    Method get_dimension Gets the sampling volume dimension.get_fieldGets the sampling volume axes as three separate 1D arrays (raveled).Gets the field as three separate 1D arrays (raveled).
    Method
    Method_get_fieldsGets the raw "fields" dictionary from the data.
    Method _keytransform Undocumented
    Returnsx, y, z
    + +
    + + + + + + + +
    + + def + get_wire_list(self): + +
    +
    + + +

    Gets the wire points as a single list of 3D points (raveled).

    ReturnsList
    +
    +
    + + + + + + + +
    + + def + get_current(self): + +
    +
    + + +

    Gets the wire current.

    +
    +
    + @@ -246,7 +323,7 @@

    magneticalc.MagnetiCalc_Data.MagnetiCalc_Data( -

    Gets the sampling volume axes as three separate 1D arrays (raveled).

    Parametersfield_typeField type ("A" or "B")
    as_3dEnable to transform each raveled 1D array into an unraveled 3D mesh (indexed by the minimal axes)
    +

    Gets the field as three separate 1D arrays (raveled).

    Parametersfield_typeField type ("A" or "B")
    as_3dEnable to transform each raveled 1D array into an unraveled 3D mesh (indexed by the minimal axes)

    @@ -324,6 +401,25 @@

    magneticalc.MagnetiCalc_Data.MagnetiCalc_Data(

    Gets the B-field components as a single list of 3D points (raveled).

    ParametersList

    +
    + + + + + + + +
    + + def + _get_fields(self): + +
    +
    + + +

    Gets the raw "fields" dictionary from the data.

    ReturnsDictionary
    +
    diff --git a/docs/magneticalc.MagnetiCalc_Data.html b/docs/magneticalc.MagnetiCalc_Data.html index 74ff346..0de2a62 100644 --- a/docs/magneticalc.MagnetiCalc_Data.html +++ b/docs/magneticalc.MagnetiCalc_Data.html @@ -46,7 +46,7 @@

    magneticalc.MagnetiCalc_Data module docum
    - +
    @@ -66,7 +66,7 @@

    magneticalc.MagnetiCalc_Data module docum
    - API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-02 09:06:24. + API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-03 23:22:21.
    diff --git a/docs/magneticalc.Menu.Menu.html b/docs/magneticalc.Menu.Menu.html index afc065e..3314bf0 100644 --- a/docs/magneticalc.Menu.Menu.html +++ b/docs/magneticalc.Menu.Menu.html @@ -46,12 +46,12 @@

    magneticalc.Menu.Menu class documentation<
    -

    +
    - + @@ -95,6 +95,11 @@

    magneticalc.Menu.Menu class documentation<

    + + + + + @@ -129,14 +134,14 @@

    magneticalc.Menu.Menu class documentation<
    - + - +
    - Backends_List = + Backends_Available_List =
    @@ -279,6 +284,25 @@

    magneticalc.Menu.Menu class documentation<

    + + + + + + +
    + + def + on_show_gauss_changed(self): + +
    +
    + + +

    Gets called when the "Show Gauss instead of Tesla" option changed.

    +
    +
    + @@ -376,7 +400,7 @@

    magneticalc.Menu.Menu class documentation<

    - API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-02 09:06:24. + API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-03 23:22:21.
    diff --git a/docs/magneticalc.Menu.html b/docs/magneticalc.Menu.html index debe46b..7175192 100644 --- a/docs/magneticalc.Menu.html +++ b/docs/magneticalc.Menu.html @@ -46,7 +46,7 @@

    magneticalc.Menu module documentation
    -

    Class VariableBackends_ListBackends_Available_List Undocumented
    Re-initializes the menu.
    Methodon_show_gauss_changedGets called when the "Show Gauss instead of Tesla" option changed.
    Method on_backend_changed Gets called when the backend changed.
    +
    @@ -66,7 +66,7 @@

    magneticalc.Menu module documentation
    - API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-02 09:06:24. + API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-03 23:22:21.
    diff --git a/docs/magneticalc.Metric.Metric.html b/docs/magneticalc.Metric.Metric.html index 3184167..00dd92f 100644 --- a/docs/magneticalc.Metric.Metric.html +++ b/docs/magneticalc.Metric.Metric.html @@ -46,7 +46,7 @@

    magneticalc.Metric.Metric class documentat
    -

    +
    @@ -385,15 +385,15 @@

    magneticalc.Metric.Metric class documentat
    - @staticmethod
    @jit(nopython=True, parallel=True)
    + @staticmethod
    @ConditionalDecorator(get_jit_enabled(), jit, nopython=True, parallel=True)
    def - _norm_worker(norm_id, vectors): + _norm_worker(norm_type, vectors):
    -

    Calculates the norm values of a list of vectors.

    Parametersnorm_idNorm ID
    vectorsOrdered list of 3D vectors
    ReturnsNorm values
    +

    Calculates the norm values of a list of vectors.

    Parametersnorm_typeNorm type
    vectorsOrdered list of 3D vectors
    ReturnsNorm values
    @@ -404,7 +404,7 @@

    magneticalc.Metric.Metric class documentat
    - @staticmethod
    @jit(nopython=True, parallel=True)
    + @staticmethod
    @ConditionalDecorator(get_jit_enabled(), jit, nopython=True, parallel=True)
    def _divergence_worker(sampling_volume_neighborhood_indices, vectors, dL, polarity): @@ -423,7 +423,7 @@

    magneticalc.Metric.Metric class documentat
    - @staticmethod
    @jit(nopython=True, parallel=True)
    + @staticmethod
    @ConditionalDecorator(get_jit_enabled(), jit, nopython=True, parallel=True)
    def _normalize_worker(color_map_id, color_is_log, color_norm_values, color_norm_min, color_norm_max, alpha_is_log, alpha_norm_values, alpha_norm_min, alpha_norm_max, colors): @@ -461,7 +461,7 @@

    magneticalc.Metric.Metric class documentat
    - @staticmethod
    @jit(nopython=True, parallel=True)
    + @staticmethod
    @ConditionalDecorator(get_jit_enabled(), jit, nopython=True, parallel=True)
    def boost_colors(boost, direction, colors): @@ -475,7 +475,7 @@

    magneticalc.Metric.Metric class documentat

    - API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-02 09:06:24. + API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-03 23:22:21.

    diff --git a/docs/magneticalc.Metric.html b/docs/magneticalc.Metric.html index 1c89b44..13c26d3 100644 --- a/docs/magneticalc.Metric.html +++ b/docs/magneticalc.Metric.html @@ -46,7 +46,7 @@

    magneticalc.Metric module documentation
    - +
    @@ -91,15 +91,15 @@

    magneticalc.Metric module documentation
    - @jit(nopython=True, parallel=False)
    + @ConditionalDecorator(get_jit_enabled(), jit, nopython=True, parallel=False)
    def - metric_norm(norm_id, vector): + metric_norm(norm_type, vector):
    -

    Calculates the selected norm of some vector.

    Note: For JIT to work, this must be declared at the top level.

    Parametersnorm_idNorm ID
    vector3D vector
    +

    Calculates the selected norm of some vector.

    Note: For JIT to work, this must be declared at the top level.

    Parametersnorm_typeNorm type
    vector3D vector

    @@ -110,7 +110,7 @@

    magneticalc.Metric module documentation
    - @jit(nopython=True, parallel=False)
    + @ConditionalDecorator(get_jit_enabled(), jit, nopython=True, parallel=False)
    def metric_divergence(neighborhood_vectors, dL, polarity): @@ -129,7 +129,7 @@

    magneticalc.Metric module documentation
    - @jit(nopython=True, parallel=False)
    + @ConditionalDecorator(get_jit_enabled(), jit, nopython=True, parallel=False)
    def color_map_divergent(color_normalized): @@ -148,7 +148,7 @@

    magneticalc.Metric module documentation
    - @jit(nopython=True, parallel=False)
    + @ConditionalDecorator(get_jit_enabled(), jit, nopython=True, parallel=False)
    def color_map_cyclic(color_normalized): @@ -162,7 +162,7 @@

    magneticalc.Metric module documentation
    - API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-02 09:06:24. + API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-03 23:22:21.

    diff --git a/docs/magneticalc.Metric_Presets.Metric_Presets.html b/docs/magneticalc.Metric_Presets.Metric_Presets.html index 1401b3f..2630cda 100644 --- a/docs/magneticalc.Metric_Presets.Metric_Presets.html +++ b/docs/magneticalc.Metric_Presets.Metric_Presets.html @@ -46,7 +46,7 @@

    magneticalc.Metric_Presets.Metric_Presets

    - +
    @@ -56,22 +56,22 @@

    magneticalc.Metric_Presets.Metric_Presets

    - + - + - + - + @@ -196,71 +196,71 @@

    magneticalc.Metric_Presets.Metric_Presets
    -
    Undocumented
    (type: Dict) +
    Undocumented
    - + - +
    - MagnitudeXY = + MagnitudeX =
    -
    Undocumented
    (type: Dict) +
    Undocumented
    - + - +
    - MagnitudeX = + MagnitudeY =
    -
    Undocumented
    (type: Dict) +
    Undocumented
    - + - +
    - MagnitudeY = + MagnitudeZ =
    -
    Undocumented
    (type: Dict) +
    Undocumented
    - + - +
    - MagnitudeZ = + MagnitudeXY =
    -
    Undocumented
    (type: Dict) +
    Undocumented
    @@ -276,7 +276,7 @@

    magneticalc.Metric_Presets.Metric_Presets

    -
    Undocumented
    (type: Dict) +
    Undocumented
    @@ -292,7 +292,7 @@

    magneticalc.Metric_Presets.Metric_Presets

    -
    Undocumented
    (type: Dict) +
    Undocumented
    @@ -308,7 +308,7 @@

    magneticalc.Metric_Presets.Metric_Presets

    -
    Undocumented
    (type: Dict) +
    Undocumented
    @@ -324,7 +324,7 @@

    magneticalc.Metric_Presets.Metric_Presets

    -
    Undocumented
    (type: Dict) +
    Undocumented
    @@ -340,7 +340,7 @@

    magneticalc.Metric_Presets.Metric_Presets

    -
    Undocumented
    (type: Dict) +
    Undocumented
    @@ -356,7 +356,7 @@

    magneticalc.Metric_Presets.Metric_Presets

    -
    Undocumented
    (type: Dict) +
    Undocumented
    @@ -372,7 +372,7 @@

    magneticalc.Metric_Presets.Metric_Presets

    -
    Undocumented
    (type: Dict) +
    Undocumented
    @@ -388,7 +388,7 @@

    magneticalc.Metric_Presets.Metric_Presets

    -
    Undocumented
    (type: Dict) +
    Undocumented
    @@ -404,7 +404,7 @@

    magneticalc.Metric_Presets.Metric_Presets

    -
    Undocumented
    (type: Dict) +
    Undocumented
    @@ -420,7 +420,7 @@

    magneticalc.Metric_Presets.Metric_Presets

    -
    Undocumented
    (type: Dict) +
    Undocumented
    @@ -436,7 +436,7 @@

    magneticalc.Metric_Presets.Metric_Presets

    -
    Undocumented
    (type: Dict) +
    Undocumented
    @@ -452,7 +452,7 @@

    magneticalc.Metric_Presets.Metric_Presets

    -
    Undocumented
    (type: Dict) +
    Undocumented
    @@ -468,7 +468,7 @@

    magneticalc.Metric_Presets.Metric_Presets

    -
    Undocumented
    (type: Dict) +
    Undocumented
    @@ -484,7 +484,7 @@

    magneticalc.Metric_Presets.Metric_Presets

    -
    Undocumented
    (type: Dict) +
    Undocumented
    @@ -500,7 +500,7 @@

    magneticalc.Metric_Presets.Metric_Presets

    -
    Undocumented
    (type: Dict) +
    Undocumented
    @@ -516,7 +516,7 @@

    magneticalc.Metric_Presets.Metric_Presets

    -
    Undocumented
    (type: Dict) +
    Undocumented
    @@ -532,7 +532,7 @@

    magneticalc.Metric_Presets.Metric_Presets

    -
    Undocumented
    (type: Dict) +
    Undocumented
    @@ -548,7 +548,7 @@

    magneticalc.Metric_Presets.Metric_Presets

    -
    Undocumented
    (type: Dict) +
    Undocumented
    @@ -589,7 +589,7 @@

    magneticalc.Metric_Presets.Metric_Presets

    - API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-02 09:06:24. + API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-03 23:22:21.
    diff --git a/docs/magneticalc.Metric_Presets.html b/docs/magneticalc.Metric_Presets.html index 990f1fa..4372996 100644 --- a/docs/magneticalc.Metric_Presets.html +++ b/docs/magneticalc.Metric_Presets.html @@ -46,7 +46,7 @@

    magneticalc.Metric_Presets module documen
    -

    Class VariableMagnitudeXYMagnitudeX Undocumented
    Class VariableMagnitudeXMagnitudeY Undocumented
    Class VariableMagnitudeYMagnitudeZ Undocumented
    Class VariableMagnitudeZMagnitudeXY Undocumented
    +
    @@ -66,7 +66,7 @@

    magneticalc.Metric_Presets module documen
    - API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-02 09:06:24. + API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-03 23:22:21.
    diff --git a/docs/magneticalc.Metric_Widget.Metric_Widget.html b/docs/magneticalc.Metric_Widget.Metric_Widget.html index 3220dda..2fc13e9 100644 --- a/docs/magneticalc.Metric_Widget.Metric_Widget.html +++ b/docs/magneticalc.Metric_Widget.Metric_Widget.html @@ -46,7 +46,7 @@

    magneticalc.Metric_Widget.Metric_Widget( -

    +
    @@ -144,14 +144,9 @@

    magneticalc.Metric_Widget.Metric_Widget( Inherited from QLayouted (via QGroupBox2):

    -

    +
    - - - - - - + @@ -176,6 +171,11 @@

    magneticalc.Metric_Widget.Metric_Widget(addButtons

    + + + + +
    Instance VariablelayoutUndocumented
    Method install_layoutAdds buttons.
    Instance Variable_layoutUndocumented
    @@ -489,7 +489,7 @@

    magneticalc.Metric_Widget.Metric_Widget(API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-02 09:06:24. + API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-03 23:22:21.

    diff --git a/docs/magneticalc.Metric_Widget.html b/docs/magneticalc.Metric_Widget.html index 4676ac5..b12607f 100644 --- a/docs/magneticalc.Metric_Widget.html +++ b/docs/magneticalc.Metric_Widget.html @@ -46,7 +46,7 @@

    magneticalc.Metric_Widget module document

    - +
    @@ -66,7 +66,7 @@

    magneticalc.Metric_Widget module document
    - API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-02 09:06:24. + API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-03 23:22:21.
    diff --git a/docs/magneticalc.Model.Model.html b/docs/magneticalc.Model.Model.html index d077dee..5101acf 100644 --- a/docs/magneticalc.Model.Model.html +++ b/docs/magneticalc.Model.Model.html @@ -46,7 +46,7 @@

    magneticalc.Model.Model class documentatio
    -

    +
    @@ -856,7 +856,7 @@

    magneticalc.Model.Model class documentatio
    - API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-02 09:06:24. + API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-03 23:22:21.
    diff --git a/docs/magneticalc.Model.html b/docs/magneticalc.Model.html index d86e657..1bdf865 100644 --- a/docs/magneticalc.Model.html +++ b/docs/magneticalc.Model.html @@ -46,7 +46,7 @@

    magneticalc.Model module documentation
    -

    +
    @@ -66,7 +66,7 @@

    magneticalc.Model module documentation
    - API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-02 09:06:24. + API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-03 23:22:21.
    diff --git a/docs/magneticalc.ModelAccess.ModelAccess.html b/docs/magneticalc.ModelAccess.ModelAccess.html index 80cf223..9daeaf6 100644 --- a/docs/magneticalc.ModelAccess.ModelAccess.html +++ b/docs/magneticalc.ModelAccess.ModelAccess.html @@ -46,14 +46,9 @@

    magneticalc.ModelAccess.ModelAccess class
    -

    +
    - - - - - - + @@ -63,11 +58,6 @@

    magneticalc.ModelAccess.ModelAccess class

    - - - - - @@ -78,6 +68,11 @@

    magneticalc.ModelAccess.ModelAccess class

    + + + + +
    Class VariableDebugColorUndocumented
    Method __init__Instance Variable gui Undocumented
    Instance VariablerecalculateUndocumented
    MethodMethod __exit__ Leaving the context starts recalculation if enabled; otherwise, just redraw.
    Instance Variable_recalculateUndocumented
    @@ -87,23 +82,7 @@

    magneticalc.ModelAccess.ModelAccess class
    -
    - - - - - - - -
    - DebugColor = - -
    -
    - -
    Undocumented
    (type: str) -
    -
    - + - +
    - recalculate = + _recalculate =
    @@ -196,7 +175,7 @@

    magneticalc.ModelAccess.ModelAccess class

    - API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-02 09:06:24. + API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-03 23:22:21.
    diff --git a/docs/magneticalc.ModelAccess.html b/docs/magneticalc.ModelAccess.html index d4ed9f7..8b748a3 100644 --- a/docs/magneticalc.ModelAccess.html +++ b/docs/magneticalc.ModelAccess.html @@ -46,7 +46,7 @@

    magneticalc.ModelAccess module documentat

    - +
    @@ -66,7 +66,7 @@

    magneticalc.ModelAccess module documentat
    - API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-02 09:06:24. + API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-03 23:22:21.
    diff --git a/docs/magneticalc.Norm_Types.html b/docs/magneticalc.Norm_Types.html new file mode 100644 index 0000000..4640a3b --- /dev/null +++ b/docs/magneticalc.Norm_Types.html @@ -0,0 +1,435 @@ + + + + + magneticalc.Norm_Types : API documentation + + + + + + + + + +
    + +
    + +
    + + + +
    + +
    + +
    +

    Norm_Types module.

    +
    + +
    +

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    VariableNORM_TYPE_XUndocumented
    VariableNORM_TYPE_YUndocumented
    VariableNORM_TYPE_ZUndocumented
    VariableNORM_TYPE_RADIUSUndocumented
    VariableNORM_TYPE_RADIUS_XUndocumented
    VariableNORM_TYPE_RADIUS_YUndocumented
    VariableNORM_TYPE_RADIUS_ZUndocumented
    VariableNORM_TYPE_RADIUS_XYUndocumented
    VariableNORM_TYPE_RADIUS_XZUndocumented
    VariableNORM_TYPE_RADIUS_YZUndocumented
    VariableNORM_TYPE_ANGLE_XYUndocumented
    VariableNORM_TYPE_ANGLE_XZUndocumented
    VariableNORM_TYPE_ANGLE_YZUndocumented
    VariableNORM_TYPE_DIVERGENCEUndocumented
    VariableNorm_Types_Str_MapUndocumented
    Functionnorm_type_to_strConverts a norm type to a norm string.
    Functionnorm_type_from_strConverts a norm string to a norm type.
    + + + +
    + +
    + +
    + + + + + + + +
    + NORM_TYPE_X = + +
    +
    + +
    Undocumented
    (type: int) +
    +
    + + + + + + + +
    + NORM_TYPE_Y = + +
    +
    + +
    Undocumented
    (type: int) +
    +
    + + + + + + + +
    + NORM_TYPE_Z = + +
    +
    + +
    Undocumented
    (type: int) +
    +
    + + + + + + + +
    + NORM_TYPE_RADIUS = + +
    +
    + +
    Undocumented
    (type: int) +
    +
    + + + + + + + +
    + NORM_TYPE_RADIUS_X = + +
    +
    + +
    Undocumented
    (type: int) +
    +
    + + + + + + + +
    + NORM_TYPE_RADIUS_Y = + +
    +
    + +
    Undocumented
    (type: int) +
    +
    + + + + + + + +
    + NORM_TYPE_RADIUS_Z = + +
    +
    + +
    Undocumented
    (type: int) +
    +
    + + + + + + + +
    + NORM_TYPE_RADIUS_XY = + +
    +
    + +
    Undocumented
    (type: int) +
    +
    + + + + + + + +
    + NORM_TYPE_RADIUS_XZ = + +
    +
    + +
    Undocumented
    (type: int) +
    +
    + + + + + + + +
    + NORM_TYPE_RADIUS_YZ = + +
    +
    + +
    Undocumented
    (type: int) +
    +
    + + + + + + + +
    + NORM_TYPE_ANGLE_XY = + +
    +
    + +
    Undocumented
    (type: int) +
    +
    + + + + + + + +
    + NORM_TYPE_ANGLE_XZ = + +
    +
    + +
    Undocumented
    (type: int) +
    +
    + + + + + + + +
    + NORM_TYPE_ANGLE_YZ = + +
    +
    + +
    Undocumented
    (type: int) +
    +
    + + + + + + + +
    + NORM_TYPE_DIVERGENCE = + +
    +
    + +
    Undocumented
    (type: int) +
    +
    + + + + + + + +
    + Norm_Types_Str_Map = + +
    +
    + +
    Undocumented
    +
    +
    + + + + + + + +
    + + def + norm_type_to_str(norm_type): + +
    +
    + + +

    Converts a norm type to a norm string.

    Parametersnorm_typeNorm type
    ReturnsNorm string, or None if norm type is invalid
    +
    +
    + + + + + + + +
    + + def + norm_type_from_str(norm_str): + +
    +
    + + +

    Converts a norm string to a norm type.

    Parametersnorm_strNorm string @return Norm type, or None if norm string is invalid
    +
    +
    + +
    +
    + API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-03 23:22:21. +
    + +

    + + + + + \ No newline at end of file diff --git a/docs/magneticalc.OverridePadding_Dialog.OverridePadding_Dialog.html b/docs/magneticalc.OverridePadding_Dialog.OverridePadding_Dialog.html index 89c4cbf..f5825a5 100644 --- a/docs/magneticalc.OverridePadding_Dialog.OverridePadding_Dialog.html +++ b/docs/magneticalc.OverridePadding_Dialog.OverridePadding_Dialog.html @@ -46,7 +46,7 @@

    magneticalc.OverridePadding_Dialog.OverridePadding_Dialo

    - +
    @@ -89,7 +89,7 @@

    magneticalc.OverridePadding_Dialog.OverridePadding_Dialo

    Inherited from QDialog2:

    -

    +
    @@ -117,14 +117,9 @@

    magneticalc.OverridePadding_Dialog.OverridePadding_Dialo

    Inherited from QLayouted (via QDialog2):

    -

    +
    - - - - - - + @@ -149,6 +144,11 @@

    magneticalc.OverridePadding_Dialog.OverridePadding_Dialo

    + + + + +
    Instance VariablelayoutUndocumented
    Method install_layoutMethod addButtons Adds buttons.
    Instance Variable_layoutUndocumented
    @@ -280,7 +280,7 @@

    magneticalc.OverridePadding_Dialog.OverridePadding_Dialo

    - API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-02 09:06:24. + API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-03 23:22:21.
    diff --git a/docs/magneticalc.OverridePadding_Dialog.html b/docs/magneticalc.OverridePadding_Dialog.html index 402bb23..e165e2e 100644 --- a/docs/magneticalc.OverridePadding_Dialog.html +++ b/docs/magneticalc.OverridePadding_Dialog.html @@ -46,7 +46,7 @@

    magneticalc.OverridePadding_Dialog module
    - +
    @@ -66,7 +66,7 @@

    magneticalc.OverridePadding_Dialog module
    - API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-02 09:06:24. + API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-03 23:22:21.
    diff --git a/docs/magneticalc.Parameters.Parameters.html b/docs/magneticalc.Parameters.Parameters.html index ff8362f..89e83e9 100644 --- a/docs/magneticalc.Parameters.Parameters.html +++ b/docs/magneticalc.Parameters.Parameters.html @@ -46,7 +46,7 @@

    magneticalc.Parameters.Parameters class do
    -

    +
    @@ -317,7 +317,7 @@

    magneticalc.Parameters.Parameters class do
    - @staticmethod
    @jit(nopython=True, parallel=True)
    + @staticmethod
    @ConditionalDecorator(get_jit_enabled(), jit, nopython=True, parallel=True)
    def _get_squared_field_worker(sampling_volume_permeabilities, field_vectors): @@ -355,7 +355,7 @@

    magneticalc.Parameters.Parameters class do
    - @staticmethod
    @jit(nopython=True, parallel=True)
    + @staticmethod
    @ConditionalDecorator(get_jit_enabled(), jit, nopython=True, parallel=True)
    def _get_magnetic_dipole_moment_worker(elements_center, elements_direction, length_scale): @@ -388,7 +388,7 @@

    magneticalc.Parameters.Parameters class do

    - API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-02 09:06:24. + API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-03 23:22:21.

    diff --git a/docs/magneticalc.Parameters.html b/docs/magneticalc.Parameters.html index 7a1fd94..0e8e3e9 100644 --- a/docs/magneticalc.Parameters.html +++ b/docs/magneticalc.Parameters.html @@ -46,7 +46,7 @@

    magneticalc.Parameters module documentati
    -

    +
    @@ -66,7 +66,7 @@

    magneticalc.Parameters module documentati
    - API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-02 09:06:24. + API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-03 23:22:21.
    diff --git a/docs/magneticalc.Parameters_Widget.Parameters_Widget.html b/docs/magneticalc.Parameters_Widget.Parameters_Widget.html index b6a71ea..fd0ff3d 100644 --- a/docs/magneticalc.Parameters_Widget.Parameters_Widget.html +++ b/docs/magneticalc.Parameters_Widget.Parameters_Widget.html @@ -46,7 +46,7 @@

    magneticalc.Parameters_Widget.Parameters_Widget(
    -

    +
    @@ -114,14 +114,9 @@

    magneticalc.Parameters_Widget.Parameters_Widget( Inherited from QLayouted (via QGroupBox2):

    -

    +
    - - - - - - + @@ -146,6 +141,11 @@

    magneticalc.Parameters_Widget.Parameters_Widget(Method

    + + + + +
    Instance VariablelayoutUndocumented
    Method install_layoutaddButtons Adds buttons.
    Instance Variable_layoutUndocumented
    @@ -357,7 +357,7 @@

    magneticalc.Parameters_Widget.Parameters_Widget(
    - API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-02 09:06:24. + API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-03 23:22:21.

    diff --git a/docs/magneticalc.Parameters_Widget.html b/docs/magneticalc.Parameters_Widget.html index bb90044..411d00f 100644 --- a/docs/magneticalc.Parameters_Widget.html +++ b/docs/magneticalc.Parameters_Widget.html @@ -46,7 +46,7 @@

    magneticalc.Parameters_Widget module docu
    - +
    @@ -66,7 +66,7 @@

    magneticalc.Parameters_Widget module docu
    - API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-02 09:06:24. + API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-03 23:22:21.
    diff --git a/docs/magneticalc.Perspective_Presets.Perspective_Presets.html b/docs/magneticalc.Perspective_Presets.Perspective_Presets.html index 9eac787..2254b09 100644 --- a/docs/magneticalc.Perspective_Presets.Perspective_Presets.html +++ b/docs/magneticalc.Perspective_Presets.Perspective_Presets.html @@ -46,7 +46,7 @@

    magneticalc.Perspective_Presets.Perspective_Presets
    -

    +
    @@ -190,7 +190,7 @@

    magneticalc.Perspective_Presets.Perspective_Presets
    - API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-02 09:06:24. + API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-03 23:22:21.
    diff --git a/docs/magneticalc.Perspective_Presets.html b/docs/magneticalc.Perspective_Presets.html index 3f4d9f9..6d4e946 100644 --- a/docs/magneticalc.Perspective_Presets.html +++ b/docs/magneticalc.Perspective_Presets.html @@ -46,7 +46,7 @@

    magneticalc.Perspective_Presets module do
    -

    +
    @@ -66,7 +66,7 @@

    magneticalc.Perspective_Presets module do
    - API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-02 09:06:24. + API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-03 23:22:21.
    diff --git a/docs/magneticalc.Perspective_Widget.Perspective_Widget.html b/docs/magneticalc.Perspective_Widget.Perspective_Widget.html index 1a9e9af..648cf75 100644 --- a/docs/magneticalc.Perspective_Widget.Perspective_Widget.html +++ b/docs/magneticalc.Perspective_Widget.Perspective_Widget.html @@ -46,7 +46,7 @@

    magneticalc.Perspective_Widget.Perspective_Widget(
    -

    +
    @@ -69,14 +69,9 @@

    magneticalc.Perspective_Widget.Perspective_Widget( Inherited from QLayouted (via QGroupBox2):

    -

    +
    - - - - - - + @@ -101,6 +96,11 @@

    magneticalc.Perspective_Widget.Perspective_Widget(Method

    + + + + +
    Instance VariablelayoutUndocumented
    Method install_layoutaddButtons Adds buttons.
    Instance Variable_layoutUndocumented
    @@ -168,7 +168,7 @@

    magneticalc.Perspective_Widget.Perspective_Widget(
    - API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-02 09:06:24. + API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-03 23:22:21.

    diff --git a/docs/magneticalc.Perspective_Widget.html b/docs/magneticalc.Perspective_Widget.html index b3da0ea..0c6dbe8 100644 --- a/docs/magneticalc.Perspective_Widget.html +++ b/docs/magneticalc.Perspective_Widget.html @@ -46,7 +46,7 @@

    magneticalc.Perspective_Widget module doc
    - +
    @@ -66,7 +66,7 @@

    magneticalc.Perspective_Widget module doc
    - API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-02 09:06:24. + API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-03 23:22:21.
    diff --git a/docs/magneticalc.QButtons.QButtons.html b/docs/magneticalc.QButtons.QButtons.html index d9ef616..c38171a 100644 --- a/docs/magneticalc.QButtons.QButtons.html +++ b/docs/magneticalc.QButtons.QButtons.html @@ -46,7 +46,7 @@

    magneticalc.QButtons.QButtons( -

    +
    @@ -106,7 +106,7 @@

    magneticalc.QButtons.QButtons(API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-02 09:06:24. + API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-03 23:22:21. diff --git a/docs/magneticalc.QButtons.html b/docs/magneticalc.QButtons.html index 1775c4d..616465c 100644 --- a/docs/magneticalc.QButtons.html +++ b/docs/magneticalc.QButtons.html @@ -46,7 +46,7 @@

    magneticalc.QButtons module documentation
    -

    +
    @@ -66,7 +66,7 @@

    magneticalc.QButtons module documentation
    - API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-02 09:06:24. + API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-03 23:22:21.
    diff --git a/docs/magneticalc.QDialog2.QDialog2.html b/docs/magneticalc.QDialog2.QDialog2.html index db121f8..bfc5ebd 100644 --- a/docs/magneticalc.QDialog2.QDialog2.html +++ b/docs/magneticalc.QDialog2.QDialog2.html @@ -46,7 +46,7 @@

    magneticalc.QDialog2.QDialog2( -

    +
    @@ -79,14 +79,9 @@

    magneticalc.QDialog2.QDialog2( Inherited from QLayouted:

    -

    +
    - - - - - - + @@ -111,6 +106,11 @@

    magneticalc.QDialog2.QDialog2(addButtons

    + + + + +
    Instance VariablelayoutUndocumented
    Method install_layoutAdds buttons.
    Instance Variable_layoutUndocumented
    @@ -186,7 +186,7 @@

    magneticalc.QDialog2.QDialog2( - +

    Shows this dialog.

    @@ -213,7 +213,7 @@

    magneticalc.QDialog2.QDialog2(API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-02 09:06:24. + API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-03 23:22:21. diff --git a/docs/magneticalc.QDialog2.html b/docs/magneticalc.QDialog2.html index a7a7c81..df5f8db 100644 --- a/docs/magneticalc.QDialog2.html +++ b/docs/magneticalc.QDialog2.html @@ -46,7 +46,7 @@

    magneticalc.QDialog2 module documentation
    - +
    @@ -66,7 +66,7 @@

    magneticalc.QDialog2 module documentation
    - API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-02 09:06:24. + API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-03 23:22:21.
    diff --git a/docs/magneticalc.QGroupBox2.QGroupBox2.html b/docs/magneticalc.QGroupBox2.QGroupBox2.html index 2622618..755e9a3 100644 --- a/docs/magneticalc.QGroupBox2.QGroupBox2.html +++ b/docs/magneticalc.QGroupBox2.QGroupBox2.html @@ -46,7 +46,7 @@

    magneticalc.QGroupBox2.QGroupBox2( -

    +
    @@ -59,14 +59,9 @@

    magneticalc.QGroupBox2.QGroupBox2( Inherited from QLayouted:

    -

    +
    - - - - - - + @@ -91,6 +86,11 @@

    magneticalc.QGroupBox2.QGroupBox2(addButtons

    + + + + +
    Instance VariablelayoutUndocumented
    Method install_layoutAdds buttons.
    Instance Variable_layoutUndocumented
    @@ -123,7 +123,7 @@

    magneticalc.QGroupBox2.QGroupBox2(API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-02 09:06:24. + API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-03 23:22:21.

    diff --git a/docs/magneticalc.QGroupBox2.html b/docs/magneticalc.QGroupBox2.html index 471fde2..700c017 100644 --- a/docs/magneticalc.QGroupBox2.html +++ b/docs/magneticalc.QGroupBox2.html @@ -46,7 +46,7 @@

    magneticalc.QGroupBox2 module documentati
    - +
    @@ -66,7 +66,7 @@

    magneticalc.QGroupBox2 module documentati
    - API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-02 09:06:24. + API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-03 23:22:21.
    diff --git a/docs/magneticalc.QHBoxLayout2.QHBoxLayout2.html b/docs/magneticalc.QHBoxLayout2.QHBoxLayout2.html index 08c6837..cbc87b9 100644 --- a/docs/magneticalc.QHBoxLayout2.QHBoxLayout2.html +++ b/docs/magneticalc.QHBoxLayout2.QHBoxLayout2.html @@ -46,7 +46,7 @@

    magneticalc.QHBoxLayout2.QHBoxLayout2( -

    +
    @@ -85,7 +85,7 @@

    magneticalc.QHBoxLayout2.QHBoxLayout2(API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-02 09:06:24. + API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-03 23:22:21. diff --git a/docs/magneticalc.QHBoxLayout2.html b/docs/magneticalc.QHBoxLayout2.html index 3b16418..3d7d204 100644 --- a/docs/magneticalc.QHBoxLayout2.html +++ b/docs/magneticalc.QHBoxLayout2.html @@ -46,7 +46,7 @@

    magneticalc.QHBoxLayout2 module documenta
    -

    +
    @@ -66,7 +66,7 @@

    magneticalc.QHBoxLayout2 module documenta
    - API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-02 09:06:24. + API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-03 23:22:21.
    diff --git a/docs/magneticalc.QHLine.QHLine.html b/docs/magneticalc.QHLine.QHLine.html index 43cb0ba..e13631b 100644 --- a/docs/magneticalc.QHLine.QHLine.html +++ b/docs/magneticalc.QHLine.QHLine.html @@ -46,7 +46,7 @@

    magneticalc.QHLine.QHLine( -

    +
    @@ -106,7 +106,7 @@

    magneticalc.QHLine.QHLine(API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-02 09:06:24. + API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-03 23:22:21. diff --git a/docs/magneticalc.QHLine.html b/docs/magneticalc.QHLine.html index 6730913..302f8ef 100644 --- a/docs/magneticalc.QHLine.html +++ b/docs/magneticalc.QHLine.html @@ -46,7 +46,7 @@

    magneticalc.QHLine module documentation
    -

    +
    @@ -66,7 +66,7 @@

    magneticalc.QHLine module documentation
    - API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-02 09:06:24. + API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-03 23:22:21.
    diff --git a/docs/magneticalc.QIconLabel.QIconLabel.html b/docs/magneticalc.QIconLabel.QIconLabel.html index 58ea347..54a1274 100644 --- a/docs/magneticalc.QIconLabel.QIconLabel.html +++ b/docs/magneticalc.QIconLabel.QIconLabel.html @@ -46,7 +46,7 @@

    magneticalc.QIconLabel.QIconLabel( -

    +
    @@ -106,7 +106,7 @@

    magneticalc.QIconLabel.QIconLabel(API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-02 09:06:24. + API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-03 23:22:21. diff --git a/docs/magneticalc.QIconLabel.html b/docs/magneticalc.QIconLabel.html index e65f840..05a9685 100644 --- a/docs/magneticalc.QIconLabel.html +++ b/docs/magneticalc.QIconLabel.html @@ -46,7 +46,7 @@

    magneticalc.QIconLabel module documentati
    -

    +
    @@ -66,7 +66,7 @@

    magneticalc.QIconLabel module documentati
    - API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-02 09:06:24. + API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-03 23:22:21.
    diff --git a/docs/magneticalc.QLabel2.QLabel2.html b/docs/magneticalc.QLabel2.QLabel2.html index 0b8b5a9..76b5a49 100644 --- a/docs/magneticalc.QLabel2.QLabel2.html +++ b/docs/magneticalc.QLabel2.QLabel2.html @@ -46,13 +46,18 @@

    magneticalc.QLabel2.QLabel2( -

    +
    + + + + +
    Method __init__ Initializes a QLabel.
    MethodsetSets the label properties.
    @@ -73,19 +78,38 @@

    magneticalc.QLabel2.QLabel2( def - __init__(self, text, font=None, bold=(False), italic=(False), color=None, fixed=(False)): + __init__(self, text, expand=(True), align_right=(False), **kwargs): + +

    +
    + + +

    Initializes a QLabel.

    Please see set() for supported arguments.

    ParameterstextText
    expandEnable to expand
    align_rightEnable to align right
    +
    +
    + + + + + + + +
    + + def + set(self, text, font=None, bold=(False), italic=(False), color="""black"""):
    -

    Initializes a QLabel.

    ParameterstextText
    fontQFont
    boldEnable for bold text
    italicEnable for italic text
    colorText color
    fixedEnable to set fixed layout size (don't expand)
    +

    Sets the label properties.

    ParameterstextText
    fontQFont
    boldEnable for bold text
    italicEnable for italic text
    colorText color
    - API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-02 09:06:24. + API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-03 23:22:21.
    diff --git a/docs/magneticalc.QLabel2.html b/docs/magneticalc.QLabel2.html index efc7697..4b463db 100644 --- a/docs/magneticalc.QLabel2.html +++ b/docs/magneticalc.QLabel2.html @@ -46,7 +46,7 @@

    magneticalc.QLabel2 module documentation<
    - +
    @@ -66,7 +66,7 @@

    magneticalc.QLabel2 module documentation<
    - API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-02 09:06:24. + API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-03 23:22:21.
    diff --git a/docs/magneticalc.QLayouted.QLayouted.html b/docs/magneticalc.QLayouted.QLayouted.html index 7f19bfe..275b10c 100644 --- a/docs/magneticalc.QLayouted.QLayouted.html +++ b/docs/magneticalc.QLayouted.QLayouted.html @@ -46,18 +46,13 @@

    magneticalc.QLayouted.QLayouted class docu
    -

    +
    - - - - - - + @@ -83,6 +78,11 @@

    magneticalc.QLayouted.QLayouted class docu

    + + + + +
    Method __init__Initializes the QLayouted class.
    Instance VariablelayoutUndocumentedInitializes the QLayouted class. This adds a layout and several related functions like addWidget() to the parent class.
    MethodMethod addButtons Adds buttons.
    Instance Variable_layoutUndocumented
    @@ -109,18 +109,18 @@

    magneticalc.QLayouted.QLayouted class docu
    -

    Initializes the QLayouted class.

    +

    Initializes the QLayouted class. This adds a layout and several related functions like addWidget() to the parent class.

    ParametersdirectionSets "vertical" or "horizontal" layout
    -

    +
    - + - +
    - layout = + _layout =
    @@ -226,7 +226,7 @@

    magneticalc.QLayouted.QLayouted class docu

    - API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-02 09:06:24. + API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-03 23:22:21.
    diff --git a/docs/magneticalc.QLayouted.html b/docs/magneticalc.QLayouted.html index 5247199..3f54651 100644 --- a/docs/magneticalc.QLayouted.html +++ b/docs/magneticalc.QLayouted.html @@ -46,7 +46,7 @@

    magneticalc.QLayouted module documentatio
    - +
    @@ -66,7 +66,7 @@

    magneticalc.QLayouted module documentatio
    - API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-02 09:06:24. + API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-03 23:22:21.
    diff --git a/docs/magneticalc.QMessageBox2.QMessageBox2.html b/docs/magneticalc.QMessageBox2.QMessageBox2.html index 08d38f3..43097ee 100644 --- a/docs/magneticalc.QMessageBox2.QMessageBox2.html +++ b/docs/magneticalc.QMessageBox2.QMessageBox2.html @@ -46,7 +46,7 @@

    magneticalc.QMessageBox2.QMessageBox2( -

    +
    @@ -106,7 +106,7 @@

    magneticalc.QMessageBox2.QMessageBox2(API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-02 09:06:24. + API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-03 23:22:21. diff --git a/docs/magneticalc.QMessageBox2.html b/docs/magneticalc.QMessageBox2.html index 65c1b0c..acdb9c0 100644 --- a/docs/magneticalc.QMessageBox2.html +++ b/docs/magneticalc.QMessageBox2.html @@ -46,7 +46,7 @@

    magneticalc.QMessageBox2 module documenta
    -

    +
    @@ -66,7 +66,7 @@

    magneticalc.QMessageBox2 module documenta
    - API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-02 09:06:24. + API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-03 23:22:21.
    diff --git a/docs/magneticalc.QSaveAction.QSaveAction.html b/docs/magneticalc.QSaveAction.QSaveAction.html index e4778f2..c1e8ed8 100644 --- a/docs/magneticalc.QSaveAction.QSaveAction.html +++ b/docs/magneticalc.QSaveAction.QSaveAction.html @@ -46,7 +46,7 @@

    magneticalc.QSaveAction.QSaveAction class
    -

    +
    @@ -106,7 +106,7 @@

    magneticalc.QSaveAction.QSaveAction class
    - API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-02 09:06:24. + API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-03 23:22:21.
    diff --git a/docs/magneticalc.QSaveAction.html b/docs/magneticalc.QSaveAction.html index 90cbd0a..8c3610d 100644 --- a/docs/magneticalc.QSaveAction.html +++ b/docs/magneticalc.QSaveAction.html @@ -46,7 +46,7 @@

    magneticalc.QSaveAction module documentat
    -

    +
    @@ -66,7 +66,7 @@

    magneticalc.QSaveAction module documentat
    - API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-02 09:06:24. + API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-03 23:22:21.
    diff --git a/docs/magneticalc.QSliderFloat.QSliderFloat.html b/docs/magneticalc.QSliderFloat.QSliderFloat.html index bccc757..3304b6d 100644 --- a/docs/magneticalc.QSliderFloat.QSliderFloat.html +++ b/docs/magneticalc.QSliderFloat.QSliderFloat.html @@ -46,7 +46,7 @@

    magneticalc.QSliderFloat.QSliderFloat( -

    +
    @@ -178,7 +178,7 @@

    magneticalc.QSliderFloat.QSliderFloat(API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-02 09:06:24. + API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-03 23:22:21. diff --git a/docs/magneticalc.QSliderFloat.html b/docs/magneticalc.QSliderFloat.html index 9cd1f6a..8b71ccb 100644 --- a/docs/magneticalc.QSliderFloat.html +++ b/docs/magneticalc.QSliderFloat.html @@ -46,7 +46,7 @@

    magneticalc.QSliderFloat module documenta
    -

    +
    @@ -66,7 +66,7 @@

    magneticalc.QSliderFloat module documenta
    - API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-02 09:06:24. + API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-03 23:22:21.
    diff --git a/docs/magneticalc.QSpinBox2.QSpinBox2.html b/docs/magneticalc.QSpinBox2.QSpinBox2.html index 4257e8f..071d627 100644 --- a/docs/magneticalc.QSpinBox2.QSpinBox2.html +++ b/docs/magneticalc.QSpinBox2.QSpinBox2.html @@ -46,7 +46,7 @@

    magneticalc.QSpinBox2.QSpinBox2( -

    +
    @@ -85,7 +85,7 @@

    magneticalc.QSpinBox2.QSpinBox2(API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-02 09:06:24. + API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-03 23:22:21. diff --git a/docs/magneticalc.QSpinBox2.html b/docs/magneticalc.QSpinBox2.html index 96c5e00..3b61a2e 100644 --- a/docs/magneticalc.QSpinBox2.html +++ b/docs/magneticalc.QSpinBox2.html @@ -46,7 +46,7 @@

    magneticalc.QSpinBox2 module documentatio
    -

    +
    @@ -66,7 +66,7 @@

    magneticalc.QSpinBox2 module documentatio
    - API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-02 09:06:24. + API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-03 23:22:21.
    diff --git a/docs/magneticalc.QTableWidget2.QTableWidget2.html b/docs/magneticalc.QTableWidget2.QTableWidget2.html index 3002529..d0b9b7c 100644 --- a/docs/magneticalc.QTableWidget2.QTableWidget2.html +++ b/docs/magneticalc.QTableWidget2.QTableWidget2.html @@ -46,18 +46,13 @@

    magneticalc.QTableWidget2.QTableWidget2( -

    +
    - - - - - @@ -228,22 +223,6 @@

    magneticalc.QTableWidget2.QTableWidget2(Undocumented (type: int) -
    - - - - - - - -
    - DebugColor = - -
    -
    - -
    Undocumented
    (type: Tuple[int, ...]) -

    Class Variable MinimumHeight Undocumented
    Class VariableDebugColorUndocumented
    Method
    ParameterscomboboxQCombobox
    rowRow
    columnColumn
    +

    Gets called when a combobox cell has been edited.

    ParameterscomboboxQCombobox
    rowRow index
    columnColumn index
    @@ -747,7 +726,7 @@

    magneticalc.QTableWidget2.QTableWidget2( -

    Gets called when the table gained focus. This highlights the border and selects the last-selected cell (if any).

    Parameters_eventEvent
    +

    Gets called when the table gained focus. This highlights the border and selects the last-selected cell (if any).

    Parameters_eventQFocusEvent

    @@ -766,13 +745,13 @@

    magneticalc.QTableWidget2.QTableWidget2( - +

    Gets called when the table lost focus, or when a cell item is being edited, or when a cell widget is selected. When not editing, this clears the selection, triggering on_selection_changed

    Parameters_eventQFocusEvent

    - API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-02 09:06:24. + API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-03 23:22:21.
    diff --git a/docs/magneticalc.QTableWidget2.html b/docs/magneticalc.QTableWidget2.html index 133f75f..8ac2377 100644 --- a/docs/magneticalc.QTableWidget2.html +++ b/docs/magneticalc.QTableWidget2.html @@ -46,7 +46,7 @@

    magneticalc.QTableWidget2 module document
    - +
    @@ -66,7 +66,7 @@

    magneticalc.QTableWidget2 module document
    - API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-02 09:06:24. + API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-03 23:22:21.
    diff --git a/docs/magneticalc.QTextBrowser2.QTextBrowser2.html b/docs/magneticalc.QTextBrowser2.QTextBrowser2.html index 5c66893..004316a 100644 --- a/docs/magneticalc.QTextBrowser2.QTextBrowser2.html +++ b/docs/magneticalc.QTextBrowser2.QTextBrowser2.html @@ -46,7 +46,7 @@

    magneticalc.QTextBrowser2.QTextBrowser2( -

    +
    @@ -109,7 +109,7 @@

    magneticalc.QTextBrowser2.QTextBrowser2(API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-02 09:06:24. + API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-03 23:22:21. diff --git a/docs/magneticalc.QTextBrowser2.html b/docs/magneticalc.QTextBrowser2.html index 7fde757..46a7de3 100644 --- a/docs/magneticalc.QTextBrowser2.html +++ b/docs/magneticalc.QTextBrowser2.html @@ -46,7 +46,7 @@

    magneticalc.QTextBrowser2 module document
    -

    +
    @@ -66,7 +66,7 @@

    magneticalc.QTextBrowser2 module document
    - API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-02 09:06:24. + API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-03 23:22:21.
    diff --git a/docs/magneticalc.SamplingVolume.SamplingVolume.html b/docs/magneticalc.SamplingVolume.SamplingVolume.html index c9c379b..6358f4c 100644 --- a/docs/magneticalc.SamplingVolume.SamplingVolume.html +++ b/docs/magneticalc.SamplingVolume.SamplingVolume.html @@ -46,7 +46,7 @@

    magneticalc.SamplingVolume.SamplingVolume
    -

    +
    @@ -523,7 +523,7 @@

    magneticalc.SamplingVolume.SamplingVolume
    -

    Returns this sampling volume's points.

    ReturnsOrdered list of 3D points
    +

    Returns this sampling volume's points.

    ReturnsArray of 3D points
    @@ -700,7 +700,7 @@

    magneticalc.SamplingVolume.SamplingVolume

    - API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-02 09:06:24. + API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-03 23:22:21.
    diff --git a/docs/magneticalc.SamplingVolume.html b/docs/magneticalc.SamplingVolume.html index 7849687..bc93135 100644 --- a/docs/magneticalc.SamplingVolume.html +++ b/docs/magneticalc.SamplingVolume.html @@ -46,7 +46,7 @@

    magneticalc.SamplingVolume module documen
    - +
    @@ -66,7 +66,7 @@

    magneticalc.SamplingVolume module documen
    - API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-02 09:06:24. + API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-03 23:22:21.
    diff --git a/docs/magneticalc.SamplingVolume_Widget.SamplingVolume_Widget.html b/docs/magneticalc.SamplingVolume_Widget.SamplingVolume_Widget.html index b7b284d..d33edec 100644 --- a/docs/magneticalc.SamplingVolume_Widget.SamplingVolume_Widget.html +++ b/docs/magneticalc.SamplingVolume_Widget.SamplingVolume_Widget.html @@ -46,7 +46,7 @@

    magneticalc.SamplingVolume_Widget.SamplingVolume_Widget(
    -

    +
    @@ -174,14 +174,9 @@

    magneticalc.SamplingVolume_Widget.SamplingVolume_Widget(

    Inherited from QLayouted (via QGroupBox2):

    -

    +
    - - - - - - + @@ -206,6 +201,11 @@

    magneticalc.SamplingVolume_Widget.SamplingVolume_Widget(

    + + + + +
    Instance VariablelayoutUndocumented
    Method install_layoutMethod addButtons Adds buttons.
    Instance Variable_layoutUndocumented
    @@ -636,7 +636,7 @@

    magneticalc.SamplingVolume_Widget.SamplingVolume_Widget(

    - API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-02 09:06:24. + API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-03 23:22:21.
    diff --git a/docs/magneticalc.SamplingVolume_Widget.html b/docs/magneticalc.SamplingVolume_Widget.html index c3b1399..0ebdc92 100644 --- a/docs/magneticalc.SamplingVolume_Widget.html +++ b/docs/magneticalc.SamplingVolume_Widget.html @@ -46,7 +46,7 @@

    magneticalc.SamplingVolume_Widget module
    - +
    @@ -66,7 +66,7 @@

    magneticalc.SamplingVolume_Widget module
    - API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-02 09:06:24. + API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-03 23:22:21.
    diff --git a/docs/magneticalc.SidebarLeft.SidebarLeft.html b/docs/magneticalc.SidebarLeft.SidebarLeft.html index ba1c044..d19a52f 100644 --- a/docs/magneticalc.SidebarLeft.SidebarLeft.html +++ b/docs/magneticalc.SidebarLeft.SidebarLeft.html @@ -46,7 +46,7 @@

    magneticalc.SidebarLeft.SidebarLeft( -

    +
    @@ -190,7 +190,7 @@

    magneticalc.SidebarLeft.SidebarLeft(API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-02 09:06:24. + API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-03 23:22:21. diff --git a/docs/magneticalc.SidebarLeft.html b/docs/magneticalc.SidebarLeft.html index fa6adb3..7d034ca 100644 --- a/docs/magneticalc.SidebarLeft.html +++ b/docs/magneticalc.SidebarLeft.html @@ -46,7 +46,7 @@

    magneticalc.SidebarLeft module documentat
    -

    +
    @@ -66,7 +66,7 @@

    magneticalc.SidebarLeft module documentat
    - API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-02 09:06:24. + API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-03 23:22:21.
    diff --git a/docs/magneticalc.SidebarRight.SidebarRight.html b/docs/magneticalc.SidebarRight.SidebarRight.html index adbcfcd..fe0b49f 100644 --- a/docs/magneticalc.SidebarRight.SidebarRight.html +++ b/docs/magneticalc.SidebarRight.SidebarRight.html @@ -46,7 +46,7 @@

    magneticalc.SidebarRight.SidebarRight( -

    +
    @@ -253,7 +253,7 @@

    magneticalc.SidebarRight.SidebarRight(API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-02 09:06:24. + API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-03 23:22:21. diff --git a/docs/magneticalc.SidebarRight.html b/docs/magneticalc.SidebarRight.html index 6a8edb9..0a2f4c8 100644 --- a/docs/magneticalc.SidebarRight.html +++ b/docs/magneticalc.SidebarRight.html @@ -46,7 +46,7 @@

    magneticalc.SidebarRight module documenta
    -

    +
    @@ -66,7 +66,7 @@

    magneticalc.SidebarRight module documenta
    - API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-02 09:06:24. + API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-03 23:22:21.
    diff --git a/docs/magneticalc.Statusbar.Statusbar.html b/docs/magneticalc.Statusbar.Statusbar.html index a9cd3b2..c19f0c9 100644 --- a/docs/magneticalc.Statusbar.Statusbar.html +++ b/docs/magneticalc.Statusbar.Statusbar.html @@ -46,7 +46,7 @@

    magneticalc.Statusbar.Statusbar class docu
    -

    +
    @@ -58,36 +58,6 @@

    magneticalc.Statusbar.Statusbar class docu

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -116,13 +86,48 @@

    magneticalc.Statusbar.Statusbar class docu

    - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -172,96 +177,96 @@

    magneticalc.Statusbar.Statusbar class docu
    Undocumented
    -
    +
    - + - +
    - start_button = + _start_button =
    Undocumented
    -
    +
    - + - +
    - cancel_button = + _cancel_button =
    Undocumented
    -
    +
    - + - +
    - auto_calculation_checkbox = + _auto_calculation_checkbox =
    Undocumented
    -
    +
    - + - +
    - cores_combobox = + _cores_combobox =
    Undocumented
    -
    +
    - + - +
    - progressbar = + _progressbar =
    Undocumented
    -
    +
    - + - +
    - label = + _label =
    @@ -384,16 +389,16 @@

    magneticalc.Statusbar.Statusbar class docu

    - + - +
    def - text(self, text): + set_text(self, text):
    @@ -403,6 +408,25 @@

    magneticalc.Statusbar.Statusbar class docu

    + + + + + + +
    + + def + set_progress(self, percentage): + +
    +
    + + +

    Updates the progress percentage.

    Instance Variable gui Undocumented
    Instance Variablestart_buttonUndocumented
    Instance Variablecancel_buttonUndocumented
    Instance Variableauto_calculation_checkboxUndocumented
    Instance Variablecores_comboboxUndocumented
    Instance VariableprogressbarUndocumented
    Instance VariablelabelUndocumented
    Method
    Methodtextset_text Updates the statusbar text.
    Methodset_progressUpdates the progress percentage.
    Method set_progressbar_color Sets the progressbar color & style.
    Instance Variable_start_buttonUndocumented
    Instance Variable_cancel_buttonUndocumented
    Instance Variable_auto_calculation_checkboxUndocumented
    Instance Variable_cores_comboboxUndocumented
    Instance Variable_progressbarUndocumented
    Instance Variable_labelUndocumented
    Method
    ParameterspercentagePercentage
    + +
    + @@ -424,7 +448,7 @@

    magneticalc.Statusbar.Statusbar class docu

    - API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-02 09:06:24. + API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-03 23:22:21.
    diff --git a/docs/magneticalc.Statusbar.html b/docs/magneticalc.Statusbar.html index 6258884..32bb3fb 100644 --- a/docs/magneticalc.Statusbar.html +++ b/docs/magneticalc.Statusbar.html @@ -46,7 +46,7 @@

    magneticalc.Statusbar module documentatio
    - +
    @@ -66,7 +66,7 @@

    magneticalc.Statusbar module documentatio
    - API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-02 09:06:24. + API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-03 23:22:21.
    diff --git a/docs/magneticalc.Theme.Theme.html b/docs/magneticalc.Theme.Theme.html index 3a670f0..9bd77bc 100644 --- a/docs/magneticalc.Theme.Theme.html +++ b/docs/magneticalc.Theme.Theme.html @@ -46,17 +46,22 @@

    magneticalc.Theme.Theme class documentatio
    -

    +
    - + - + + + + + + @@ -66,13 +71,13 @@

    magneticalc.Theme.Theme class documentatio

    - + - + - - - + + +
    Class VariablePrimaryColorMainColor Undocumented
    Class VariableLightColorLiteColorUndocumented
    Class VariableDarkColor Undocumented
    Class VariableWarningColorFailureColor Undocumented
    Static Methodget_iconGets a PyQt5 standard icon by name.Class VariableDefaultFontFaceUndocumented
    @@ -84,14 +89,30 @@

    magneticalc.Theme.Theme class documentatio
    - + + + + + + +
    + MainColor = + +
    +
    + +
    Undocumented
    (type: str) +
    +
    + + - +
    - PrimaryColor = + LiteColor =
    @@ -100,14 +121,14 @@

    magneticalc.Theme.Theme class documentatio

    - + - +
    - LightColor = + DarkColor =
    @@ -132,44 +153,41 @@

    magneticalc.Theme.Theme class documentatio

    - + - +
    - WarningColor = + FailureColor =
    Undocumented
    (type: str)
    -
    +
    - + - +
    - @staticmethod
    - def - get_icon(widget, name): + DefaultFontFace =
    -
    - +
    -

    Gets a PyQt5 standard icon by name.

    ParameterswidgetBase QWidget
    nameName
    ReturnsPyQt5 icon
    +
    Undocumented
    (type: str)
    - API Documentation for MagnetiCalc, generated by pydoctor at 2021-12-30 03:01:53. + API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-03 23:22:21.

    diff --git a/docs/magneticalc.Theme.html b/docs/magneticalc.Theme.html index 21bed6f..74c1daa 100644 --- a/docs/magneticalc.Theme.html +++ b/docs/magneticalc.Theme.html @@ -46,7 +46,7 @@

    magneticalc.Theme module documentation
    - +
    @@ -66,7 +66,7 @@

    magneticalc.Theme module documentation
    - API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-02 09:06:24. + API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-03 23:22:21.
    diff --git a/docs/magneticalc.Usage_Dialog.Usage_Dialog.html b/docs/magneticalc.Usage_Dialog.Usage_Dialog.html index 41f9d65..db15189 100644 --- a/docs/magneticalc.Usage_Dialog.Usage_Dialog.html +++ b/docs/magneticalc.Usage_Dialog.Usage_Dialog.html @@ -46,7 +46,7 @@

    magneticalc.Usage_Dialog.Usage_Dialog( -

    +
    @@ -64,7 +64,7 @@

    magneticalc.Usage_Dialog.Usage_Dialog( Inherited from QDialog2:

    -

    +
    @@ -92,14 +92,9 @@

    magneticalc.Usage_Dialog.Usage_Dialog( Inherited from QLayouted (via QDialog2):

    -

    +
    - - - - - - + @@ -124,6 +119,11 @@

    magneticalc.Usage_Dialog.Usage_Dialog(addButtons

    + + + + +
    Instance VariablelayoutUndocumented
    Method install_layoutAdds buttons.
    Instance Variable_layoutUndocumented
    @@ -172,7 +172,7 @@

    magneticalc.Usage_Dialog.Usage_Dialog(API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-02 09:06:24. + API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-03 23:22:21.

    diff --git a/docs/magneticalc.Usage_Dialog.html b/docs/magneticalc.Usage_Dialog.html index 9fd9ac0..f4d7670 100644 --- a/docs/magneticalc.Usage_Dialog.html +++ b/docs/magneticalc.Usage_Dialog.html @@ -46,7 +46,7 @@

    magneticalc.Usage_Dialog module documenta
    - +
    @@ -66,7 +66,7 @@

    magneticalc.Usage_Dialog module documenta
    - API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-02 09:06:24. + API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-03 23:22:21.
    diff --git a/docs/magneticalc.Version.Version.html b/docs/magneticalc.Version.Version.html index f375db0..5eafdf0 100644 --- a/docs/magneticalc.Version.Version.html +++ b/docs/magneticalc.Version.Version.html @@ -46,7 +46,7 @@

    magneticalc.Version.Version class document
    -

    +
    @@ -124,7 +124,7 @@

    magneticalc.Version.Version class document
    - API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-02 09:06:24. + API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-03 23:22:21.
    diff --git a/docs/magneticalc.Version.html b/docs/magneticalc.Version.html index 6b8bbd3..f840bb0 100644 --- a/docs/magneticalc.Version.html +++ b/docs/magneticalc.Version.html @@ -46,7 +46,7 @@

    magneticalc.Version module documentation<
    -

    +
    @@ -129,7 +129,7 @@

    magneticalc.Version module documentation<
    - API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-02 09:06:24. + API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-03 23:22:21.
    diff --git a/docs/magneticalc.VispyCanvas.VispyCanvas.html b/docs/magneticalc.VispyCanvas.VispyCanvas.html index e9874d4..fc9bbac 100644 --- a/docs/magneticalc.VispyCanvas.VispyCanvas.html +++ b/docs/magneticalc.VispyCanvas.VispyCanvas.html @@ -46,15 +46,10 @@

    magneticalc.VispyCanvas.VispyCanvas( -

    +
    - - - - - @@ -319,22 +314,6 @@

    magneticalc.VispyCanvas.VispyCanvas( - - - - - - -
    - DefaultFontFace = - -
    -
    - -
    Undocumented
    (type: str) -
    -
    - @@ -1201,7 +1180,7 @@

    magneticalc.VispyCanvas.VispyCanvas(API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-02 09:06:24. + API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-03 23:22:21.

    diff --git a/docs/magneticalc.VispyCanvas.html b/docs/magneticalc.VispyCanvas.html index 7af82d4..99765a8 100644 --- a/docs/magneticalc.VispyCanvas.html +++ b/docs/magneticalc.VispyCanvas.html @@ -46,7 +46,7 @@

    magneticalc.VispyCanvas module documentat
    -

    Class VariableDefaultFontFaceUndocumented
    Class Variable DefaultFontSize Undocumented
    +
    @@ -66,7 +66,7 @@

    magneticalc.VispyCanvas module documentat
    - API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-02 09:06:24. + API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-03 23:22:21.
    diff --git a/docs/magneticalc.Wire.Wire.html b/docs/magneticalc.Wire.Wire.html index 7f83631..571f45b 100644 --- a/docs/magneticalc.Wire.Wire.html +++ b/docs/magneticalc.Wire.Wire.html @@ -46,7 +46,7 @@

    magneticalc.Wire.Wire class documentation<
    -

    +
    @@ -499,7 +499,7 @@

    magneticalc.Wire.Wire class documentation<
    - API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-02 09:06:24. + API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-03 23:22:21.
    diff --git a/docs/magneticalc.Wire.html b/docs/magneticalc.Wire.html index 675bd12..f936f4b 100644 --- a/docs/magneticalc.Wire.html +++ b/docs/magneticalc.Wire.html @@ -46,7 +46,7 @@

    magneticalc.Wire module documentation
    -

    +
    @@ -66,7 +66,7 @@

    magneticalc.Wire module documentation
    - API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-02 09:06:24. + API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-03 23:22:21.
    diff --git a/docs/magneticalc.Wire_Presets.Wire_Presets.html b/docs/magneticalc.Wire_Presets.Wire_Presets.html index afd499b..a0df0b2 100644 --- a/docs/magneticalc.Wire_Presets.Wire_Presets.html +++ b/docs/magneticalc.Wire_Presets.Wire_Presets.html @@ -46,7 +46,7 @@

    magneticalc.Wire_Presets.Wire_Presets clas
    -

    +
    @@ -323,7 +323,7 @@

    magneticalc.Wire_Presets.Wire_Presets clas
    @staticmethod
    def - get_phase_jumping_toroidal_loop(n_points=1000, n_phase_jumps=32, toroidal_radius=1, poloidal_radius=0.5, toroidal_freq=1, poloidal_freq=32): + get_phase_jumping_toroidal_loop(n_points, n_phase_jumps, toroidal_radius, poloidal_radius, toroidal_freq, poloidal_freq):
    @@ -466,7 +466,7 @@

    magneticalc.Wire_Presets.Wire_Presets clas

    - API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-02 09:06:24. + API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-03 23:22:21.
    diff --git a/docs/magneticalc.Wire_Presets.html b/docs/magneticalc.Wire_Presets.html index 625d5dc..f4fc995 100644 --- a/docs/magneticalc.Wire_Presets.html +++ b/docs/magneticalc.Wire_Presets.html @@ -46,7 +46,7 @@

    magneticalc.Wire_Presets module documenta
    -

    +
    @@ -66,7 +66,7 @@

    magneticalc.Wire_Presets module documenta
    - API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-02 09:06:24. + API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-03 23:22:21.
    diff --git a/docs/magneticalc.Wire_Widget.Wire_Widget.html b/docs/magneticalc.Wire_Widget.Wire_Widget.html index d87828e..a9d320e 100644 --- a/docs/magneticalc.Wire_Widget.Wire_Widget.html +++ b/docs/magneticalc.Wire_Widget.Wire_Widget.html @@ -46,7 +46,7 @@

    magneticalc.Wire_Widget.Wire_Widget( -

    +
    @@ -304,14 +304,9 @@

    magneticalc.Wire_Widget.Wire_Widget( Inherited from QLayouted (via QGroupBox2):

    -

    +
    - - - - - - + @@ -336,6 +331,11 @@

    magneticalc.Wire_Widget.Wire_Widget(addButtons

    + + + + +
    Instance VariablelayoutUndocumented
    Method install_layoutAdds buttons.
    Instance Variable_layoutUndocumented
    @@ -1147,7 +1147,7 @@

    magneticalc.Wire_Widget.Wire_Widget( -

    Gets called after a table cell has been edited.

    ParametersvalueCell value
    rowRow
    columnColumn
    +

    Gets called after a table cell has been edited.

    ParametersvalueCell value
    rowRow index
    columnColumn index

    @@ -1191,7 +1191,7 @@

    magneticalc.Wire_Widget.Wire_Widget(API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-02 09:06:24. + API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-03 23:22:21.

    diff --git a/docs/magneticalc.Wire_Widget.html b/docs/magneticalc.Wire_Widget.html index ebcc3da..e189353 100644 --- a/docs/magneticalc.Wire_Widget.html +++ b/docs/magneticalc.Wire_Widget.html @@ -46,7 +46,7 @@

    magneticalc.Wire_Widget module documentat
    - +
    @@ -66,7 +66,7 @@

    magneticalc.Wire_Widget module documentat
    - API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-02 09:06:24. + API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-03 23:22:21.
    diff --git a/docs/magneticalc.__init__.html b/docs/magneticalc.__init__.html index 3427115..3745c5c 100644 --- a/docs/magneticalc.__init__.html +++ b/docs/magneticalc.__init__.html @@ -58,7 +58,7 @@

    magneticalc.__init__ module documentation
    - API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-02 09:06:24. + API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-03 23:22:21.
    diff --git a/docs/magneticalc.__main__.html b/docs/magneticalc.__main__.html index 52a44c0..01783bf 100644 --- a/docs/magneticalc.__main__.html +++ b/docs/magneticalc.__main__.html @@ -46,7 +46,7 @@

    magneticalc.__main__ module documentation
    -

    +
    @@ -85,7 +85,7 @@

    magneticalc.__main__ module documentation
    - API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-02 09:06:24. + API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-03 23:22:21.
    diff --git a/docs/magneticalc.html b/docs/magneticalc.html index 3a6a4b6..ca6d6d3 100644 --- a/docs/magneticalc.html +++ b/docs/magneticalc.html @@ -90,11 +90,26 @@

    magneticalc package documentationCheckForUpdates_Dialog module.

    + + + + + + + + + + + + + + + @@ -180,6 +195,11 @@

    magneticalc package documentationModel access module.

    + + + + + @@ -351,7 +371,7 @@

    magneticalc package documentation
    - API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-02 09:06:24. + API Documentation for MagnetiCalc, generated by pydoctor at 2022-01-03 23:22:21.
    diff --git a/docs/moduleIndex.html b/docs/moduleIndex.html index 1b94bba..742b852 100644 --- a/docs/moduleIndex.html +++ b/docs/moduleIndex.html @@ -26,7 +26,7 @@

    Module Index

    - + diff --git a/docs/nameIndex.html b/docs/nameIndex.html index 51bea7a..a278065 100644 --- a/docs/nameIndex.html +++ b/docs/nameIndex.html @@ -36,7 +36,7 @@

    Index Of Names

    A

    @@ -45,7 +45,7 @@

    A

    B

    @@ -54,7 +54,7 @@

    B

    C

    @@ -63,7 +63,7 @@

    C

    D

    @@ -72,7 +72,7 @@

    D

    E

    @@ -81,7 +81,7 @@

    E

    F

    @@ -90,7 +90,7 @@

    F

    G

    @@ -99,7 +99,7 @@

    G

    H

    @@ -108,7 +108,7 @@

    H

    I

    @@ -126,7 +126,7 @@

    K

    L

    @@ -135,7 +135,7 @@

    L

    M

    @@ -144,7 +144,7 @@

    M

    N

    @@ -153,7 +153,7 @@

    N

    O

    @@ -162,7 +162,7 @@

    O

    P

    @@ -171,7 +171,7 @@

    P

    Q

    @@ -180,7 +180,7 @@

    Q

    R

    @@ -189,7 +189,7 @@

    R

    S

    @@ -198,7 +198,7 @@

    S

    T

    @@ -216,7 +216,7 @@

    U

    V

    @@ -225,7 +225,7 @@

    V

    W

    @@ -234,7 +234,7 @@

    W

    _

    diff --git a/docs/objects.inv b/docs/objects.inv index cead0cc..9afe360 100644 Binary files a/docs/objects.inv and b/docs/objects.inv differ diff --git a/docs/undoccedSummary.html b/docs/undoccedSummary.html index f580265..20b849e 100644 --- a/docs/undoccedSummary.html +++ b/docs/undoccedSummary.html @@ -27,7 +27,7 @@

    Summary of Undocumented Objects

    +
  • Class Variable - magneticalc.About_Dialog.About_Dialog.DonationURL
  • Class Variable - magneticalc.About_Dialog.About_Dialog.HTML
  • Instance Variable - magneticalc.Assert_Dialog.Assert_Dialog._dialog
  • Instance Variable - magneticalc.Backend_CUDA.Backend_CUDA._current_elements
  • Instance Variable - magneticalc.Backend_CUDA.Backend_CUDA._dc
  • Instance Variable - magneticalc.Backend_CUDA.Backend_CUDA._distance_limit
  • Instance Variable - magneticalc.Backend_CUDA.Backend_CUDA._field_type
  • Instance Variable - magneticalc.Backend_CUDA.Backend_CUDA._length_scale
  • Instance Variable - magneticalc.Backend_CUDA.Backend_CUDA._progress_callback
  • Instance Variable - magneticalc.Backend_CUDA.Backend_CUDA._sampling_volume_permeabilities
  • Instance Variable - magneticalc.Backend_CUDA.Backend_CUDA._sampling_volume_points
  • Instance Variable - magneticalc.Backend_JIT.Backend_JIT._current_elements
  • Instance Variable - magneticalc.Backend_JIT.Backend_JIT._dc
  • Instance Variable - magneticalc.Backend_JIT.Backend_JIT._distance_limit
  • Instance Variable - magneticalc.Backend_JIT.Backend_JIT._field_type
  • Instance Variable - magneticalc.Backend_JIT.Backend_JIT._length_scale
  • Instance Variable - magneticalc.Backend_JIT.Backend_JIT._progress_callback
  • Instance Variable - magneticalc.Backend_JIT.Backend_JIT._sampling_volume_permeabilities
  • Instance Variable - magneticalc.Backend_JIT.Backend_JIT._sampling_volume_points
  • Variable - magneticalc.Backend_Types.BACKEND_CUDA
  • Variable - magneticalc.Backend_Types.BACKEND_JIT
  • Class Variable - magneticalc.CalculationThread.CalculationThread._field_valid
  • Class Variable - magneticalc.CalculationThread.CalculationThread._metric_valid
  • Class Variable - magneticalc.CalculationThread.CalculationThread._parameters_valid
  • Class Variable - magneticalc.CalculationThread.CalculationThread._progress_update
  • Class Variable - magneticalc.CalculationThread.CalculationThread._sampling_volume_valid
  • Class Variable - magneticalc.CalculationThread.CalculationThread._wire_valid
  • Instance Variable - magneticalc.CalculationThread.CalculationThread.gui
  • Instance Variable - magneticalc.CalculationThread.CalculationThread.progress_callback
  • Variable - magneticalc.Comparison_Types.COMPARISON_TYPE_IN_RANGE
  • Variable - magneticalc.Comparison_Types.Comparison_Types_Str_Map
  • Instance Variable - magneticalc.ConditionalDecorator.ConditionalDecorator.condition
  • Instance Variable - magneticalc.ConditionalDecorator.ConditionalDecorator.decorating_args
  • Instance Variable - magneticalc.ConditionalDecorator.ConditionalDecorator.decorating_func
  • Class Variable - magneticalc.Config.Config.CoordinatePrecision
  • Class Variable - magneticalc.Config.Config.Default
  • Class Variable - magneticalc.Config.Config.DefaultPerspectivePreset
  • Class Variable - magneticalc.Config.Config.DefaultWirePreset
  • Class Variable - magneticalc.Config.Config.FloatPrecision
  • Instance Variable - magneticalc.Config.Config._changed_callback
  • Instance Variable - magneticalc.Config.Config._config
  • Instance Variable - magneticalc.Config.Config._filename
  • Instance Variable - magneticalc.Config.Config._synced
  • Instance Variable - magneticalc.Config_Group.Config_Collection.first_without_suffix
  • Instance Variable - magneticalc.Config_Group.Config_Collection.gui
  • Instance Variable - magneticalc.Config_Group.Config_Collection.prefix
  • Instance Variable - magneticalc.Config_Group.Config_Collection.types
  • Class Variable - magneticalc.Constants.Constants.mu_0
  • Class Variable - magneticalc.Constraint.Constraint.Comparison_Types_List
  • Class Variable - magneticalc.Constraint.Constraint.Comparison_Types_List_Str
  • Class Variable - magneticalc.Constraint.Constraint.Norm_Types_Degrees_List
  • Class Variable - magneticalc.Constraint.Constraint.Norm_Types_List
  • Class Variable - magneticalc.Constraint.Constraint.Norm_Types_List_Str
  • Instance Variable - magneticalc.Constraint.Constraint._comparison_type
  • Instance Variable - magneticalc.Constraint.Constraint._is_angle
  • Instance Variable - magneticalc.Constraint.Constraint._max
  • Instance Variable - magneticalc.Constraint.Constraint._min
  • Instance Variable - magneticalc.Constraint.Constraint._norm_type
  • Instance Variable - magneticalc.Constraint.Constraint.permeability
  • Class Variable - magneticalc.Constraint_Editor.Constraint_Editor.Constraint_Options
  • Class Variable - magneticalc.Constraint_Editor.Constraint_Editor.Constraint_Types
  • Instance Variable - magneticalc.Constraint_Editor.Constraint_Editor._changed
  • Instance Variable - magneticalc.Constraint_Editor.Constraint_Editor._constraint_collection
  • Instance Variable - magneticalc.Constraint_Editor.Constraint_Editor.gui
  • Instance Variable - magneticalc.Constraint_Editor.Constraint_Editor.table
  • Class Variable - magneticalc.Debug.Debug.Blacklist
  • Class Variable - magneticalc.Display_Widget.Display_Widget.ExcessiveFieldLabelThreshold
  • Class Variable - magneticalc.Display_Widget.Display_Widget.FieldArrowHeadScaleMaximum
  • Class Variable - magneticalc.Display_Widget.Display_Widget.FieldArrowHeadScaleMinimum
  • Class Variable - magneticalc.Display_Widget.Display_Widget.FieldArrowHeadScaleStep
  • Class Variable - magneticalc.Display_Widget.Display_Widget.FieldArrowLineScaleMaximum
  • Class Variable - magneticalc.Display_Widget.Display_Widget.FieldArrowLineScaleMinimum
  • Class Variable - magneticalc.Display_Widget.Display_Widget.FieldArrowLineScaleStep
  • Class Variable - magneticalc.Display_Widget.Display_Widget.FieldBoostMaximum
  • Class Variable - magneticalc.Display_Widget.Display_Widget.FieldBoostMinimum
  • Class Variable - magneticalc.Display_Widget.Display_Widget.FieldBoostStep
  • Class Variable - magneticalc.Display_Widget.Display_Widget.FieldPointScaleMaximum
  • Class Variable - magneticalc.Display_Widget.Display_Widget.FieldPointScaleMinimum
  • Class Variable - magneticalc.Display_Widget.Display_Widget.FieldPointScaleStep
  • Instance Variable - magneticalc.Display_Widget.Display_Widget.display_field_magnitude_labels_checkbox
  • Instance Variable - magneticalc.Display_Widget.Display_Widget.field_arrow_head_scale_slider
  • Instance Variable - magneticalc.Display_Widget.Display_Widget.field_arrow_line_scale_slider
  • Instance Variable - magneticalc.Display_Widget.Display_Widget.field_boost_slider
  • Instance Variable - magneticalc.Display_Widget.Display_Widget.field_label_resolution_combobox
  • Instance Variable - magneticalc.Display_Widget.Display_Widget.field_label_resolution_combobox_connection
  • Instance Variable - magneticalc.Display_Widget.Display_Widget.field_point_scale_slider
  • Instance Variable - magneticalc.Display_Widget.Display_Widget.gui
  • Instance Variable - magneticalc.Display_Widget.Display_Widget.total_labels_label
  • Instance Variable - magneticalc.ExportContainer_Dialog.ExportContainer_Dialog.a_field_checkbox
  • Instance Variable - magneticalc.ExportContainer_Dialog.ExportContainer_Dialog.b_field_checkbox
  • Instance Variable - magneticalc.ExportContainer_Dialog.ExportContainer_Dialog.gui
  • Instance Variable - magneticalc.ExportContainer_Dialog.ExportContainer_Dialog.wire_current_checkbox
  • Instance Variable - magneticalc.ExportContainer_Dialog.ExportContainer_Dialog.wire_points_checkbox
  • Instance Variable - magneticalc.Field.Field._backend_type
  • Instance Variable - magneticalc.Field.Field._distance_limit
  • Instance Variable - magneticalc.Field.Field._field_type
  • Instance Variable - magneticalc.Field.Field._length_scale
  • Instance Variable - magneticalc.Field.Field._total_calculations
  • Instance Variable - magneticalc.Field.Field._total_skipped_calculations
  • Instance Variable - magneticalc.Field.Field._vectors
  • Variable - magneticalc.Field_Types.A_FIELD
  • Variable - magneticalc.Field_Types.B_FIELD
  • Variable - magneticalc.Field_Types.Field_Types_Str_Map
  • Class Variable - magneticalc.Field_Widget.Field_Widget.DistanceLimitMaximum
  • Class Variable - magneticalc.Field_Widget.Field_Widget.DistanceLimitMinimum
  • Class Variable - magneticalc.Field_Widget.Field_Widget.DistanceLimitPrecision
  • Class Variable - magneticalc.Field_Widget.Field_Widget.DistanceLimitStep
  • Instance Variable - magneticalc.Field_Widget.Field_Widget.distance_limit_spinbox
  • Instance Variable - magneticalc.Field_Widget.Field_Widget.field_type_a_checkbox
  • Instance Variable - magneticalc.Field_Widget.Field_Widget.field_type_b_checkbox
  • Instance Variable - magneticalc.Field_Widget.Field_Widget.field_type_group
  • Instance Variable - magneticalc.Field_Widget.Field_Widget.gui
  • Instance Variable - magneticalc.Field_Widget.Field_Widget.total_calculations_label
  • Instance Variable - magneticalc.Field_Widget.Field_Widget.total_skipped_calculations_label
  • Class Variable - magneticalc.GUI.GUI.DefaultFilename
  • Class Variable - magneticalc.GUI.GUI.MinimumWindowSize
  • Class Variable - magneticalc.GUI.GUI.calculation_exited
  • Instance Variable - magneticalc.GUI.GUI.calculation_start_time
  • Class Variable - magneticalc.GUI.GUI.calculation_status
  • Instance Variable - magneticalc.GUI.GUI.calculation_thread
  • Instance Variable - magneticalc.GUI.GUI.config
  • Instance Variable - magneticalc.GUI.GUI.initializing
  • Instance Variable - magneticalc.GUI.GUI.locale
  • Instance Variable - magneticalc.GUI.GUI.menu
  • Instance Variable - magneticalc.GUI.GUI.model
  • Instance Variable - magneticalc.GUI.GUI.sidebar_left
  • Instance Variable - magneticalc.GUI.GUI.sidebar_right
  • Instance Variable - magneticalc.GUI.GUI.splitter
  • Instance Variable - magneticalc.GUI.GUI.statusbar
  • Instance Variable - magneticalc.GUI.GUI.vispy_canvas
  • Method - magneticalc.MagnetiCalc_Data.MagnetiCalc_Data.__delitem__
  • Method - magneticalc.MagnetiCalc_Data.MagnetiCalc_Data.__getitem__
  • Method - magneticalc.MagnetiCalc_Data.MagnetiCalc_Data.__iter__
  • Method - magneticalc.MagnetiCalc_Data.MagnetiCalc_Data.__len__
  • Method - magneticalc.MagnetiCalc_Data.MagnetiCalc_Data.__setitem__
  • Method - magneticalc.MagnetiCalc_Data.MagnetiCalc_Data._keytransform
  • Instance Variable - magneticalc.MagnetiCalc_Data.MagnetiCalc_Data.data
  • Class Variable - magneticalc.Menu.Menu.Backends_Available_List
  • Instance Variable - magneticalc.Menu.Menu.backend_actions
  • Instance Variable - magneticalc.Menu.Menu.config_bound_checkboxes
  • Instance Variable - magneticalc.Menu.Menu.export_wire_action
  • Instance Variable - magneticalc.Menu.Menu.gui
  • Instance Variable - magneticalc.Menu.Menu.import_wire_action
  • Instance Variable - magneticalc.Menu.Menu.options_backend_group
  • Class Variable - magneticalc.Metric.Metric.LengthScale
  • Class Variable - magneticalc.Metric.Metric.LogNormMinimum
  • Instance Variable - magneticalc.Metric.Metric._alpha_preset
  • Instance Variable - magneticalc.Metric.Metric._color_preset
  • Instance Variable - magneticalc.Metric.Metric._colors
  • Instance Variable - magneticalc.Metric.Metric._limits
  • Class Variable - magneticalc.Metric_Presets.Metric_Presets.AngleXY
  • Class Variable - magneticalc.Metric_Presets.Metric_Presets.AngleXZ
  • Class Variable - magneticalc.Metric_Presets.Metric_Presets.AngleYZ
  • Class Variable - magneticalc.Metric_Presets.Metric_Presets.Divergence
  • Class Variable - magneticalc.Metric_Presets.Metric_Presets.List
  • Class Variable - magneticalc.Metric_Presets.Metric_Presets.LogDivergence
  • Class Variable - magneticalc.Metric_Presets.Metric_Presets.LogMagnitude
  • Class Variable - magneticalc.Metric_Presets.Metric_Presets.LogMagnitudeX
  • Class Variable - magneticalc.Metric_Presets.Metric_Presets.LogMagnitudeXY
  • Class Variable - magneticalc.Metric_Presets.Metric_Presets.LogMagnitudeXZ
  • Class Variable - magneticalc.Metric_Presets.Metric_Presets.LogMagnitudeY
  • Class Variable - magneticalc.Metric_Presets.Metric_Presets.LogMagnitudeYZ
  • Class Variable - magneticalc.Metric_Presets.Metric_Presets.LogMagnitudeZ
  • Class Variable - magneticalc.Metric_Presets.Metric_Presets.Magnitude
  • Class Variable - magneticalc.Metric_Presets.Metric_Presets.MagnitudeX
  • Class Variable - magneticalc.Metric_Presets.Metric_Presets.MagnitudeXY
  • Class Variable - magneticalc.Metric_Presets.Metric_Presets.MagnitudeXZ
  • Class Variable - magneticalc.Metric_Presets.Metric_Presets.MagnitudeY
  • Class Variable - magneticalc.Metric_Presets.Metric_Presets.MagnitudeYZ
  • Class Variable - magneticalc.Metric_Presets.Metric_Presets.MagnitudeZ
  • Class Variable - magneticalc.Metric_Presets.Metric_Presets.NegDivergence
  • Class Variable - magneticalc.Metric_Presets.Metric_Presets.NegLogDivergence
  • Class Variable - magneticalc.Metric_Presets.Metric_Presets.PosDivergence
  • Class Variable - magneticalc.Metric_Presets.Metric_Presets.PosLogDivergence
  • Class Variable - magneticalc.Metric_Widget.Metric_Widget.Cool_Gradient_CSS
  • Class Variable - magneticalc.Metric_Widget.Metric_Widget.HSV_Gradient_CSS
  • Class Variable - magneticalc.Metric_Widget.Metric_Widget.ValuePrecision
  • Instance Variable - magneticalc.Metric_Widget.Metric_Widget.alpha_metric_combobox
  • Instance Variable - magneticalc.Metric_Widget.Metric_Widget.alpha_metric_limits_layout
  • Instance Variable - magneticalc.Metric_Widget.Metric_Widget.alpha_metric_limits_widget
  • Instance Variable - magneticalc.Metric_Widget.Metric_Widget.alpha_metric_max_label
  • Instance Variable - magneticalc.Metric_Widget.Metric_Widget.alpha_metric_min_label
  • Instance Variable - magneticalc.Metric_Widget.Metric_Widget.color_metric_combobox
  • Instance Variable - magneticalc.Metric_Widget.Metric_Widget.color_metric_limits_layout
  • Instance Variable - magneticalc.Metric_Widget.Metric_Widget.color_metric_limits_widget
  • Instance Variable - magneticalc.Metric_Widget.Metric_Widget.color_metric_max_label
  • Instance Variable - magneticalc.Metric_Widget.Metric_Widget.color_metric_min_label
  • Instance Variable - magneticalc.Metric_Widget.Metric_Widget.gui
  • Instance Variable - magneticalc.Model.Model._field_cache
  • Instance Variable - magneticalc.Model.Model._selected_field_type
  • Instance Variable - magneticalc.Model.Model.gui
  • Instance Variable - magneticalc.Model.Model.metric
  • Instance Variable - magneticalc.Model.Model.parameters
  • Instance Variable - magneticalc.Model.Model.sampling_volume
  • Instance Variable - magneticalc.Model.Model.wire
  • Instance Variable - magneticalc.ModelAccess.ModelAccess._recalculate
  • Instance Variable - magneticalc.ModelAccess.ModelAccess.gui
  • Variable - magneticalc.Norm_Types.NORM_TYPE_ANGLE_XY
  • Variable - magneticalc.Norm_Types.NORM_TYPE_ANGLE_XZ
  • Variable - magneticalc.Norm_Types.NORM_TYPE_ANGLE_YZ
  • Variable - magneticalc.Norm_Types.NORM_TYPE_DIVERGENCE
  • Variable - magneticalc.Norm_Types.NORM_TYPE_RADIUS
  • Variable - magneticalc.Norm_Types.NORM_TYPE_RADIUS_X
  • Variable - magneticalc.Norm_Types.NORM_TYPE_RADIUS_XY
  • Variable - magneticalc.Norm_Types.NORM_TYPE_RADIUS_XZ
  • Variable - magneticalc.Norm_Types.NORM_TYPE_RADIUS_Y
  • Variable - magneticalc.Norm_Types.NORM_TYPE_RADIUS_YZ
  • Variable - magneticalc.Norm_Types.NORM_TYPE_RADIUS_Z
  • Variable - magneticalc.Norm_Types.NORM_TYPE_X
  • Variable - magneticalc.Norm_Types.NORM_TYPE_Y
  • Variable - magneticalc.Norm_Types.NORM_TYPE_Z
  • Variable - magneticalc.Norm_Types.Norm_Types_Str_Map
  • Class Variable - magneticalc.OverridePadding_Dialog.OverridePadding_Dialog.BoundsRange
  • Instance Variable - magneticalc.OverridePadding_Dialog.OverridePadding_Dialog.bounds_max_spinbox
  • Instance Variable - magneticalc.OverridePadding_Dialog.OverridePadding_Dialog.bounds_min_spinbox
  • Instance Variable - magneticalc.OverridePadding_Dialog.OverridePadding_Dialog.buttons
  • Instance Variable - magneticalc.OverridePadding_Dialog.OverridePadding_Dialog.gui
  • Instance Variable - magneticalc.Parameters.Parameters._energy
  • Instance Variable - magneticalc.Parameters.Parameters._magnetic_dipole_moment
  • Instance Variable - magneticalc.Parameters.Parameters._self_inductance
  • Class Variable - magneticalc.Parameters_Widget.Parameters_Widget.ValuePrecision
  • Instance Variable - magneticalc.Parameters_Widget.Parameters_Widget.energy_units_label
  • Instance Variable - magneticalc.Parameters_Widget.Parameters_Widget.energy_value_label
  • Instance Variable - magneticalc.Parameters_Widget.Parameters_Widget.gui
  • Instance Variable - magneticalc.Parameters_Widget.Parameters_Widget.magnetic_dipole_moment_units_label
  • Instance Variable - magneticalc.Parameters_Widget.Parameters_Widget.magnetic_dipole_moment_value_label
  • Instance Variable - magneticalc.Parameters_Widget.Parameters_Widget.self_inductance_units_label
  • Instance Variable - magneticalc.Parameters_Widget.Parameters_Widget.self_inductance_value_label
  • Instance Variable - magneticalc.Parameters_Widget.Parameters_Widget.wire_length_units_label
  • Instance Variable - magneticalc.Parameters_Widget.Parameters_Widget.wire_length_value_label
  • Class Variable - magneticalc.Perspective_Presets.Perspective_Presets.Isometric
  • Class Variable - magneticalc.Perspective_Presets.Perspective_Presets.List
  • Class Variable - magneticalc.Perspective_Presets.Perspective_Presets.PlaneXY
  • Class Variable - magneticalc.Perspective_Presets.Perspective_Presets.PlaneXZ
  • Class Variable - magneticalc.Perspective_Presets.Perspective_Presets.PlaneYZ
  • Instance Variable - magneticalc.Perspective_Widget.Perspective_Widget.gui
  • Instance Variable - magneticalc.QButtons.QButtons.dictionary
  • Class Variable - magneticalc.QDialog2.QDialog2.dialog_shown
  • Instance Variable - magneticalc.QDialog2.QDialog2.success
  • Class Variable - magneticalc.QHLine.QHLine.VerticalSpacing
  • Class Variable - magneticalc.QIconLabel.QIconLabel.HorizontalSpacing
  • Instance Variable - magneticalc.QLayouted.QLayouted._layout
  • Instance Variable - magneticalc.QMessageBox2.QMessageBox2.choice
  • Instance Variable - magneticalc.QSaveAction.QSaveAction.filename
  • Instance Variable - magneticalc.QSliderFloat.QSliderFloat._step
  • Class Variable - magneticalc.QTableWidget2.QTableWidget2.MinimumHeight
  • Instance Variable - magneticalc.QTableWidget2.QTableWidget2._cell_edited_callback
  • Instance Variable - magneticalc.QTableWidget2.QTableWidget2._enabled
  • Instance Variable - magneticalc.QTableWidget2.QTableWidget2._minimum_rows
  • Instance Variable - magneticalc.QTableWidget2.QTableWidget2._options
  • Instance Variable - magneticalc.QTableWidget2.QTableWidget2._prefix
  • Instance Variable - magneticalc.QTableWidget2.QTableWidget2._row_deleted_callback
  • Instance Variable - magneticalc.QTableWidget2.QTableWidget2._selection_changed_callback
  • Instance Variable - magneticalc.QTableWidget2.QTableWidget2._types
  • Instance Variable - magneticalc.QTableWidget2.QTableWidget2.gui
  • Class Variable - magneticalc.SamplingVolume.SamplingVolume.Debug_Constraints
  • Instance Variable - magneticalc.SamplingVolume.SamplingVolume._bounds_max
  • Instance Variable - magneticalc.SamplingVolume.SamplingVolume._bounds_min
  • Instance Variable - magneticalc.SamplingVolume.SamplingVolume._dimension
  • Instance Variable - magneticalc.SamplingVolume.SamplingVolume._label_resolution
  • Instance Variable - magneticalc.SamplingVolume.SamplingVolume._labeled_indices
  • Instance Variable - magneticalc.SamplingVolume.SamplingVolume._neighbor_indices
  • Instance Variable - magneticalc.SamplingVolume.SamplingVolume._permeabilities
  • Instance Variable - magneticalc.SamplingVolume.SamplingVolume._points
  • Instance Variable - magneticalc.SamplingVolume.SamplingVolume._resolution
  • Instance Variable - magneticalc.SamplingVolume.SamplingVolume.constraints
  • Class Variable - magneticalc.SamplingVolume_Widget.SamplingVolume_Widget.PaddingMax
  • Class Variable - magneticalc.SamplingVolume_Widget.SamplingVolume_Widget.PaddingMin
  • Class Variable - magneticalc.SamplingVolume_Widget.SamplingVolume_Widget.ResolutionOptionsDict
  • Class Variable - magneticalc.SamplingVolume_Widget.SamplingVolume_Widget.UnitsLabelWidth
  • Instance Variable - magneticalc.SamplingVolume_Widget.SamplingVolume_Widget.constraint_editor
  • Instance Variable - magneticalc.SamplingVolume_Widget.SamplingVolume_Widget.gui
  • Instance Variable - magneticalc.SamplingVolume_Widget.SamplingVolume_Widget.padding_spinbox
  • Instance Variable - magneticalc.SamplingVolume_Widget.SamplingVolume_Widget.padding_widget
  • Instance Variable - magneticalc.SamplingVolume_Widget.SamplingVolume_Widget.resolution_combobox
  • Instance Variable - magneticalc.SamplingVolume_Widget.SamplingVolume_Widget.resolution_units_label
  • Instance Variable - magneticalc.SamplingVolume_Widget.SamplingVolume_Widget.total_constraints_label
  • Instance Variable - magneticalc.SamplingVolume_Widget.SamplingVolume_Widget.total_extent_label
  • Instance Variable - magneticalc.SamplingVolume_Widget.SamplingVolume_Widget.total_points_label
  • Class Variable - magneticalc.SidebarLeft.SidebarLeft.MaximumWidth
  • Class Variable - magneticalc.SidebarLeft.SidebarLeft.VerticalSpacing
  • Instance Variable - magneticalc.SidebarLeft.SidebarLeft.gui
  • Instance Variable - magneticalc.SidebarLeft.SidebarLeft.sampling_volume_widget
  • Instance Variable - magneticalc.SidebarLeft.SidebarLeft.wire_widget
  • Class Variable - magneticalc.SidebarRight.SidebarRight.MaximumWidth
  • Class Variable - magneticalc.SidebarRight.SidebarRight.VerticalSpacing
  • Instance Variable - magneticalc.SidebarRight.SidebarRight.display_widget
  • Instance Variable - magneticalc.SidebarRight.SidebarRight.field_widget
  • Instance Variable - magneticalc.SidebarRight.SidebarRight.gui
  • Instance Variable - magneticalc.SidebarRight.SidebarRight.metric_widget
  • Instance Variable - magneticalc.SidebarRight.SidebarRight.parameters_widget
  • Instance Variable - magneticalc.SidebarRight.SidebarRight.perspective_widget
  • Instance Variable - magneticalc.Statusbar.Statusbar._auto_calculation_checkbox
  • Instance Variable - magneticalc.Statusbar.Statusbar._cancel_button
  • Instance Variable - magneticalc.Statusbar.Statusbar._cores_combobox
  • Instance Variable - magneticalc.Statusbar.Statusbar._label
  • Instance Variable - magneticalc.Statusbar.Statusbar._progressbar
  • Instance Variable - magneticalc.Statusbar.Statusbar._start_button
  • Instance Variable - magneticalc.Statusbar.Statusbar.gui
  • Class Variable - magneticalc.Theme.Theme.DarkColor
  • Class Variable - magneticalc.Theme.Theme.DefaultFontFace
  • Class Variable - magneticalc.Theme.Theme.FailureColor
  • Class Variable - magneticalc.Theme.Theme.LiteColor
  • Class Variable - magneticalc.Theme.Theme.MainColor
  • Class Variable - magneticalc.Theme.Theme.SuccessColor
  • Class Variable - magneticalc.Usage_Dialog.Usage_Dialog.HTML
  • Class Variable - magneticalc.Version.Version.Copyright
  • Class Variable - magneticalc.Version.Version.License
  • Class Variable - magneticalc.Version.Version.String
  • Variable - magneticalc.Version.__URL__
  • Variable - magneticalc.Version.__VERSION__
  • Variable - magneticalc.Version.__VERSION__URL__
  • Class Variable - magneticalc.VispyCanvas.VispyCanvas.Black
  • Class Variable - magneticalc.VispyCanvas.VispyCanvas.DebugPerspective
  • Class Variable - magneticalc.VispyCanvas.VispyCanvas.DebugVisuals
  • Class Variable - magneticalc.VispyCanvas.VispyCanvas.DefaultFontSize
  • Class Variable - magneticalc.VispyCanvas.VispyCanvas.FieldArrowHeadSize
  • Class Variable - magneticalc.VispyCanvas.VispyCanvas.FieldPointSize
  • Class Variable - magneticalc.VispyCanvas.VispyCanvas.MagnitudeLimit
  • Class Variable - magneticalc.VispyCanvas.VispyCanvas.MagnitudePrecision
  • Class Variable - magneticalc.VispyCanvas.VispyCanvas.ScaleFactorMax
  • Class Variable - magneticalc.VispyCanvas.VispyCanvas.ScaleFactorMin
  • Class Variable - magneticalc.VispyCanvas.VispyCanvas.White
  • Class Variable - magneticalc.VispyCanvas.VispyCanvas.WirePointSelectedColor
  • Class Variable - magneticalc.VispyCanvas.VispyCanvas.WirePointSelectedSize
  • Class Variable - magneticalc.VispyCanvas.VispyCanvas.WirePointSize
  • Instance Variable - magneticalc.VispyCanvas.VispyCanvas.background
  • Instance Variable - magneticalc.VispyCanvas.VispyCanvas.bgcolor
  • Instance Variable - magneticalc.VispyCanvas.VispyCanvas.font_manager
  • Instance Variable - magneticalc.VispyCanvas.VispyCanvas.foreground
  • Instance Variable - magneticalc.VispyCanvas.VispyCanvas.gui
  • Instance Variable - magneticalc.VispyCanvas.VispyCanvas.initializing
  • Instance Variable - magneticalc.VispyCanvas.VispyCanvas.redraw_start_time
  • Instance Variable - magneticalc.VispyCanvas.VispyCanvas.signals_blocked
  • Instance Variable - magneticalc.VispyCanvas.VispyCanvas.super_perspective_changed
  • Instance Variable - magneticalc.VispyCanvas.VispyCanvas.view_main
  • Instance Variable - magneticalc.VispyCanvas.VispyCanvas.view_text
  • Instance Variable - magneticalc.VispyCanvas.VispyCanvas.visual_coordinate_system
  • Instance Variable - magneticalc.VispyCanvas.VispyCanvas.visual_field_arrow_heads
  • Instance Variable - magneticalc.VispyCanvas.VispyCanvas.visual_field_arrow_lines
  • Instance Variable - magneticalc.VispyCanvas.VispyCanvas.visual_field_labels
  • Instance Variable - magneticalc.VispyCanvas.VispyCanvas.visual_field_points
  • Instance Variable - magneticalc.VispyCanvas.VispyCanvas.visual_perspective_info
  • Instance Variable - magneticalc.VispyCanvas.VispyCanvas.visual_startup_info
  • Instance Variable - magneticalc.VispyCanvas.VispyCanvas.visual_wire_points_selected
  • Instance Variable - magneticalc.VispyCanvas.VispyCanvas.visual_wire_points_sliced
  • Instance Variable - magneticalc.VispyCanvas.VispyCanvas.visual_wire_segments
  • Instance Variable - magneticalc.Wire.Wire._dc
  • Instance Variable - magneticalc.Wire.Wire._length
  • Instance Variable - magneticalc.Wire.Wire._points_base
  • Instance Variable - magneticalc.Wire.Wire._points_sliced
  • Instance Variable - magneticalc.Wire.Wire._points_transformed
  • Instance Variable - magneticalc.Wire.Wire._slicer_limit
  • Class Variable - magneticalc.Wire_Presets.Wire_Presets.CompensatedDoubleSquareLoop_Centered
  • Class Variable - magneticalc.Wire_Presets.Wire_Presets.CompensatedDoubleSquareLoop_Offset
  • Class Variable - magneticalc.Wire_Presets.Wire_Presets.CompensatedSolenoidCircularLoops4
  • Class Variable - magneticalc.Wire_Presets.Wire_Presets.CompensatedSolenoidCircularLoops8
  • Class Variable - magneticalc.Wire_Presets.Wire_Presets.List
  • Class Variable - magneticalc.Wire_Presets.Wire_Presets.PhaseJumpingToroidalLoop16
  • Class Variable - magneticalc.Wire_Presets.Wire_Presets.PhaseJumpingToroidalLoop32
  • Class Variable - magneticalc.Wire_Presets.Wire_Presets.PhaseJumpingToroidalLoop8
  • Class Variable - magneticalc.Wire_Presets.Wire_Presets.SingleCircularLoop_Offset
  • Class Variable - magneticalc.Wire_Presets.Wire_Presets.SingleSquareLoop_Centered
  • Class Variable - magneticalc.Wire_Presets.Wire_Presets.SingleSquareLoop_Offset
  • Class Variable - magneticalc.Wire_Presets.Wire_Presets.SolenoidCircularLoops4
  • Class Variable - magneticalc.Wire_Presets.Wire_Presets.SolenoidCircularLoops8
  • Class Variable - magneticalc.Wire_Presets.Wire_Presets.StraightLine
  • Class Variable - magneticalc.Wire_Presets.Wire_Presets.ToroidalLoop16
  • Class Variable - magneticalc.Wire_Presets.Wire_Presets.ToroidalLoop32
  • Class Variable - magneticalc.Wire_Presets.Wire_Presets.ToroidalLoop8
  • Class Variable - magneticalc.Wire_Widget.Wire_Widget.DcMaximum
  • Class Variable - magneticalc.Wire_Widget.Wire_Widget.DcMinimum
  • Class Variable - magneticalc.Wire_Widget.Wire_Widget.DcPrecision
  • Class Variable - magneticalc.Wire_Widget.Wire_Widget.DcStep
  • Class Variable - magneticalc.Wire_Widget.Wire_Widget.RotationalSymmetryCountMax
  • Class Variable - magneticalc.Wire_Widget.Wire_Widget.RotationalSymmetryCountMin
  • Class Variable - magneticalc.Wire_Widget.Wire_Widget.RotationalSymmetryOffsetMax
  • Class Variable - magneticalc.Wire_Widget.Wire_Widget.RotationalSymmetryOffsetMin
  • Class Variable - magneticalc.Wire_Widget.Wire_Widget.RotationalSymmetryOffsetPrecision
  • Class Variable - magneticalc.Wire_Widget.Wire_Widget.RotationalSymmetryOffsetStep
  • Class Variable - magneticalc.Wire_Widget.Wire_Widget.RotationalSymmetryRadiusMax
  • Class Variable - magneticalc.Wire_Widget.Wire_Widget.RotationalSymmetryRadiusMin
  • Class Variable - magneticalc.Wire_Widget.Wire_Widget.RotationalSymmetryRadiusPrecision
  • Class Variable - magneticalc.Wire_Widget.Wire_Widget.RotationalSymmetryRadiusStep
  • Class Variable - magneticalc.Wire_Widget.Wire_Widget.SlicerLimitMaximum
  • Class Variable - magneticalc.Wire_Widget.Wire_Widget.SlicerLimitMinimum
  • Class Variable - magneticalc.Wire_Widget.Wire_Widget.SlicerLimitPrecision
  • Class Variable - magneticalc.Wire_Widget.Wire_Widget.SlicerLimitStep
  • Class Variable - magneticalc.Wire_Widget.Wire_Widget.StretchMax
  • Class Variable - magneticalc.Wire_Widget.Wire_Widget.StretchMin
  • Class Variable - magneticalc.Wire_Widget.Wire_Widget.StretchPrecision
  • Class Variable - magneticalc.Wire_Widget.Wire_Widget.StretchStep
  • Class Variable - magneticalc.Wire_Widget.Wire_Widget.UnitsLabelWidth
  • Instance Variable - magneticalc.Wire_Widget.Wire_Widget.close_loop_checkbox
  • Instance Variable - magneticalc.Wire_Widget.Wire_Widget.dc_spinbox
  • Instance Variable - magneticalc.Wire_Widget.Wire_Widget.gui
  • Instance Variable - magneticalc.Wire_Widget.Wire_Widget.rotational_symmetry_axis_combobox
  • Instance Variable - magneticalc.Wire_Widget.Wire_Widget.rotational_symmetry_count_spinbox
  • Instance Variable - magneticalc.Wire_Widget.Wire_Widget.rotational_symmetry_offset_spinbox
  • Instance Variable - magneticalc.Wire_Widget.Wire_Widget.rotational_symmetry_radius_spinbox
  • Instance Variable - magneticalc.Wire_Widget.Wire_Widget.sliced_total_label
  • Instance Variable - magneticalc.Wire_Widget.Wire_Widget.slicer_limit_spinbox
  • Instance Variable - magneticalc.Wire_Widget.Wire_Widget.stretch_spinbox
  • Instance Variable - magneticalc.Wire_Widget.Wire_Widget.table
  • Instance Variable - magneticalc.Wire_Widget.Wire_Widget.table_total_label
  • Instance Variable - magneticalc.Wire_Widget.Wire_Widget.transformed_total_label
  • diff --git a/magneticalc/API.py b/magneticalc/API.py index afe45bc..38c4c32 100644 --- a/magneticalc/API.py +++ b/magneticalc/API.py @@ -87,7 +87,7 @@ def export_hdf5(filename: str, data: Union[Dict, MagnetiCalc_Data]) -> None: # ------------------------------------------------------------------------------------------------------------------ @staticmethod - def _dict_to_hdf5_group(hdf5_group, dictionary) -> None: + def _dict_to_hdf5_group(hdf5_group: h5py.Group, dictionary: Dict) -> None: """ Recursively transforms a dictionary into an HDF5 group (in-place). @@ -102,7 +102,7 @@ def _dict_to_hdf5_group(hdf5_group, dictionary) -> None: hdf5_group[key] = dictionary[key] @staticmethod - def _hdf5_group_to_dict(hdf5_group, dictionary) -> None: + def _hdf5_group_to_dict(hdf5_group: h5py.Group, dictionary: Dict) -> None: """ Recursively transforms an HDF5 group into a dictionary (in-place). diff --git a/magneticalc/About_Dialog.py b/magneticalc/About_Dialog.py index 19bf605..aa99519 100644 --- a/magneticalc/About_Dialog.py +++ b/magneticalc/About_Dialog.py @@ -18,10 +18,11 @@ import webbrowser from functools import partial -from magneticalc.Theme import Theme -from magneticalc.Version import Version from magneticalc.QDialog2 import QDialog2 from magneticalc.QTextBrowser2 import QTextBrowser2 +from magneticalc.Debug import Debug +from magneticalc.Theme import Theme +from magneticalc.Version import Version class About_Dialog(QDialog2): @@ -32,7 +33,7 @@ class About_Dialog(QDialog2): # HTML content HTML = f""" - {Version.String}
    + {Version.String}

    Copyright © 2020–2021, Paul Wilhelm, M. Sc. <anfrage@paulwilhelm.de>
    @@ -53,24 +54,25 @@ class About_Dialog(QDialog2): OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

    - + If you like this software, please consider buying me a coffee!  :)
    """ - def __init__(self): + def __init__(self) -> None: """ Initializes "About" dialog. """ QDialog2.__init__(self, title="About", width=640) + Debug(self, ": Init") text_browser = QTextBrowser2(html=self.HTML) self.dialog_shown.connect(text_browser.fit_to_contents) self.addWidget(text_browser) buttons = self.addButtons({ - "OK": ("fa.check", self.accept), - "Donate 3€ …": ("fa.paypal", partial(webbrowser.open, About_Dialog.DonationURL)) + "OK" : ("fa.check", self.accept), + "Donate 3€ …" : ("fa.paypal", partial(webbrowser.open, About_Dialog.DonationURL)) }) buttons[0].setFocus() diff --git a/magneticalc/Assert_Dialog.py b/magneticalc/Assert_Dialog.py index 4a019b6..fcf1773 100644 --- a/magneticalc/Assert_Dialog.py +++ b/magneticalc/Assert_Dialog.py @@ -17,18 +17,18 @@ # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. import sys +from urllib.parse import urlencode, quote_plus from magneticalc.QDialog2 import QDialog2 +from magneticalc.QTextBrowser2 import QTextBrowser2 from magneticalc.Debug import Debug from magneticalc.Theme import Theme from magneticalc.Version import Version, __URL__ -from urllib.parse import urlencode, quote_plus -from magneticalc.QTextBrowser2 import QTextBrowser2 class Assert_Dialog: """ Assert_Dialog class. """ - def __init__(self, assertion: bool, message: str): + def __init__(self, assertion: bool, message: str) -> None: """ Shows a user dialog if an assertion failed. Intended for beta-testing. This allows the user to either quit or resume (possibly resulting in unstable behaviour). @@ -37,27 +37,24 @@ def __init__(self, assertion: bool, message: str): @param assertion: Boolean @param message: Error message """ - self.assertion = assertion - self.message = message - if assertion: return - Debug(self, f": Failed: {message}", color=Theme.WarningColor, force=True) + Debug(self, f": ERROR: Assertion failed: {message}", error=True) - self.dialog = QDialog2(title="Assertion failed", width=600) + self._dialog = QDialog2(title="Assertion failed", width=600) # Generate Github issue URL issue_url = \ f"{__URL__}/issues/new?" + \ urlencode( { - "title": f"Assertion failed: {self.message}", + "title": f"Assertion failed: {message}", "labels": "bug", "body": f"**I discovered a bug in {Version.String}:**\n" "```\n" - f"{self.message}\n" + f"{message}\n" "```\n\n" f"**Steps to reproduce the problem:**\n\n" "[_Please make sure to fill this in!_]" @@ -67,24 +64,25 @@ def __init__(self, assertion: bool, message: str): # HTML content html = f""" - Sorry for the inconvenience!
    + Sorry for the inconvenience!

    You seem to have discovered a bug in MagnetiCalc.
    If this error persists, please file an issue on GitHub!

    Error message:
    -
    {self.message}
    +
    {message}
    """ text_browser = QTextBrowser2(html=html) - self.dialog.addWidget(text_browser) + self._dialog.addWidget(text_browser) - self.dialog.addButtons({ - "Abort application": ("fa.times-circle", self.dialog.reject), - "Resume (possibly unstable)": ("fa.play-circle", self.dialog.accept) + self._dialog.addButtons({ + "Abort application" : ("fa.times-circle", self._dialog.reject), + "Resume (possibly unstable)": ("fa.play-circle", self._dialog.accept) }) - self.dialog.show() - if not self.dialog.success: + self._dialog.show() + + if not self._dialog.success: sys.exit() diff --git a/magneticalc/Backend_CUDA.py b/magneticalc/Backend_CUDA.py index 0eeecd3..ead2577 100644 --- a/magneticalc/Backend_CUDA.py +++ b/magneticalc/Backend_CUDA.py @@ -16,6 +16,7 @@ # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +from typing import Callable, Tuple, Optional import math import numpy as np from numba import cuda @@ -23,7 +24,6 @@ from magneticalc.Constants import Constants from magneticalc.Debug import Debug from magneticalc.Field_Types import A_FIELD, B_FIELD -from magneticalc.Theme import Theme class Backend_CUDA: @@ -38,11 +38,11 @@ def __init__( distance_limit: float, length_scale: float, dc: float, - current_elements, - sampling_volume_points, - sampling_volume_permeabilities, - progress_callback - ): + current_elements: np.ndarray, + sampling_volume_points: np.ndarray, + sampling_volume_permeabilities: np.ndarray, + progress_callback: Callable + ) -> None: """ Initializes the class attributes. @@ -55,7 +55,9 @@ def __init__( @param sampling_volume_permeabilities: Ordered list of sampling volume's relative permeabilities µ_r @param progress_callback: Progress callback """ - self.field_type = field_type + Debug(self, ": Init") + + self._field_type = field_type self._distance_limit = distance_limit self._length_scale = length_scale self._dc = dc @@ -65,7 +67,7 @@ def __init__( self._progress_callback = progress_callback @staticmethod - def is_available(): + def is_available() -> bool: """ Indicates the availability of this backend. @@ -76,17 +78,17 @@ def is_available(): @staticmethod @cuda.jit def worker( - field_type, - distance_limit, - length_scale, - element_centers, - element_directions, - sampling_volume_points, - sampling_volume_permeabilities, - field_vectors, - total_calculations, - total_skipped_calculations - ): + field_type: int, + distance_limit: float, + length_scale: float, + element_centers: np.ndarray, + element_directions: np.ndarray, + sampling_volume_points: np.ndarray, + sampling_volume_permeabilities: np.ndarray, + field_vectors: np.ndarray, + total_calculations: np.ndarray, + total_skipped_calculations: np.ndarray + ) -> None: """ Applies the Biot-Savart law for calculating the magnetic flux density (B-field) or vector potential (A-field) for all sampling volume points. @@ -133,11 +135,14 @@ def worker( total_calculations[sampling_volume_index] += 1 if field_type == A_FIELD: + # Calculate A-field (vector potential) vector_x += element_directions[current_element_index][0] * length_scale / scalar_distance vector_y += element_directions[current_element_index][1] * length_scale / scalar_distance vector_z += element_directions[current_element_index][2] * length_scale / scalar_distance + elif field_type == B_FIELD: + # Calculate B-field (flux density) a_1 = element_directions[current_element_index][0] * length_scale a_2 = element_directions[current_element_index][1] * length_scale @@ -150,13 +155,13 @@ def worker( field_vectors[sampling_volume_index, 1] = vector_y * sampling_volume_permeabilities[sampling_volume_index] field_vectors[sampling_volume_index, 2] = vector_z * sampling_volume_permeabilities[sampling_volume_index] - def get_result(self): + def get_result(self) -> Optional[Tuple[int, int, np.ndarray]]: """ Calculates the field at every point of the sampling volume. @return: (Total # of calculations, total # of skipped calculations, field) if successful, None if interrupted """ - Debug(self, ".get_result()", color=Theme.PrimaryColor) + Debug(self, ".get_result()") element_centers = [element[0] for element in self._current_elements] element_directions = [element[1] for element in self._current_elements] @@ -191,7 +196,7 @@ def get_result(self): self._progress_callback(100 * chunk_start / len(self._sampling_volume_points)) if QThread.currentThread().isInterruptionRequested(): - Debug(self, ".get_result(): Interruption requested, exiting now", color=Theme.PrimaryColor) + Debug(self, ".get_result(): WARNING: Interruption requested, exiting now", warning=True) return None remaining -= chunk_size @@ -205,7 +210,7 @@ def get_result(self): BPG = 65536 # Maximum blocks per grid Backend_CUDA.worker[BPG, TPB]( - self.field_type, + self._field_type, self._distance_limit, self._length_scale, element_centers_global, @@ -221,7 +226,7 @@ def get_result(self): total_skipped_calculations_local = total_skipped_calculations_global.copy_to_host() field_vectors_local = field_vectors_global.copy_to_host() - if self.field_type == A_FIELD or self.field_type == B_FIELD: + if self._field_type == A_FIELD or self._field_type == B_FIELD: # Field is A-field or B-field field_vectors_local = field_vectors_local * self._dc * Constants.mu_0 / 4 / np.pi diff --git a/magneticalc/Backend_JIT.py b/magneticalc/Backend_JIT.py index e2a60c8..9bec39f 100644 --- a/magneticalc/Backend_JIT.py +++ b/magneticalc/Backend_JIT.py @@ -16,13 +16,15 @@ # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +from typing import Callable, Tuple, Optional import numpy as np from numba import jit, prange from PyQt5.QtCore import QThread +from magneticalc.ConditionalDecorator import ConditionalDecorator +from magneticalc.Config import get_jit_enabled from magneticalc.Constants import Constants from magneticalc.Debug import Debug from magneticalc.Field_Types import A_FIELD, B_FIELD -from magneticalc.Theme import Theme class Backend_JIT: @@ -37,11 +39,11 @@ def __init__( distance_limit: float, length_scale: float, dc: float, - current_elements, - sampling_volume_points, - sampling_volume_permeabilities, - progress_callback - ): + current_elements: np.ndarray, + sampling_volume_points: np.ndarray, + sampling_volume_permeabilities: np.ndarray, + progress_callback: Callable + ) -> None: """ Initializes the class attributes. @@ -54,7 +56,9 @@ def __init__( @param sampling_volume_permeabilities: Ordered list of sampling volume's relative permeabilities µ_r @param progress_callback: Progress callback """ - self.field_type = field_type + Debug(self, ": Init") + + self._field_type = field_type self._distance_limit = distance_limit self._length_scale = length_scale self._dc = dc @@ -64,14 +68,14 @@ def __init__( self._progress_callback = progress_callback @staticmethod - @jit(nopython=True, parallel=True) + @ConditionalDecorator(get_jit_enabled(), jit, nopython=True, parallel=True) def worker( field_type: int, distance_limit: float, length_scale: float, - current_elements, - sampling_volume_point - ): + current_elements: np.ndarray, + sampling_volume_point: np.ndarray + ) -> Optional[Tuple[int, int, np.ndarray]]: """ Applies the Biot-Savart law for calculating the magnetic flux density (B-field) or vector potential (A-field) for a single sampling volume point. @@ -111,13 +115,13 @@ def worker( return total_calculations, total_skipped_calculations, vector - def get_result(self): + def get_result(self) -> Optional[Tuple[int, int, np.ndarray]]: """ Calculates the field at every point of the sampling volume. @return: (Total # of calculations, total # of skipped calculations, field) if successful, None if interrupted """ - Debug(self, ".get_result()", color=Theme.PrimaryColor) + Debug(self, ".get_result()") total_calculations = 0 total_skipped_calculations = 0 @@ -127,7 +131,7 @@ def get_result(self): for i in range(len(self._sampling_volume_points)): tup = Backend_JIT.worker( - self.field_type, + self._field_type, self._distance_limit, self._length_scale, self._current_elements, @@ -145,10 +149,10 @@ def get_result(self): self._progress_callback(100 * (i + 1) / len(self._sampling_volume_points)) if QThread.currentThread().isInterruptionRequested(): - Debug(self, ".get_result(): Interruption requested, exiting now", color=Theme.PrimaryColor) + Debug(self, ".get_result(): WARNING: Interruption requested, exiting now", warning=True) return None - if self.field_type == A_FIELD or self.field_type == B_FIELD: + if self._field_type == A_FIELD or self._field_type == B_FIELD: vectors = np.array(vectors) * self._dc * Constants.mu_0 / 4 / np.pi self._progress_callback(100) diff --git a/magneticalc/Backend_Types.py b/magneticalc/Backend_Types.py index ed6e87e..ba6bb17 100644 --- a/magneticalc/Backend_Types.py +++ b/magneticalc/Backend_Types.py @@ -16,6 +16,5 @@ # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -# Backend types BACKEND_JIT = 0 BACKEND_CUDA = 1 diff --git a/magneticalc/CalculationThread.py b/magneticalc/CalculationThread.py index e5b5f2f..40ddb44 100644 --- a/magneticalc/CalculationThread.py +++ b/magneticalc/CalculationThread.py @@ -16,10 +16,17 @@ # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +from __future__ import annotations from PyQt5.QtCore import QThread, pyqtSignal from multiprocessing import cpu_count +from magneticalc.Debug import Debug from magneticalc.ModelAccess import ModelAccess +# Note: Workaround for type hinting +# noinspection PyUnreachableCode +if False: + from magneticalc.GUI import GUI + class CalculationThread(QThread): """ @@ -29,40 +36,51 @@ class CalculationThread(QThread): """ # Progress update signal - progress_update = pyqtSignal(int) + _progress_update = pyqtSignal(int) # Valid state signals - wire_valid = pyqtSignal() - sampling_volume_valid = pyqtSignal() - field_valid = pyqtSignal() - metric_valid = pyqtSignal() - parameters_valid = pyqtSignal() + _wire_valid = pyqtSignal() + _sampling_volume_valid = pyqtSignal() + _field_valid = pyqtSignal() + _metric_valid = pyqtSignal() + _parameters_valid = pyqtSignal() - def __init__(self, gui): + def __init__(self, gui: GUI) -> None: """ Initializes calculation thread. @param gui: GUI """ QThread.__init__(self) - + Debug(self, ": Init") self.gui = gui - # Connect progress update signal and create callback - self.progress_update.connect(lambda x: self.gui.statusbar.progressbar.setValue(x)) - self.progress_callback = self.progress_update.emit + # Connect progress update signal and create callback: + + # noinspection PyUnresolvedReferences + self._progress_update.connect(lambda x: self.gui.statusbar.set_progress(x)) + # noinspection PyUnresolvedReferences + self.progress_callback = self._progress_update.emit - # Connect valid state signals to corresponding handlers - self.wire_valid.connect(self.on_wire_valid) - self.sampling_volume_valid.connect(self.on_sampling_volume_valid) - self.field_valid.connect(self.on_field_valid) - self.metric_valid.connect(self.on_metric_valid) - self.parameters_valid.connect(self.on_parameters_valid) + # Connect valid state signals to corresponding handlers: - def run(self): + # noinspection PyUnresolvedReferences + self._wire_valid.connect(self.on_wire_valid) + # noinspection PyUnresolvedReferences + self._sampling_volume_valid.connect(self.on_sampling_volume_valid) + # noinspection PyUnresolvedReferences + self._field_valid.connect(self.on_field_valid) + # noinspection PyUnresolvedReferences + self._metric_valid.connect(self.on_metric_valid) + # noinspection PyUnresolvedReferences + self._parameters_valid.connect(self.on_parameters_valid) + + def run(self) -> None: """ Thread main function. """ + Debug(self, ".run()") + with ModelAccess(self.gui, recalculate=False): if not self.gui.model.wire.is_valid(): @@ -72,7 +90,8 @@ def run(self): self.on_finished(False) return - self.wire_valid.emit() + # noinspection PyUnresolvedReferences + self._wire_valid.emit() # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -83,7 +102,8 @@ def run(self): self.on_finished(False) return - self.sampling_volume_valid.emit() + # noinspection PyUnresolvedReferences + self._sampling_volume_valid.emit() # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -101,7 +121,8 @@ def run(self): self.on_finished(False) return - self.field_valid.emit() + # noinspection PyUnresolvedReferences + self._field_valid.emit() # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -112,7 +133,8 @@ def run(self): self.on_finished(False) return - self.metric_valid.emit() + # noinspection PyUnresolvedReferences + self._metric_valid.emit() # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -123,7 +145,8 @@ def run(self): self.on_finished(False) return - self.parameters_valid.emit() + # noinspection PyUnresolvedReferences + self._parameters_valid.emit() # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -131,12 +154,13 @@ def run(self): # ------------------------------------------------------------------------------------------------------------------ - def on_finished(self, success: bool): + def on_finished(self, success: bool) -> None: """ Signals that the calculation finished. @param success: True if calculation was successful, False otherwise """ + Debug(self, f".on_finished(success={success})") # We cannot directly call this; we won't be able to modify the UI thread (which we'd really like to do somehow): # self.gui.calculation_stopped(success) @@ -147,37 +171,42 @@ def on_finished(self, success: bool): # ------------------------------------------------------------------------------------------------------------------ - def on_wire_valid(self): + def on_wire_valid(self) -> None: """ Gets called when the wire was successfully calculated. """ + Debug(self, ".on_wire_valid()") self.gui.model.on_wire_valid() self.gui.vispy_canvas.redraw() - def on_sampling_volume_valid(self): + def on_sampling_volume_valid(self) -> None: """ Gets called when the sampling volume was successfully calculated. """ + Debug(self, ".on_sampling_volume_valid()") self.gui.model.on_sampling_volume_valid() self.gui.vispy_canvas.redraw() - def on_field_valid(self): + def on_field_valid(self) -> None: """ Gets called when the field was successfully calculated. """ + Debug(self, ".on_field_valid()") self.gui.model.on_field_valid() self.gui.vispy_canvas.redraw() - def on_metric_valid(self): + def on_metric_valid(self) -> None: """ Gets called when the metric was successfully calculated. """ + Debug(self, ".on_metric_valid()") self.gui.model.on_metric_valid() self.gui.vispy_canvas.redraw() - def on_parameters_valid(self): + def on_parameters_valid(self) -> None: """ Gets called when the parameters were successfully calculated. """ + Debug(self, ".on_parameters_valid()") self.gui.model.on_parameters_valid() self.gui.vispy_canvas.redraw() diff --git a/magneticalc/CheckForUpdates_Dialog.py b/magneticalc/CheckForUpdates_Dialog.py index 456e063..ab12eb8 100644 --- a/magneticalc/CheckForUpdates_Dialog.py +++ b/magneticalc/CheckForUpdates_Dialog.py @@ -20,10 +20,10 @@ from urllib.request import urlopen from PyQt5.Qt import QFont, QSize from PyQt5.QtWidgets import QTextEdit -from magneticalc.QLabel2 import QLabel2 from magneticalc.QDialog2 import QDialog2 -from magneticalc.Debug import Debug from magneticalc.QIconLabel import QIconLabel +from magneticalc.QLabel2 import QLabel2 +from magneticalc.Debug import Debug from magneticalc.Theme import Theme from magneticalc.Version import __VERSION__, __VERSION__URL__ @@ -36,6 +36,7 @@ def __init__(self) -> None: Prepares the 'Check for Updates' dialog. """ QDialog2.__init__(self, title="Check for Updates", width=500) + Debug(self, ": Init") update_hint = False @@ -43,7 +44,7 @@ def __init__(self) -> None: try: version_py = urlopen(__VERSION__URL__, timeout=2).read().decode("utf-8") except Exception: - icon, string, color = "fa.exclamation-circle", f"Network Error", Theme.WarningColor + icon, string, color = "fa.exclamation-circle", f"Network Error", Theme.FailureColor else: # noinspection RegExpAnonymousGroup pattern = re.compile(r'__VERSION__ = "v(\d+)\.(\d+)\.(\d+)"') @@ -51,25 +52,25 @@ def __init__(self) -> None: try: version = "v" + ".".join(pattern.search(version_py).groups()) except Exception: - icon, string, color = "fa.exclamation-circle", f"Invalid Format", Theme.WarningColor + icon, string, color = "fa.exclamation-circle", f"Invalid Format", Theme.FailureColor else: if version > __VERSION__: icon, string, color = "fa.info-circle", f"Newer version available: {version}", Theme.SuccessColor update_hint = True elif version == __VERSION__: - icon, string, color = "fa.check-circle", f"Up-to-date: {version}", Theme.PrimaryColor + icon, string, color = "fa.check-circle", f"Up-to-date: {version}", Theme.MainColor else: icon, string, color = \ - "fa.exclamation-circle", f"Ahead of current release {version}", Theme.WarningColor + "fa.exclamation-circle", f"Ahead of current release {version}", Theme.FailureColor - Debug(self, f": Check for Updates ({__VERSION__URL__}): {string}", color=color, force=True) + Debug(self, f": Check for Updates ({__VERSION__URL__}): {string}", color=color) icon_label = QIconLabel( text=string, icon=icon, text_color=color, icon_color=color, icon_size=QSize(32, 32), - font=QFont("DejaVu Sans Mono", 14) + font=QFont(Theme.DefaultFontFace, 14) ) self.addLayout(icon_label) @@ -78,7 +79,7 @@ def __init__(self) -> None: self.addWidget(QLabel2("Please update now:", italic=True)) self.addSpacing(8) cmd = QTextEdit("python3 -m pip install magneticalc --upgrade") - cmd.setFont(QFont("DejaVu Sans Mono", 12)) + cmd.setFont(QFont(Theme.DefaultFontFace, 12)) cmd.setMaximumHeight(64) cmd.setReadOnly(True) self.add_element(cmd) diff --git a/magneticalc/Comparison_Types.py b/magneticalc/Comparison_Types.py new file mode 100644 index 0000000..173d7d3 --- /dev/null +++ b/magneticalc/Comparison_Types.py @@ -0,0 +1,51 @@ +""" Comparison_Types module. """ + +# ISC License +# +# Copyright (c) 2020–2021, Paul Wilhelm, M. Sc. +# +# Permission to use, copy, modify, and/or distribute this software for any +# purpose with or without fee is hereby granted, provided that the above +# copyright notice and this permission notice appear in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +from typing import Optional + + +COMPARISON_TYPE_IN_RANGE = 0 + + +Comparison_Types_Str_Map = { + COMPARISON_TYPE_IN_RANGE : "In Range" +} + + +def comparison_type_to_str(comparison_type: int) -> Optional[str]: + """ + Converts a comparison type to a comparison string. + + @param comparison_type: Comparison type + @return: Comparison string, or None if comparison type is invalid + """ + return Comparison_Types_Str_Map.get(comparison_type, None) + + +def comparison_type_from_str(comparison_str: str) -> Optional[int]: + """ + Converts a comparison string to a comparison type. + + @param comparison_str: Comparison string + @return Comparison type, or None if comparison string is invalid + """ + result = [ + _comparison_type for _comparison_type, _comparison_str in Comparison_Types_Str_Map.items() + if _comparison_str == comparison_str + ] + return result[0] if len(result) == 1 else None diff --git a/magneticalc/ConditionalDecorator.py b/magneticalc/ConditionalDecorator.py new file mode 100644 index 0000000..2fbe97d --- /dev/null +++ b/magneticalc/ConditionalDecorator.py @@ -0,0 +1,44 @@ +""" ConditionalDecorator module. """ + +# ISC License +# +# Copyright (c) 2020–2021, Paul Wilhelm, M. Sc. +# +# Permission to use, copy, modify, and/or distribute this software for any +# purpose with or without fee is hereby granted, provided that the above +# copyright notice and this permission notice appear in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +from typing import Callable, Any + + +class ConditionalDecorator(object): + """ ConditionalDecorator class. """ + + def __init__(self, condition: bool, decorating_func: Callable, **decorating_args: Any) -> None: + """ + Initializes a conditional decorator. + + @param condition: Condition + @param decorating_func: Decorating function + @param decorating_args: Arguments to decorating function + """ + self.condition = condition + self.decorating_func = decorating_func + self.decorating_args = decorating_args + + def __call__(self, func: Callable) -> Callable: + """ + Gets called when a function is to be decorated. + + @param func: Function to be decorated + @return: Decorated function + """ + return self.decorating_func(func, **self.decorating_args) if self.condition else func diff --git a/magneticalc/Config.py b/magneticalc/Config.py index a9feebd..f5da5a4 100644 --- a/magneticalc/Config.py +++ b/magneticalc/Config.py @@ -16,17 +16,27 @@ # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +from typing import Optional, Dict, Callable, List, Union, Any import os import configparser -from magneticalc.Backend_Types import BACKEND_JIT, BACKEND_CUDA +import numpy as np +from magneticalc.Backend_Types import BACKEND_CUDA from magneticalc.Debug import Debug -from magneticalc.Field_Types import A_FIELD, B_FIELD +from magneticalc.Field_Types import B_FIELD from magneticalc.Perspective_Presets import Perspective_Presets -from magneticalc.Theme import Theme from magneticalc.Version import Version from magneticalc.Wire_Presets import Wire_Presets +def get_jit_enabled() -> bool: + """ + Checks if JIT is enabled (or at least not explicitly disabled). + + @return: Boolean + """ + return (os.environ["NUMBA_DISABLE_JIT"] == "0") if "NUMBA_DISABLE_JIT" in os.environ else True + + class Config: """ Config class. """ @@ -34,9 +44,6 @@ class Config: FloatPrecision = 4 CoordinatePrecision = 6 - # Enable to additionally debug read access to configuration - DebugGetters = False - # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # Default wire preset @@ -87,7 +94,7 @@ class Config: "constraint_count" : "0" } - def __init__(self): + def __init__(self) -> None: """ Initializes the configuration. """ @@ -111,7 +118,7 @@ def __init__(self): # ------------------------------------------------------------------------------------------------------------------ - def set_changed_callback(self, config_changed_callback): + def set_changed_callback(self, config_changed_callback: Callable) -> None: """ Sets the callback for any changes to the configuration. @@ -129,14 +136,15 @@ def get_synced(self) -> bool: # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - def set_filename(self, filename: str): + def set_filename(self, filename: str) -> None: """ Sets the filename for the current session. @param filename: Filename """ self._filename = os.path.join(os.path.dirname(os.path.dirname(__file__)), filename) - Debug(self, ".set_filename: file://" + self._filename.replace(" ", "%20"), force=True) + + Debug(self, ".set_filename: file://" + self._filename.replace(" ", "%20")) def get_filename(self) -> str: """ @@ -148,12 +156,12 @@ def get_filename(self) -> str: # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - def load(self): + def load(self) -> None: """ Loads the configuration from file. """ - Debug(self, ".load()", force=True) + Debug(self, ".load()") self._config = configparser.ConfigParser() @@ -169,7 +177,7 @@ def load(self): # Save newly created default file self.save() - def set_defaults(self): + def set_defaults(self) -> None: """ Sets the default key-value pairs. Creates empty "User" section if not present. """ @@ -181,11 +189,11 @@ def set_defaults(self): # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - def save(self): + def save(self) -> None: """ Saves the configuration to file. """ - Debug(self, ".save()", force=True) + Debug(self, ".save()") with open(self._filename, "w") as file: self._config.write(file) @@ -194,7 +202,7 @@ def save(self): if self._changed_callback is not None: self._changed_callback() - def close(self): + def close(self) -> None: """ Close configuration. """ @@ -202,14 +210,14 @@ def close(self): # ------------------------------------------------------------------------------------------------------------------ - def remove_key(self, key): + def remove_key(self, key: str) -> None: """ Removes a key from the configuration. @param key: Key """ if not self._config.remove_option("User", key): - Debug(self, f".remove_key({key}): WARNING: No such key", color=Theme.WarningColor, force=True) + Debug(self, f".remove_key({key}): ERROR: No such key", error=True) # ------------------------------------------------------------------------------------------------------------------ @@ -240,7 +248,7 @@ def get_int(self, key: str) -> int: """ return int(self.get_str(key)) - def get_points(self, key: str): + def get_points(self, key: str) -> List[List[float]]: """ Gets list of 3D points, convert from string. @@ -249,7 +257,7 @@ def get_points(self, key: str): """ return Config.str_to_points(self.get_str(key)) - def get_point(self, key: str): + def get_point(self, key: str) -> List[float]: """ Gets a single 3D point, convert from string. @@ -265,15 +273,12 @@ def get_str(self, key: str) -> str: @param key: Key @return: Value """ - if self.DebugGetters: - Debug(self, f".get_str({key})") - value = self._config.get("User", key) return value # ------------------------------------------------------------------------------------------------------------------ - def set_bool(self, key: str, value: bool): + def set_bool(self, key: str, value: bool) -> None: """ Sets boolean value, convert to string. @@ -282,7 +287,7 @@ def set_bool(self, key: str, value: bool): """ self.set_str(key, "True" if value else "False") - def set_float(self, key: str, value: float): + def set_float(self, key: str, value: float) -> None: """ Sets float value, convert to string. @@ -291,7 +296,7 @@ def set_float(self, key: str, value: float): """ self.set_str(key, f"{float(value):.{Config.FloatPrecision}f}") - def set_int(self, key: str, value: int): + def set_int(self, key: str, value: int) -> None: """ Sets integer value, convert to string. @@ -300,7 +305,7 @@ def set_int(self, key: str, value: int): """ self.set_str(key, str(int(value))) - def set_points(self, key: str, value): + def set_points(self, key: str, value: Union[np.ndarray, List[List[float]]]) -> None: """ Sets list of 3D points, convert to string. @@ -309,7 +314,7 @@ def set_points(self, key: str, value): """ self.set_str(key, Config.points_to_str(value)) - def set_point(self, key: str, value): + def set_point(self, key: str, value: Union[np.ndarray, List[float]]) -> None: """ Sets a single 3D point, convert to string. @@ -318,21 +323,19 @@ def set_point(self, key: str, value): """ self.set_str(key, Config.point_to_str(value)) - def set_str(self, key: str, value: str): + def set_str(self, key: str, value: str) -> None: """ Writes a configuration value. Key must be in "Default" section and may be overridden in "User" section. @param key: Key @param value: Value """ - Debug(self, f".set_str({key}, {value})") - self._config.set("User", key, value) self._synced = False if self._changed_callback is not None: self._changed_callback() - def set_get_bool(self, key: str, value: bool) -> bool: + def set_get_bool(self, key: str, value: bool) -> Optional[bool]: """ If value is not None, writes and returns key-value; otherwise (if value is None), reads and returns key-value. @@ -345,7 +348,7 @@ def set_get_bool(self, key: str, value: bool) -> bool: self.set_bool(key, value) return value - def set_get_float(self, key: str, value: float) -> float: + def set_get_float(self, key: str, value: float) -> Optional[float]: """ If value is not None, writes and returns key-value; otherwise (if value is None), reads and returns key-value. @@ -358,7 +361,7 @@ def set_get_float(self, key: str, value: float) -> float: self.set_float(key, value) return value - def set_get_int(self, key: str, value: int) -> int: + def set_get_int(self, key: str, value: int) -> Optional[int]: """ If value is not None, writes and returns key-value; otherwise (if value is None), reads and returns key-value. @@ -371,7 +374,11 @@ def set_get_int(self, key: str, value: int) -> int: self.set_int(key, value) return value - def set_get_points(self, key: str, value): + def set_get_points( + self, + key: str, + value: Union[np.ndarray, List[List[float]]] + ) -> Optional[Union[np.ndarray, List[List[float]]]]: """ If value is not None, writes and returns key-value; otherwise (if value is None), reads and returns key-value. @@ -384,7 +391,11 @@ def set_get_points(self, key: str, value): self.set_points(key, value) return value - def set_get_point(self, key: str, value): + def set_get_point( + self, + key: str, + value: Union[np.ndarray, List[float]] + ) -> Optional[Union[np.ndarray, List[float]]]: """ If value is not None, writes and returns key-value; otherwise (if value is None), reads and returns key-value. @@ -397,7 +408,7 @@ def set_get_point(self, key: str, value): self.set_point(key, value) return value - def set_get_str(self, key: str, value: str) -> str: + def set_get_str(self, key: str, value: str) -> Optional[str]: """ If value is not None, writes and returns key-value; otherwise (if value is None), reads and returns key-value. @@ -413,7 +424,7 @@ def set_get_str(self, key: str, value: str) -> str: # ------------------------------------------------------------------------------------------------------------------ @staticmethod - def point_to_str(point) -> str: + def point_to_str(point: Union[np.ndarray, List[float]]) -> str: """ Converts a single 3D point to string. @@ -426,7 +437,7 @@ def point_to_str(point) -> str: f"{point[2]:+0.0{Config.CoordinatePrecision}f}" @staticmethod - def points_to_str(points) -> str: + def points_to_str(points: Union[np.ndarray, List[List[float]]]) -> str: """ Converts list of 3D points to string. @@ -436,7 +447,7 @@ def points_to_str(points) -> str: return "; ".join([Config.point_to_str(point) for point in points]) @staticmethod - def str_to_point(str_point: str): + def str_to_point(str_point: str) -> Union[np.ndarray, List[float]]: """ Converts string to single 3D point. @@ -446,7 +457,7 @@ def str_to_point(str_point: str): return [float(coord) for coord in str_point.split(",")] @staticmethod - def str_to_points(str_points: str): + def str_to_points(str_points: str) -> Union[np.ndarray, List[List[float]]]: """ Converts string to list of 3D points. @@ -460,7 +471,7 @@ def str_to_points(str_points: str): # ------------------------------------------------------------------------------------------------------------------ - def get_generic(self, _key: str, _type): + def get_generic(self, _key: str, _type) -> Any: """ Gets some "_key"-"_value" of data type "_type". @@ -480,7 +491,7 @@ def get_generic(self, _key: str, _type): # noinspection PyArgumentList return set_func.get(_type)(_key) - def set_generic(self, _key: str, _type, _value): + def set_generic(self, _key: str, _type, _value: Any) -> None: """ Sets some "_key"-"_value" of data type "_type". @@ -500,13 +511,13 @@ def set_generic(self, _key: str, _type, _value): # noinspection PyArgumentList set_func.get(_type)(_key, _value) - def set_get_dict(self, prefix: str, suffix: str, types, values): + def set_get_dict(self, prefix: str, suffix: str, types: Dict, values: Optional[Dict]) -> Optional[Dict]: """ If "values" is None, reads and returns all key-values in "types". Note: The actual keys saved in the configuration file are prefixed with "prefix", and suffixed with "suffix". If "values" is not None, writes and returns all key-values in "types". - Note: In this case, "values" must have the same keys as "types. + Note: In this case, "values" must have the same keys as "types". @param prefix: Prefix @param suffix: Suffix diff --git a/magneticalc/Config_Group.py b/magneticalc/Config_Group.py new file mode 100644 index 0000000..68edae9 --- /dev/null +++ b/magneticalc/Config_Group.py @@ -0,0 +1,142 @@ +""" Config_Collection module. """ + +# ISC License +# +# Copyright (c) 2020–2021, Paul Wilhelm +# +# Permission to use, copy, modify, and/or distribute this software for any +# purpose with or without fee is hereby granted, provided that the above +# copyright notice and this permission notice appear in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +from __future__ import annotations +from typing import Optional, List, Dict +from magneticalc.Assert_Dialog import Assert_Dialog + +# Note: Workaround for type hinting +# noinspection PyUnreachableCode +if False: + from magneticalc.GUI import GUI + + +class Config_Collection: + """ Config_Collection class. """ + + def __init__(self, gui: GUI, prefix: str, types: Dict, first_without_suffix: bool) -> None: + """ + Initializes a config collection: A list of groups (dictionaries). + + Example for the SOMETHING collection, consisting of two groups _0 and _1, each with two keys FOO and BAR: + SOMETHING_count = 2 + SOMETHING_FOO_0 = "1st value in 1st group" + SOMETHING_BAR_0 = "2nd value in 1st group" + SOMETHING_FOO_1 = "1st value in 2nd group" + SOMETHING_BAR_1 = "2nd value in 2nd group" + + @param gui: GUI + @param prefix: Prefix + @param types: Key:Type (Dictionary) + @param first_without_suffix: Enable to omit the suffix "_0" for the first group + """ + self.gui = gui + self.prefix = prefix + self.types = types + self.first_without_suffix = first_without_suffix + + def _get_suffix(self, group_index: int) -> str: + """ + Gets the suffix for a given group index. + + @param group_index: Group index + @return: String + """ + return "" if group_index == 0 and self.first_without_suffix else f"_{group_index}" + + def get_count(self) -> int: + """ + Gets the number of groups in the collection. + + @return: Number of groups in the collection + """ + return self.gui.config.get_int(self.prefix + "count") + + def get_group(self, group_index: int) -> Dict: + """ + Gets a group from the collection. + + @param group_index: Group index + @return: Group (dictionary) + """ + return self.gui.config.set_get_dict( + prefix=self.prefix, + suffix=self._get_suffix(group_index), + types=self.types, + values=None + ) + + def get_all_groups(self) -> List[Dict]: + """ + Gets every group in the collection. + + @return: List of groups (dictionaries) + """ + return [self.get_group(group_index) for group_index in range(self.get_count())] + + def add_group(self, values: Optional[Dict]) -> None: + """ + Appends a group to the collection. + + @param values: Key:Value (Dictionary) + """ + group_index = self.get_count() + self.gui.config.set_int(self.prefix + "count", group_index + 1) + self.gui.config.set_get_dict( + prefix=self.prefix, + suffix=self._get_suffix(group_index), + types=self.types, + values=values, + ) + + def del_group(self, group_index: int) -> None: + """ + Deletes a group from the collection. + + @param group_index: Group index + """ + Assert_Dialog(group_index < self.get_count(), "Attempting to delete non-existing group") + + # Make a copy of all groups + groups = self.get_all_groups() + + # Delete the desired group from the copy + del groups[group_index] + + # Delete all groups from the collection + for i in range(self.get_count()): + for key in self.types.keys(): + self.gui.config.remove_key(f"{self.prefix}{key}_{i}") + + # Clear the group count of the collection + self.gui.config.set_int(self.prefix + "count", 0) + + # Recreate the groups of the collection (regenerate suffixes) + for group in groups: + self.add_group(group) + + def set(self, group_index: int, key: str, value) -> None: + """ + Sets a value for some key in a group of the collection. + + @param group_index: Group index + @param key: Key + @param value: Value + """ + _type = self.types.get(key) + self.gui.config.set_generic(f"{self.prefix}{key}_{group_index}", _type, value) diff --git a/magneticalc/Constants.py b/magneticalc/Constants.py index d8586a4..0b10317 100644 --- a/magneticalc/Constants.py +++ b/magneticalc/Constants.py @@ -20,5 +20,5 @@ class Constants: """ Constants class. """ - # Magnetic field constant µ0 + # Magnetic field constant µ_0 mu_0 = 1.25663706212e-6 # kg · m / s² / A² diff --git a/magneticalc/Constraint.py b/magneticalc/Constraint.py index acbdfb0..7b010b5 100644 --- a/magneticalc/Constraint.py +++ b/magneticalc/Constraint.py @@ -16,85 +16,93 @@ # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +from magneticalc.Norm_Types import * +from typing import Union, List +import numpy as np from magneticalc.Debug import Debug from magneticalc.Metric import metric_norm -from magneticalc.Theme import Theme +from magneticalc.Comparison_Types import * class Constraint: """ Constraint class. """ - # Norm IDs - # Note: These have to match the norm IDs defined in Metric.metric_norm - Norm_ID_List = [ - "X", - "Y", - "Z", - "Radius XY", - "Radius XZ", - "Radius YZ", - "Radius", - "Angle XY", - "Angle XZ", - "Angle YZ", + # Supported norm types + Norm_Types_List = [ + NORM_TYPE_X, + NORM_TYPE_Y, + NORM_TYPE_Z, + NORM_TYPE_RADIUS, + NORM_TYPE_RADIUS_X, + NORM_TYPE_RADIUS_Y, + NORM_TYPE_RADIUS_Z, + NORM_TYPE_RADIUS_XY, + NORM_TYPE_RADIUS_XZ, + NORM_TYPE_RADIUS_YZ, + NORM_TYPE_ANGLE_XY, + NORM_TYPE_ANGLE_XZ, + NORM_TYPE_ANGLE_YZ ] + Norm_Types_List_Str = [norm_type_to_str(norm_type) for norm_type in Norm_Types_List] - # Comparison IDs - Comparison_ID_List = [ - "In Range" + # Supported norm types using minimum and maximum angles in degrees + Norm_Types_Degrees_List = [ + NORM_TYPE_ANGLE_XY, + NORM_TYPE_ANGLE_XZ, + NORM_TYPE_ANGLE_YZ ] - # Norm IDs using minimum and maximum angles in degrees - Norm_ID_List_Degrees = [ - "Angle XY", - "Angle XZ", - "Angle YZ" + # Supported comparison types + Comparison_Types_List = [ + COMPARISON_TYPE_IN_RANGE ] + Comparison_Types_List_Str = [comparison_type_to_str(comparison_type) for comparison_type in Comparison_Types_List] - def __init__(self, norm_id: str, comparison_id: str, _min: float, _max: float, permeability: float): + def __init__(self, norm_type: int, comparison_type: int, _min: float, _max: float, permeability: float): """ Initializes the constraint. - @param norm_id: Norm ID - @param comparison_id: Comparison ID + @param norm_type: Norm type + @param comparison_type: Comparison type @param _min: Minimum value @param _max: Maximum value @param permeability: Relative permeability µ_r """ - if norm_id not in self.Norm_ID_List: - Debug(self, "Invalid norm ID", color=Theme.WarningColor, force=True) + if norm_type not in self.Norm_Types_List: + Debug(self, ": ERROR: Invalid norm ID", error=True) return - if comparison_id not in self.Comparison_ID_List: - Debug(self, "Invalid comparison ID", color=Theme.WarningColor, force=True) + if comparison_type not in self.Comparison_Types_List: + Debug(self, ": ERROR: Invalid comparison ID", error=True) return - self._is_angle = norm_id in self.Norm_ID_List_Degrees + self._is_angle = norm_type in self.Norm_Types_Degrees_List - self._norm_id = norm_id - self._comparison_id = comparison_id + self._norm_type = norm_type + self._comparison_type = comparison_type self._min = _min self._max = _max self.permeability = permeability - def evaluate(self, point) -> bool: + def evaluate(self, point: Union[np.ndarray, List[float]]) -> bool: """ Evaluate this constraint at some point. @param point: Point (3D vector) """ - norm = metric_norm(self._norm_id, point) + norm = metric_norm(self._norm_type, point) # Perform comparison - if self._comparison_id == "In Range": + if self._comparison_type == COMPARISON_TYPE_IN_RANGE: if self._is_angle: # Convert normalized angle to degrees norm *= 360 return self._min <= norm <= self._max + else: # Invalid comparison ID return False diff --git a/magneticalc/Constraint_Editor.py b/magneticalc/Constraint_Editor.py index 7fa7346..22b9c2b 100644 --- a/magneticalc/Constraint_Editor.py +++ b/magneticalc/Constraint_Editor.py @@ -16,16 +16,24 @@ # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +from __future__ import annotations +from typing import List, Dict, Any import qtawesome as qta from PyQt5.QtCore import Qt from PyQt5.QtWidgets import QPushButton, QSizePolicy from magneticalc.Constraint import Constraint from magneticalc.Debug import Debug +from magneticalc.Config_Group import Config_Collection from magneticalc.QIconLabel import QIconLabel from magneticalc.QTableWidget2 import QTableWidget2 -from magneticalc.Theme import Theme from magneticalc.QDialog2 import QDialog2 from magneticalc.QTextBrowser2 import QTextBrowser2 +from magneticalc.Theme import Theme + +# Note: Workaround for type hinting +# noinspection PyUnreachableCode +if False: + from magneticalc.GUI import GUI class Constraint_Editor(QDialog2): @@ -42,24 +50,29 @@ class Constraint_Editor(QDialog2): # Constraint options Constraint_Options = [ - Constraint.Norm_ID_List, - Constraint.Comparison_ID_List, + Constraint.Norm_Types_List_Str, + Constraint.Comparison_Types_List_Str, None, None, None ] - def __init__(self, gui): + def __init__(self, gui: GUI) -> None: """ Prepares the constraint editor, but doesn't fully initialize it yet. @param gui: GUI """ QDialog2.__init__(self, title="Constraint Editor", width=700) - + Debug(self, ": Init") self.gui = gui - self._constraints = [] + self._constraint_collection = Config_Collection( + gui=gui, + prefix="constraint_", + types=self.Constraint_Types, + first_without_suffix=False + ) self._changed = None @@ -91,7 +104,7 @@ def __init__(self, gui): html = f""" Lengths in cm.   Angles in degrees.

    - Experimental Feature

    + Experimental Feature

    By default, all sampling volume points have relative permeability µr = 1.
    A constraint assigns some other µr to some region of the sampling volume.
    @@ -113,41 +126,34 @@ def __init__(self, gui): # This will be called by the SamplingVolume_Widget: # self.reinitialize() - def reinitialize(self): + self.dialog_shown.connect(self.table.setFocus) + + def reinitialize(self) -> None: """ Re-initializes the constraint editor. """ Debug(self, ".reinitialize()") - # Initially load the constraints - self.reload_constraints() self.update_table() self.clear_changed() # ------------------------------------------------------------------------------------------------------------------ - def show(self): - """ - Shows this dialog. - """ - self.table.setFocus() - self.exec() - def get_changed(self) -> bool: """ Returns the "changed" state of the current session. """ return self._changed - def clear_changed(self): + def clear_changed(self) -> None: """ Clears the "changed" state of the current session. """ self._changed = False self.update_title() - def update_title(self): + def update_title(self) -> None: """ Updates the window title. """ @@ -158,112 +164,71 @@ def update_title(self): # ------------------------------------------------------------------------------------------------------------------ - def reload_constraints(self): - """ - Re-loads the list of constraints. + def get_count(self) -> int: """ - self._constraints = [] + Gets the number of constraints. - for i in range(self.gui.config.get_int("constraint_count")): - self._constraints.append(self.gui.config.set_get_dict( - prefix=f"constraint_", - suffix=f"_{i}", - types=self.Constraint_Types, - values=None - )) + @return: Number of constraints + """ + return self._constraint_collection.get_count() - def get_constraints(self): + def get_constraints(self) -> List[Dict]: """ - Returns the list of constraints. + Gets the list of constraints. @param: List of constraints """ - return self._constraints + return self._constraint_collection.get_all_groups() # ------------------------------------------------------------------------------------------------------------------ - def update_table(self): + def update_table(self) -> None: """ Populates the table. """ self.table.clear_rows() - self.table.set_vertical_header([str(i + 1) for i in range(len(self.get_constraints()))]) + self.table.set_vertical_header([str(i + 1) for i in range(self.get_count())]) self.table.set_contents(self.get_constraints()) self.table.select_last_row(focus=False) - def on_table_row_added(self): + def on_table_row_added(self) -> None: """ Gets called after a row has been added to the table. """ - count = self.gui.config.get_int("constraint_count") + 1 - self.gui.config.set_int("constraint_count", count) - - self.gui.config.set_get_dict( - prefix=f"constraint_", - suffix=f"_{count - 1}", - types=self.Constraint_Types, - values={ - "norm" : Constraint.Norm_ID_List[0], - "comparison" : Constraint.Comparison_ID_List[0], - "min" : "0.0000", - "max" : "1.0000", - "permeability" : "1.0000" - }, - ) + self._constraint_collection.add_group(values={ + "norm" : Constraint.Norm_Types_List_Str[0], + "comparison" : Constraint.Comparison_Types_List_Str[0], + "min" : "0.0000", + "max" : "1.0000", + "permeability" : "1.0000" + }) - self.reload_constraints() self.update_table() self.table.select_last_row() self._changed = True self.update_title() - def on_table_cell_edited(self, value, row, column): + def on_table_cell_edited(self, value: Any, row: int, column: int): """ Gets called after a table cell has been edited. @param value: Cell value - @param row: Row - @param column: Column + @param row: Row index + @param column: Column index """ - key = list(self.Constraint_Types.keys())[column] - _type = self.Constraint_Types.get(key) - self.gui.config.set_generic(f"constraint_{key}_{row}", _type, value) - self.reload_constraints() + self._constraint_collection.set(group_index=row, key=list(self.Constraint_Types.keys())[column], value=value) self._changed = True self.update_title() - def on_table_row_deleted(self, index): + def on_table_row_deleted(self, row: int) -> None: """ Gets called after a row has been deleted from the table. - @param index: Row index + @param row: Row index """ - count = self.gui.config.get_int("constraint_count") - - assert count > 0 - assert index < count - - # Remove all constraints from configuration - for i in range(count): - for key in self.Constraint_Types.keys(): - self.gui.config.remove_key(f"constraint_{key}_{i}") - - # Remove selected constraint from internal list - del self._constraints[index] - - # Add all remaining constraints to configuration again (regenerate keys) - for i, constraint in enumerate(self.get_constraints()): - self.gui.config.set_get_dict( - prefix=f"constraint_", - suffix=f"_{i}", - types=self.Constraint_Types, - values=constraint - ) - - self.gui.config.set_int("constraint_count", count - 1) - + self._constraint_collection.del_group(row) self.update_table() self._changed = True diff --git a/magneticalc/Debug.py b/magneticalc/Debug.py index b39ce59..5f3d0bc 100644 --- a/magneticalc/Debug.py +++ b/magneticalc/Debug.py @@ -16,11 +16,12 @@ # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +from typing import Optional from inspect import isclass, stack -from sty import fg, ef, rs +from sty import Style, fg, ef -# Enable to see JIT debug output +# Enable to see JIT debug output: # import os # os.environ["NUMBA_PARALLEL_DIAGNOSTICS"] = "4" @@ -28,67 +29,26 @@ class Debug: """ Debug class. """ - # Enable debug output from specific classes only - Whitelist = [ - "About_Dialog", - "API", - "Assert_Dialog", - "Backend_Types", - "Backend_CUDA", - "Backend_JIT", - "CalculationThread", - "CheckForUpdates_Dialog", - # "Config", - "Constants", - "Constraint", - "Constraint_Editor", - - "Display_Widget", - "ExportContainer_Dialog", - "Field", - "Field_Types", - "Field_Widget", - "GUI", - "Menu", - "Metric", - "Metric_Presets", - "Metric_Widget", - "Model", - # "ModelAccess", - "OverridePadding_Dialog", - "Parameters", - "Parameters_Widget", - "Perspective_Presets", - "Perspective_Widget", - "QButtons", - "QDialog2", - "QGroupBox2", - "QHBoxLayout2", - "QHLine", - "QIconLabel", - "QLabel2", - "QLayouted", - "QMessageBox2", - "QSaveAction", - "QSliderFloat", - "QSpinBox2", - # "QTableWidget2", - "QTextBrowser2", - "SamplingVolume", - # "SamplingVolume_Widget", - "SidebarLeft", - "SidebarRight", - "Statusbar", - "Theme", - "Usage_Dialog", - "Version", - # "VispyCanvas", - "Wire", - "Wire_Presets", - "Wire_Widget" + # Colors + LightColor = fg.grey + SuccessColor = fg.green + WarningColor = fg.magenta + ErrorColor = fg.red + + # Block debug output from specific classes + Blacklist = [ ] - def __init__(self, obj, text: str, color=None, force: bool = False): + def __init__( + self, + obj: object, + text: str, + color: Optional[Style] = None, + force: bool = False, + success: bool = False, + warning: bool = False, + error: bool = False + ) -> None: """ Displays a colorful debug message and the current call hierarchy. @@ -96,6 +56,9 @@ def __init__(self, obj, text: str, color=None, force: bool = False): @param text: Debug message @param color: Color (may be None) @param force: Enable to override whitelist + @param success: Enable to set color=SuccessColor + @param warning: Enable to set color=WarningColor and force=True + @param error: Enable to set color=ErrorColor and force=True """ if isclass(obj): # Called from within class method, i.e. Debug(self, ...) @@ -104,9 +67,12 @@ def __init__(self, obj, text: str, color=None, force: bool = False): # Called from within instance / static method name = type(obj).__name__ + if warning or error: + force = True + if not force: - # Skip non-whitelisted class names - if name not in self.Whitelist: + # Skip blacklisted class names + if name in self.Blacklist: return # A class may specify its own default color @@ -114,7 +80,7 @@ def __init__(self, obj, text: str, color=None, force: bool = False): if hasattr(obj, "DebugColor"): color = obj.DebugColor else: - color = (0, 0, 0) + color = "" # Format call hierarchy hierarchy = "" @@ -128,14 +94,13 @@ def __init__(self, obj, text: str, color=None, force: bool = False): func_str = "\tCalculationThread" hierarchy += func_str + "/" - if isinstance(color, str): - # Convert hex color string ("#abcdef") to RGB tuple - color = tuple(int(color[i:i+2], 16) for i in (1, 3, 5)) + if success: + color = self.SuccessColor - if color == (0, 0, 0): - # Allow a terminal use its own foreground color - color_text = ef.bold + name + ef.rs + text - else: - color_text = fg(*color) + ef.bold + name + ef.rs + text + fg.rs + if warning: + color = self.WarningColor + + if error: + color = self.ErrorColor - print(fg(128, 128, 128) + hierarchy + fg.rs + color_text + rs.all + "\n", end="") + print(self.LightColor + hierarchy + fg.rs + color + ef.bold + name + ef.rs + text + fg.rs + "\n", end="") diff --git a/magneticalc/Display_Widget.py b/magneticalc/Display_Widget.py index 4ff8220..9ad7d98 100644 --- a/magneticalc/Display_Widget.py +++ b/magneticalc/Display_Widget.py @@ -16,6 +16,7 @@ # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +from __future__ import annotations import numpy as np from PyQt5.QtCore import Qt from PyQt5.QtWidgets import QCheckBox, QComboBox, QLabel, QSizePolicy, QHBoxLayout, QVBoxLayout, QMessageBox @@ -29,6 +30,11 @@ from magneticalc.Theme import Theme from magneticalc.VispyCanvas import VispyCanvas +# Note: Workaround for type hinting +# noinspection PyUnreachableCode +if False: + from magneticalc.GUI import GUI + class Display_Widget(QGroupBox2): """ Display_Widget class. """ @@ -50,14 +56,14 @@ class Display_Widget(QGroupBox2): # Warn about displaying an excessive number of field labels ExcessiveFieldLabelThreshold = 250 - def __init__(self, gui): + def __init__(self, gui: GUI) -> None: """ Populates the widget. @param gui: GUI """ QGroupBox2.__init__(self, "Display") - + Debug(self, ": Init") self.gui = gui # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -159,9 +165,9 @@ def __init__(self, gui): total_labels_layout = QHBoxLayout() total_labels_left = QLabel("Total labels:") - total_labels_left.setStyleSheet(f"color: {Theme.LightColor}; font-style: italic;") + total_labels_left.setStyleSheet(f"color: {Theme.LiteColor}; font-style: italic;") self.total_labels_label = QLabel("N/A") - self.total_labels_label.setStyleSheet(f"color: {Theme.PrimaryColor};") + self.total_labels_label.setStyleSheet(f"color: {Theme.MainColor};") self.total_labels_label.setAlignment(Qt.AlignRight | Qt.AlignVCenter) total_labels_layout.addWidget(total_labels_left, alignment=Qt.AlignVCenter) total_labels_layout.addWidget(self.total_labels_label, alignment=Qt.AlignVCenter) @@ -171,7 +177,7 @@ def __init__(self, gui): self.reinitialize() - def reinitialize(self): + def reinitialize(self) -> None: """ Re-initializes the widget. """ @@ -193,7 +199,7 @@ def reinitialize(self): # ------------------------------------------------------------------------------------------------------------------ - def set_enabled(self, enabled: bool): + def set_enabled(self, enabled: bool) -> None: """ Enables / disables this widget. @@ -203,7 +209,7 @@ def set_enabled(self, enabled: bool): # ------------------------------------------------------------------------------------------------------------------ - def set_field_point_scale(self, value: float): + def set_field_point_scale(self, value: float) -> None: """ Sets field point scale. @@ -215,7 +221,7 @@ def set_field_point_scale(self, value: float): self.gui.config.set_float("field_point_scale", value) self.gui.redraw() - def set_field_arrow_head_scale(self, value: float): + def set_field_arrow_head_scale(self, value: float) -> None: """ Sets field arrow head scale. @@ -227,7 +233,7 @@ def set_field_arrow_head_scale(self, value: float): self.gui.config.set_float("field_arrow_head_scale", value) self.gui.redraw() - def set_field_arrow_line_scale(self, value: float): + def set_field_arrow_line_scale(self, value: float) -> None: """ Sets field arrow line scale. @@ -239,7 +245,7 @@ def set_field_arrow_line_scale(self, value: float): self.gui.config.set_float("field_arrow_line_scale", value) self.gui.redraw() - def set_field_boost(self, value: float): + def set_field_boost(self, value: float) -> None: """ Sets field boost value. @@ -251,7 +257,7 @@ def set_field_boost(self, value: float): self.gui.config.set_float("field_boost", value) self.gui.redraw() - def set_display_field_magnitude_labels(self, value: bool): + def set_display_field_magnitude_labels(self, value: bool) -> None: """ Sets field label "Display Magnitude" value. @@ -268,7 +274,7 @@ def set_display_field_magnitude_labels(self, value: bool): self.gui.redraw() - def set_field_label_resolution(self, value: int): + def set_field_label_resolution(self, value: int) -> None: """ Sets field label resolution exponent. @@ -285,7 +291,7 @@ def set_field_label_resolution(self, value: int): # ------------------------------------------------------------------------------------------------------------------ - def update(self): + def update(self) -> None: """ Updates this widget. """ @@ -294,7 +300,7 @@ def update(self): self.update_labels() self.update_controls() - def update_labels(self): + def update_labels(self) -> None: """ Updates the labels. """ @@ -302,14 +308,14 @@ def update_labels(self): if self.gui.model.sampling_volume.is_valid(): n = self.gui.model.sampling_volume.get_labels_count() - color = Theme.WarningColor if n > self.ExcessiveFieldLabelThreshold else Theme.LightColor + color = Theme.FailureColor if n > self.ExcessiveFieldLabelThreshold else Theme.LiteColor self.total_labels_label.setText(str(n)) self.total_labels_label.setStyleSheet(f"color: {color}; font-style: italic;") else: self.total_labels_label.setText("N/A") - self.total_labels_label.setStyleSheet(f"color: {Theme.LightColor}; font-style: italic;") + self.total_labels_label.setStyleSheet(f"color: {Theme.LiteColor}; font-style: italic;") - def update_controls(self): + def update_controls(self) -> None: """ Updates the field label resolution combobox. """ @@ -349,12 +355,7 @@ def connection(): # Set default field label resolution if it is not available anymore target = self.gui.config.get_int("sampling_volume_label_resolution_exponent") if target not in label_resolution_options_dict.values(): - Debug( - self, - f": Invalid: sampling_volume_label_resolution_exponent = {target}", - color=Theme.WarningColor, - force=True - ) + Debug(self, f": WARNING: Invalid: sampling_volume_label_resolution_exponent = {target}", warning=True) self.gui.config.set_int( "sampling_volume_label_resolution_exponent", next(iter(label_resolution_options_dict.items()))[1] # First value from combobox diff --git a/magneticalc/ExportContainer_Dialog.py b/magneticalc/ExportContainer_Dialog.py index b36c6b8..2c09d83 100644 --- a/magneticalc/ExportContainer_Dialog.py +++ b/magneticalc/ExportContainer_Dialog.py @@ -16,31 +16,39 @@ # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +from __future__ import annotations from PyQt5.QtWidgets import QCheckBox from magneticalc.QLabel2 import QLabel2 from magneticalc.QDialog2 import QDialog2 from magneticalc.QSaveAction import QSaveAction from magneticalc.API import API +from magneticalc.Debug import Debug from magneticalc.Field_Types import A_FIELD, B_FIELD from magneticalc.Theme import Theme +# Note: Workaround for type hinting +# noinspection PyUnreachableCode +if False: + from magneticalc.GUI import GUI + class ExportContainer_Dialog(QDialog2): """ ExportContainer_Dialog class. """ - def __init__(self, gui) -> None: + def __init__(self, gui: GUI) -> None: """ Prepares the 'Export Container' dialog. @param gui: GUI """ QDialog2.__init__(self, title="Export Container", width=500) + Debug(self, ": Init") self.gui = gui - self.addWidget(QLabel2("Please select items for export", bold=True, color=Theme.PrimaryColor)) + self.addWidget(QLabel2("Please select items for export", bold=True, color=Theme.MainColor)) self.addSpacing(8) self.addWidget(QLabel2( - "Fields must have been calculated before they can be exported.", italic=True, color=Theme.LightColor + "Fields must have been calculated before they can be exported.", italic=True, color=Theme.LiteColor )) self.addSpacing(16) @@ -89,6 +97,8 @@ def export(self) -> None: """ Exports wire points, current and fields to some HDF5 container file. """ + Debug(self, ".export()") + export_a_field = self.a_field_checkbox.isChecked() export_b_field = self.b_field_checkbox.isChecked() export_wire_points = self.wire_points_checkbox.isChecked() diff --git a/magneticalc/Field.py b/magneticalc/Field.py index bff861a..91e735d 100644 --- a/magneticalc/Field.py +++ b/magneticalc/Field.py @@ -16,22 +16,25 @@ # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -from typing import Tuple +from typing import Tuple, Callable import numpy as np from numba import jit, prange, set_num_threads from magneticalc.Assert_Dialog import Assert_Dialog from magneticalc.Backend_Types import BACKEND_JIT, BACKEND_CUDA from magneticalc.Backend_CUDA import Backend_CUDA from magneticalc.Backend_JIT import Backend_JIT +from magneticalc.ConditionalDecorator import ConditionalDecorator +from magneticalc.Config import get_jit_enabled from magneticalc.Debug import Debug from magneticalc.Field_Types import A_FIELD, B_FIELD -from magneticalc.Theme import Theme +from magneticalc.SamplingVolume import SamplingVolume +from magneticalc.Wire import Wire class Field: """ Field class. """ - def __init__(self, backend_type: int, field_type: int, distance_limit: float, length_scale: float): + def __init__(self, backend_type: int, field_type: int, distance_limit: float, length_scale: float) -> None: """ Initializes an empty field. @@ -62,11 +65,11 @@ def is_valid(self) -> bool: self._total_skipped_calculations is not None and \ self._vectors is not None - def invalidate(self): + def invalidate(self) -> None: """ Resets data, hiding from display. """ - Debug(self, ".invalidate()", color=Theme.InvalidColor) + Debug(self, ".invalidate()") self._total_calculations = None self._total_skipped_calculations = None @@ -98,7 +101,7 @@ def get_units(self, show_gauss=False) -> Tuple[str, float]: B_FIELD: "T" # Tesla }.get(self._field_type, None), 1e0 - def get_vectors(self): + def get_vectors(self) -> np.ndarray: """ Gets field vectors. (The selected field type determined which field was calculated.) @@ -130,7 +133,13 @@ def get_total_skipped_calculations(self) -> int: # ------------------------------------------------------------------------------------------------------------------ - def recalculate(self, wire, sampling_volume, progress_callback, num_cores: int) -> bool: + def recalculate( + self, + wire: Wire, + sampling_volume: SamplingVolume, + progress_callback: Callable, + num_cores: int + ) -> bool: """ Recalculates field vectors. @@ -140,6 +149,7 @@ def recalculate(self, wire, sampling_volume, progress_callback, num_cores: int) @param num_cores: Number of cores to use for multiprocessing @return: True if successful, False if interrupted (CUDA backend currently not interruptable) """ + Debug(self, ".recalculate()") # Compute the current elements. current_elements = wire.get_elements() @@ -148,17 +158,15 @@ def recalculate(self, wire, sampling_volume, progress_callback, num_cores: int) if self._backend_type == BACKEND_CUDA: if not Backend_CUDA.is_available(): Debug( - self, - f".recalculate(): WARNING: CUDA backend not available, defaulting to JIT backend", - color=Theme.WarningColor, - force=True + self, f".recalculate(): WARNING: CUDA backend not available, defaulting to JIT backend", + warning=True ) self._backend_type = BACKEND_JIT if self._backend_type == BACKEND_JIT: # Initialize Biot-Savart JIT backend - biot_savart = Backend_JIT( + backend = Backend_JIT( self._field_type, self._distance_limit, self._length_scale, @@ -171,12 +179,12 @@ def recalculate(self, wire, sampling_volume, progress_callback, num_cores: int) # Fetch result using Biot-Savart JIT backend set_num_threads(num_cores) - tup = biot_savart.get_result() + backend_result = backend.get_result() elif self._backend_type == BACKEND_CUDA: # Initialize Biot-Savart CUDA backend - biot_savart = Backend_CUDA( + backend = Backend_CUDA( self._field_type, self._distance_limit, self._length_scale, @@ -189,44 +197,25 @@ def recalculate(self, wire, sampling_volume, progress_callback, num_cores: int) # Fetch result using Biot-Savart CUDA backend set_num_threads(num_cores) - tup = biot_savart.get_result() + backend_result = backend.get_result() else: - Debug(self, f".recalculate(): No such backend: {self._backend_type}", color=Theme.WarningColor, force=True) + Debug(self, f".recalculate(): ERROR: No such backend: {self._backend_type}", error=True) return False # Handle interrupt - if tup is None: + if backend_result is None: return False - self._total_calculations = tup[0] - self._total_skipped_calculations = tup[1] - self._vectors = tup[2] - - # Prints the sampling volume points, current elements and field vectors; may be used for debugging: - """ - def print_array(array): return "np.array([" + ",".join([f"[{p[0]},{p[1]},{p[2]}]" for p in array]) + "])" - - element_centers = [element[0] for element in wire.get_elements()] - element_directions = [element[1] for element in wire.get_elements()] - - import sys - import numpy - numpy.set_printoptions(threshold=sys.maxsize) - - print("Total calculations =", self.get_total_calculations()) - print("Total skipped calculations =", self.get_total_skipped_calculations()) - print("sampling_volume_points =", print_array(sampling_volume.get_points())) - print("element_centers =", print_array(element_centers)) - print("element_directions =", print_array(element_directions)) - print("vectors =", print_array(self._vectors)) - """ + self._total_calculations = backend_result[0] + self._total_skipped_calculations = backend_result[1] + self._vectors = backend_result[2] # Sanity check expected_total_calculations = len(current_elements) * sampling_volume.get_points_count() if expected_total_calculations != self._total_calculations: - Assert_Dialog(False, "FATAL: Unexpected number of calculations – Backend seems to be buggy") + Assert_Dialog(False, "ERROR: Unexpected number of calculations – Backend seems to be buggy") return False return True @@ -234,15 +223,15 @@ def print_array(array): return "np.array([" + ",".join([f"[{p[0]},{p[1]},{p[2]}] # ------------------------------------------------------------------------------------------------------------------ @staticmethod - @jit(nopython=True, parallel=True) + @ConditionalDecorator(get_jit_enabled(), jit, nopython=True, parallel=True) def get_arrows( - sampling_volume_points, - field_vectors, - line_pairs, - head_points, + sampling_volume_points: np.ndarray, + field_vectors: np.ndarray, + line_pairs: np.ndarray, + head_points: np.ndarray, arrow_scale: float, magnitude_limit: float - ): + ) -> Tuple[np.ndarray, np.ndarray]: """ Returns the field arrow parameters needed by L{VispyCanvas}. @@ -252,6 +241,7 @@ def get_arrows( @param head_points: Arrow head points (ordered list of arrow stop 3D points) @param arrow_scale: Arrow scale @param magnitude_limit: Magnitude limit (mitigating divisions by zero) + @return: Line pairs, head points """ for i in prange(len(field_vectors)): diff --git a/magneticalc/Field_Types.py b/magneticalc/Field_Types.py index 8a5718f..9de45a9 100644 --- a/magneticalc/Field_Types.py +++ b/magneticalc/Field_Types.py @@ -16,11 +16,24 @@ # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -# Field types +from typing import Optional + + A_FIELD = 0 B_FIELD = 1 -FIELD_TYPES_STR = { + +Field_Types_Str_Map = { A_FIELD: "A-Field", B_FIELD: "B-Field" } + + +def field_type_to_str(field_type: int) -> Optional[str]: + """ + Converts a field type to a field string. + + @param field_type: Field type + @return: Field string, or None if field type is invalid + """ + return Field_Types_Str_Map.get(field_type, None) diff --git a/magneticalc/Field_Widget.py b/magneticalc/Field_Widget.py index b00ba0c..e6c73ff 100644 --- a/magneticalc/Field_Widget.py +++ b/magneticalc/Field_Widget.py @@ -16,21 +16,27 @@ # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +from __future__ import annotations from typing import Optional from functools import partial from PyQt5.QtCore import Qt -from PyQt5.QtWidgets import QHBoxLayout, QVBoxLayout, QButtonGroup, QRadioButton, QDoubleSpinBox, QLabel, QSizePolicy,\ - QCheckBox -from magneticalc.Debug import Debug -from magneticalc.Field import Field -from magneticalc.Field_Types import A_FIELD, B_FIELD +from PyQt5.QtWidgets import QHBoxLayout, QVBoxLayout, QSizePolicy +from PyQt5.QtWidgets import QButtonGroup, QRadioButton, QDoubleSpinBox, QLabel, QCheckBox from magneticalc.QGroupBox2 import QGroupBox2 from magneticalc.QHLine import QHLine from magneticalc.QIconLabel import QIconLabel +from magneticalc.Debug import Debug +from magneticalc.Field import Field +from magneticalc.Field_Types import A_FIELD, B_FIELD from magneticalc.Metric import Metric from magneticalc.ModelAccess import ModelAccess from magneticalc.Theme import Theme +# Note: Workaround for type hinting +# noinspection PyUnreachableCode +if False: + from magneticalc.GUI import GUI + class Field_Widget(QGroupBox2): """ Field_Widget class. """ @@ -41,14 +47,14 @@ class Field_Widget(QGroupBox2): DistanceLimitStep = 0.0001 DistanceLimitPrecision = 4 - def __init__(self, gui): + def __init__(self, gui: GUI) -> None: """ Populates the widget. @param gui: GUI """ QGroupBox2.__init__(self, "Field") - + Debug(self, ": Init") self.gui = gui # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -86,9 +92,9 @@ def __init__(self, gui): total_calculations_layout = QHBoxLayout() total_calculations_left = QLabel("Total calculations:") - total_calculations_left.setStyleSheet(f"color: {Theme.LightColor}; font-style: italic;") + total_calculations_left.setStyleSheet(f"color: {Theme.LiteColor}; font-style: italic;") self.total_calculations_label = QLabel("N/A") - self.total_calculations_label.setStyleSheet(f"color: {Theme.PrimaryColor};") + self.total_calculations_label.setStyleSheet(f"color: {Theme.MainColor};") self.total_calculations_label.setAlignment(Qt.AlignRight | Qt.AlignVCenter) total_calculations_layout.addWidget(total_calculations_left, alignment=Qt.AlignVCenter) total_calculations_layout.addWidget(self.total_calculations_label, alignment=Qt.AlignVCenter) @@ -105,6 +111,7 @@ def __init__(self, gui): self.distance_limit_spinbox.setMinimum(self.DistanceLimitMinimum) self.distance_limit_spinbox.setMaximum(self.DistanceLimitMaximum) self.distance_limit_spinbox.setSingleStep(self.DistanceLimitStep) + # noinspection PyUnresolvedReferences self.distance_limit_spinbox.valueChanged.connect( lambda: self.set_field(distance_limit=self.distance_limit_spinbox.value()) ) @@ -117,9 +124,9 @@ def __init__(self, gui): total_skipped_calculations_layout = QHBoxLayout() total_skipped_calculations_left = QLabel("Total skipped calculations:") - total_skipped_calculations_left.setStyleSheet(f"color: {Theme.LightColor}; font-style: italic;") + total_skipped_calculations_left.setStyleSheet(f"color: {Theme.LiteColor}; font-style: italic;") self.total_skipped_calculations_label = QLabel("N/A") - self.total_skipped_calculations_label.setStyleSheet(f"color: {Theme.PrimaryColor};") + self.total_skipped_calculations_label.setStyleSheet(f"color: {Theme.MainColor};") self.total_skipped_calculations_label.setAlignment(Qt.AlignRight | Qt.AlignVCenter) total_skipped_calculations_layout.addWidget(total_skipped_calculations_left, alignment=Qt.AlignVCenter) total_skipped_calculations_layout.addWidget(self.total_skipped_calculations_label, alignment=Qt.AlignVCenter) @@ -129,7 +136,7 @@ def __init__(self, gui): self.reinitialize() - def reinitialize(self): + def reinitialize(self) -> None: """ Re-initializes the widget. """ @@ -149,7 +156,7 @@ def reinitialize(self): # ------------------------------------------------------------------------------------------------------------------ - def on_field_type_changed(self, field_type: bool, checked: bool): + def on_field_type_changed(self, field_type: bool, checked: bool) -> None: """ Gets called when the field type changed. @@ -173,7 +180,7 @@ def set_field( recalculate: bool = True, invalidate_self: bool = True, allow_cache: bool = False - ): + ) -> None: """ Sets the field. This will replace the currently set field in the model. @@ -188,6 +195,8 @@ def set_field( if self.signalsBlocked(): return + Debug(self, ".set_field()") + with ModelAccess(self.gui, recalculate): if allow_cache: @@ -196,7 +205,7 @@ def set_field( field = None if field is not None: - Debug(self, ".on_field_type_changed(): Using cached field", color=Theme.PrimaryColor) + Debug(self, ".set_field(): Using cached field") else: backend_type = self.gui.config.get_int("backend_type") field_type = self.gui.config.set_get_int("field_type", field_type) @@ -210,7 +219,7 @@ def set_field( # ------------------------------------------------------------------------------------------------------------------ - def update(self): + def update(self) -> None: """ Updates this widget. """ @@ -219,7 +228,7 @@ def update(self): self.update_labels() self.update_controls() - def update_labels(self): + def update_labels(self) -> None: """ Updates the labels. """ @@ -230,7 +239,7 @@ def update_labels(self): self.total_calculations_label.setText("N/A") self.total_skipped_calculations_label.setText("N/A") - def update_controls(self): + def update_controls(self) -> None: """ Updates the controls. """ diff --git a/magneticalc/GUI.py b/magneticalc/GUI.py index 82a9a05..4a5314d 100644 --- a/magneticalc/GUI.py +++ b/magneticalc/GUI.py @@ -19,8 +19,9 @@ import time import atexit from typing import Optional - +from sty import fg import qtawesome as qta +from PyQt5.Qt import QCloseEvent, QKeyEvent from PyQt5.QtCore import Qt, QThread, pyqtSignal, QLocale from PyQt5.QtWidgets import QMainWindow, QSplitter, QFileDialog, QMessageBox from magneticalc.QMessageBox2 import QMessageBox2 @@ -48,7 +49,7 @@ class GUI(QMainWindow): MinimumWindowSize = (800, 600) # Used by L{Debug} - DebugColor = Theme.PrimaryColor + DebugColor = fg.blue # Default configuration filename DefaultFilename = "MagnetiCalc-DefaultProject.ini" @@ -57,17 +58,16 @@ class GUI(QMainWindow): calculation_status = pyqtSignal(str) calculation_exited = pyqtSignal(bool) - def __init__(self): + def __init__(self) -> None: """ Initializes the GUI. """ QMainWindow.__init__(self, flags=Qt.Window) - Debug(self, ": Init") self.locale = QLocale(QLocale.English) - self.setWindowIcon(qta.icon("ei.magnet", color=Theme.PrimaryColor)) + self.setWindowIcon(qta.icon("ei.magnet", color=Theme.MainColor)) self.setMinimumSize(*self.MinimumWindowSize) self.showMaximized() @@ -109,7 +109,7 @@ def __init__(self): # Connect the calculation thread communication signals # noinspection PyUnresolvedReferences - self.calculation_status.connect(lambda text: self.statusbar.text(text)) + self.calculation_status.connect(lambda text: self.statusbar.set_text(text)) # noinspection PyUnresolvedReferences self.calculation_exited.connect(lambda success: self.on_calculation_exited(success)) @@ -123,26 +123,18 @@ def __init__(self): # ------------------------------------------------------------------------------------------------------------------ - def redraw(self): + def redraw(self) -> None: """ Re-draws the scene. """ + Debug(self, ".redraw()") + if self.calculation_thread is not None: if self.calculation_thread.isRunning(): - Debug( - self, - ".redraw(): Skipped because calculation is in progress", - color=Theme.PrimaryColor, - force=True - ) + Debug(self, ".redraw(): WARNING: Skipped because calculation is in progress", warning=True) return else: - Debug( - self, - ".redraw(): WARNING: Setting calculation thread to None", - color=Theme.WarningColor, - force=True - ) + Debug(self, ".redraw(): WARNING: Setting calculation thread to None", warning=True) self.calculation_thread = None self.sidebar_right.display_widget.set_enabled(self.model.field.is_valid()) @@ -151,19 +143,14 @@ def redraw(self): # ------------------------------------------------------------------------------------------------------------------ - def recalculate(self): + def recalculate(self) -> None: """ Re-calculates the model. """ Debug(self, ".recalculate()") if self.calculation_thread is not None: - Debug( - self, - ".recalculate(): WARNING: Killing orphaned calculation thread", - color=Theme.WarningColor, - force=True - ) + Debug(self, ".recalculate(): WARNING: Killing orphaned calculation thread", warning=True) self.interrupt_calculation() if self.initializing: @@ -178,12 +165,14 @@ def recalculate(self): self.calculation_start_time = time.monotonic() self.calculation_thread.start() - def on_calculation_exited(self, success: bool): + def on_calculation_exited(self, success: bool) -> None: """ This is called after calculation thread has exited. @param success: True if calculation was successful, False otherwise """ + Debug(self, f".on_calculation_exited(success={success})") + calculation_time = time.monotonic() - self.calculation_start_time if self.calculation_thread is not None: @@ -196,73 +185,55 @@ def on_calculation_exited(self, success: bool): else: # This happens when calculation finished and no other thread was started self.calculation_thread = None - Debug( - self, - f".on_calculation_exited(): Success (took {calculation_time:.2f} s)", - color=Theme.SuccessColor - ) + Debug(self, f".on_calculation_exited(): Success (took {calculation_time:.2f} s)", success=True) else: Debug( - self, - f".on_calculation_exited(): Interrupted after {calculation_time:.2f} s", color=Theme.PrimaryColor - ) + self, f".on_calculation_exited(): WARNING: Interrupted after {calculation_time:.2f} s", warning=True) # Note: For some reason, most of the time we need an additional ("final-final") re-draw here; VisPy glitch? self.redraw() self.statusbar.disarm(success) - def interrupt_calculation(self): + def interrupt_calculation(self) -> None: """ Kills any running calculation. """ + Debug(self, ".interrupt_calculation()") + if self.calculation_thread is None: - Debug( - self, - ".interrupt_calculation: WARNING: No calculation thread to interrupt", - color=Theme.WarningColor, - force=True - ) + Debug(self, ".interrupt_calculation(): WARNING: No calculation thread to interrupt", warning=True) return if self.calculation_thread.isRunning(): - Debug(self, ".interrupt_calculation(): Requesting interruption", color=Theme.PrimaryColor) + Debug(self, ".interrupt_calculation(): WARNING: Requesting interruption", warning=True) self.calculation_thread.requestInterruption() if self.calculation_thread.wait(5000): - Debug(self, ".interrupt_calculation(): Exited gracefully", color=Theme.PrimaryColor) + Debug(self, ".interrupt_calculation(): Exited gracefully", success=True) else: Assert_Dialog(False, "Failed to terminate calculation thread") if self.calculation_thread is not None: if self.calculation_thread.isRunning(): - Debug( - self, - ".interrupt_calculation(): WARNING: Terminating ungracefully", - color=Theme.WarningColor, - force=True - ) + Debug(self, ".interrupt_calculation(): WARNING: Terminating ungracefully", warning=True) self.calculation_thread.terminate() self.calculation_thread.wait() else: - Debug( - self, - ".interrupt_calculation: WARNING: Calculation thread should be running", - color=Theme.WarningColor, - force=True - ) + Debug(self, ".interrupt_calculation(): WARNING: Calculation thread should be running", warning=True) self.calculation_thread = None # ------------------------------------------------------------------------------------------------------------------ - @staticmethod - def confirm_saving_unsaved_work(cancelable: bool) -> Optional[bool]: + def confirm_saving_unsaved_work(self, cancelable: bool) -> Optional[bool]: """ Confirm saving unsaved work. @param cancelable: True to make dialog cancelable, False to make dialog non-cancelable @return: None if canceled, True if saving, False if discarding """ + Debug(self, f".confirm_saving_unsaved_work(cancelable={cancelable})") + buttons = QMessageBox.Save | QMessageBox.Discard | (QMessageBox.Cancel if cancelable else 0) messagebox = QMessageBox2( title="Project Changed", @@ -283,6 +254,8 @@ def confirm_close(self) -> None: Called by menu "Quit" action. Lets user choose to cancel closing or save / discard file if there is unsaved work. """ + Debug(self, ".confirm_close()") + if not self.config.get_synced(): choice = self.confirm_saving_unsaved_work(cancelable=True) if choice is None: @@ -296,19 +269,22 @@ def confirm_close(self) -> None: self.close() - def closeEvent(self, _event): + def closeEvent(self, _event: QCloseEvent) -> None: """ Handles close event. @param _event: Close event """ Debug(self, ".closeEvent()") + self.quit() def quit(self): """ Quits the application. """ + Debug(self, ".quit()") + if self.calculation_thread != QThread.currentThread(): Debug(self, ".quit()") if self.calculation_thread is not None: @@ -324,7 +300,7 @@ def quit(self): # Unregister exit handler (used by Assert_Dialog to exit gracefully) atexit.unregister(self.quit) - def keyPressEvent(self, event): + def keyPressEvent(self, event: QKeyEvent) -> None: """ Handles key press event. @@ -362,7 +338,7 @@ def keyPressEvent(self, event): # ------------------------------------------------------------------------------------------------------------------ - def on_config_changed(self): + def on_config_changed(self) -> None: """ Gets called when the configuration changed. """ @@ -377,10 +353,11 @@ def on_config_changed(self): # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - def file_open(self): + def file_open(self) -> None: """ Opens a project from an INI file. """ + Debug(self, ".file_open()") # Stop any running calculation if self.calculation_thread is not None: @@ -397,7 +374,7 @@ def file_open(self): if filename != "": - with ModelAccess(self.gui, recalculate=False): + with ModelAccess(self, recalculate=False): self.model.invalidate() if not self.config.get_synced(): @@ -429,18 +406,22 @@ def file_open(self): # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - def file_save(self): + def file_save(self) -> None: """ Saves the project to the currently set INI file. """ + Debug(self, ".file_save()") + self.config.save() # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - def file_save_as(self): + def file_save_as(self) -> None: """ Saves the project to an INI file. """ + Debug(self, ".file_save_as()") + action = QSaveAction( self, title="Save Project", @@ -455,10 +436,12 @@ def file_save_as(self): # ------------------------------------------------------------------------------------------------------------------ - def file_save_image(self): + def file_save_image(self) -> None: """ Saves the currently displayed scene to a PNG file. """ + Debug(self, ".file_save_image()") + action = QSaveAction( self, title="Save Image", @@ -472,10 +455,12 @@ def file_save_image(self): # ------------------------------------------------------------------------------------------------------------------ - def import_wire(self): + def import_wire(self) -> None: """ Imports wire points from a TXT file. """ + Debug(self, ".import_wire()") + filename, _chosen_extension = QFileDialog.getOpenFileName( parent=self, caption="Import Wire", @@ -497,10 +482,12 @@ def import_wire(self): } ) - def export_wire(self): + def export_wire(self) -> None: """ Exports wire points to a TXT file. """ + Debug(self, ".export_wire()") + if not self.model.wire.is_valid(): Assert_Dialog(False, "Attempting to export invalid wire") return diff --git a/magneticalc/MagnetiCalc_Data.py b/magneticalc/MagnetiCalc_Data.py index 1594d60..93378ea 100644 --- a/magneticalc/MagnetiCalc_Data.py +++ b/magneticalc/MagnetiCalc_Data.py @@ -39,13 +39,44 @@ def __init__(self, data: Dict) -> None: # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + def get_wire(self) -> Tuple[np.ndarray, np.ndarray, np.ndarray]: + """ + Gets the wire points as three separate 1D arrays (raveled). + + @return: x, y, z + """ + assert "wire_points" in self, "Sorry, there are no wire points in this data." + wire_points = self["wire_points"] + x, y, z = wire_points["x"], wire_points["y"], wire_points["z"] + return x, y, z + + def get_wire_list(self) -> List: + """ + Gets the wire points as a single list of 3D points (raveled). + + @return: List + """ + return list(zip(self.get_wire())) + + # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + def get_current(self) -> float: + """ + Gets the wire current. + """ + assert "wire_current" in self, "Sorry, there is no wire current in this data." + return self["wire_current"] + + # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + def get_dimension(self) -> Tuple[int, int, int]: """ Gets the sampling volume dimension. @return: nx, ny, nz """ - return self.data["fields"]["nx"], self.data["fields"]["ny"], self.data["fields"]["nz"] + fields = self._get_fields() + return fields["nx"], fields["ny"], fields["nz"] # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -56,7 +87,7 @@ def get_axes(self, reduce: bool = False) -> Tuple[np.ndarray, np.ndarray, np.nda @param reduce: Enable to reduce each raveled array to its minimal representation (axis ticks) @return: x, y, z """ - fields = self.data["fields"] + fields = self._get_fields() x, y, z = fields["x"], fields["y"], fields["z"] if reduce: @@ -74,11 +105,7 @@ def get_axes_list(self, **kwargs) -> List: # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - def get_field( - self, - field_type: str, - as_3d: bool = False - ) -> Tuple[np.ndarray, np.ndarray, np.ndarray]: + def get_field(self, field_type: str, as_3d: bool = False) -> Tuple[np.ndarray, np.ndarray, np.ndarray]: """ Gets the field as three separate 1D arrays (raveled). @@ -87,8 +114,10 @@ def get_field( """ assert field_type in ["A", "B"], "Invalid field type" - fields = self.data["fields"] - field_x, field_y, field_z = fields[field_type + "_x"], fields[field_type + "_y"], fields[field_type + "_z"] + fields = self._get_fields() + keys = [field_type + "_x", field_type + "_y", field_type + "_z"] + assert all([key in fields for key in keys]), f"Sorry, there is no {field_type}-field in this data." + field_x, field_y, field_z = [fields[key] for key in keys] if as_3d: shape_3d = self.get_dimension() @@ -130,6 +159,17 @@ def get_b_field_list(self, **kwargs) -> List: """ return list(zip(self.get_b_field(**kwargs))) + # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + def _get_fields(self) -> Dict: + """ + Gets the raw "fields" dictionary from the data. + + @return: Dictionary + """ + assert "fields" in self, "Sorry, there are no fields in this data." + return self["fields"] + # ------------------------------------------------------------------------------------------------------------------ def __getitem__(self, key): diff --git a/magneticalc/Menu.py b/magneticalc/Menu.py index 029c10d..2f4698a 100644 --- a/magneticalc/Menu.py +++ b/magneticalc/Menu.py @@ -16,9 +16,10 @@ # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +from __future__ import annotations +from functools import partial import webbrowser import qtawesome as qta -from functools import partial from PyQt5.QtCore import Qt from PyQt5.QtWidgets import QMenu, QAction, QActionGroup from magneticalc.About_Dialog import About_Dialog @@ -31,22 +32,28 @@ from magneticalc.Wire_Presets import Wire_Presets from magneticalc.Version import __URL__ +# Note: Workaround for type hinting +# noinspection PyUnreachableCode +if False: + from magneticalc.GUI import GUI + class Menu: """ Menu class. """ # List of available backends - Backends_List = { - "Backend: JIT": True, - "Backend: JIT + CUDA": Backend_CUDA.is_available() + Backends_Available_List = { + "Backend: JIT" : True, + "Backend: JIT + CUDA" : Backend_CUDA.is_available() } - def __init__(self, gui): + def __init__(self, gui: GUI) -> None: """ Creates the menu bar. @param gui: GUI """ + Debug(self, ": Init") self.gui = gui # List of checkboxes that are bound to configuration @@ -87,6 +94,7 @@ def __init__(self, gui): for preset in Wire_Presets.List: action = QAction(preset["id"], wire_menu) action.setIcon(qta.icon("mdi.vector-square")) + # noinspection PyUnresolvedReferences action.triggered.connect( partial( self.gui.sidebar_left.wire_widget.set_wire, @@ -107,12 +115,14 @@ def __init__(self, gui): self.import_wire_action = QAction("&Import TXT …") self.import_wire_action.setIcon(qta.icon("fa.folder")) + # noinspection PyUnresolvedReferences self.import_wire_action.triggered.connect(self.gui.import_wire) wire_menu.addAction(self.import_wire_action) self.export_wire_action = QAction("&Export TXT …") self.export_wire_action.setIcon(qta.icon("fa.save")) self.export_wire_action.setEnabled(False) + # noinspection PyUnresolvedReferences self.export_wire_action.triggered.connect(self.gui.export_wire) wire_menu.addAction(self.export_wire_action) @@ -127,10 +137,7 @@ def __init__(self, gui): view_menu.addSeparator() self.add_config_bound_checkbox("Show Colored Labels", "show_colored_labels", view_menu, self.gui.redraw) self.add_config_bound_checkbox( - "Show Gauss (Gs) instead of Tesla (T)", - "show_gauss", - view_menu, - self.on_show_gauss_changed + "Show Gauss (Gs) instead of Tesla (T)", "show_gauss", view_menu, self.on_show_gauss_changed ) view_menu.addSeparator() self.add_config_bound_checkbox("Show Coordinate System", "show_coordinate_system", view_menu, self.gui.redraw) @@ -147,12 +154,13 @@ def __init__(self, gui): self.options_backend_group.setExclusive(True) self.gui.blockSignals(True) self.backend_actions = [] - for i, item in enumerate(self.Backends_List.items()): + for i, item in enumerate(self.Backends_Available_List.items()): name, enabled = item action = QAction(name) self.backend_actions.append(action) action.setCheckable(True) action.setEnabled(enabled) + # noinspection PyUnresolvedReferences action.changed.connect(partial(self.on_backend_changed, i)) self.options_backend_group.addAction(action) options_menu.addAction(action) @@ -178,7 +186,7 @@ def __init__(self, gui): self.reinitialize() - def reinitialize(self): + def reinitialize(self) -> None: """ Re-initializes the menu. """ @@ -191,7 +199,7 @@ def reinitialize(self): if not Backend_CUDA.is_available(): self.gui.config.set_int("backend_type", BACKEND_JIT) - for i, name in enumerate(self.Backends_List): + for i, name in enumerate(self.Backends_Available_List): self.backend_actions[i].setChecked(self.gui.config.get_int("backend_type") == i) self.reinitialize_config_bound_checkboxes() @@ -225,7 +233,7 @@ def on_backend_changed(self, index) -> None: # ------------------------------------------------------------------------------------------------------------------ - def add_config_bound_checkbox(self, label: str, key: str, menu, callback): + def add_config_bound_checkbox(self, label: str, key: str, menu, callback) -> None: """ Creates a checkbox inside some menu. Checkbox state is bound to configuration. @@ -236,12 +244,13 @@ def add_config_bound_checkbox(self, label: str, key: str, menu, callback): """ checkbox = QAction(label, menu) checkbox.setCheckable(True) + # noinspection PyUnresolvedReferences checkbox.triggered.connect(partial(self.config_bound_checkbox_changed, key)) self.config_bound_checkboxes[key] = {"checkbox": checkbox, "callback_final": callback} checkbox.setChecked(self.gui.config.get_bool(key)) menu.addAction(checkbox) - def config_bound_checkbox_changed(self, key: str): + def config_bound_checkbox_changed(self, key: str) -> None: """ Handles change of checkbox state. @@ -250,7 +259,7 @@ def config_bound_checkbox_changed(self, key: str): self.gui.config.set_bool(key, self.config_bound_checkboxes[key]["checkbox"].isChecked()) self.config_bound_checkboxes[key]["callback_final"]() - def reinitialize_config_bound_checkboxes(self): + def reinitialize_config_bound_checkboxes(self) -> None: """ Re-initializes the configuration bound checkboxes. @@ -266,4 +275,6 @@ def update_wire_menu(self) -> None: """ Updates the wire menu. """ + Debug(self, ".update_wire_menu()") + self.export_wire_action.setEnabled(self.gui.model.wire.is_valid()) diff --git a/magneticalc/Metric.py b/magneticalc/Metric.py index bf2fbe5..206b01b 100644 --- a/magneticalc/Metric.py +++ b/magneticalc/Metric.py @@ -16,52 +16,61 @@ # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +from __future__ import annotations +from magneticalc.Norm_Types import * +from typing import Dict, List, Callable import numpy as np from numba import jit, prange from magneticalc.Assert_Dialog import Assert_Dialog +from magneticalc.ConditionalDecorator import ConditionalDecorator +from magneticalc.Config import get_jit_enabled from magneticalc.Debug import Debug -from magneticalc.Theme import Theme +# Note: Workaround for type hinting +# noinspection PyUnreachableCode +if False: + from magneticalc.Field import Field + from magneticalc.SamplingVolume import SamplingVolume -@jit(nopython=True, parallel=False) -def metric_norm(norm_id: str, vector) -> float: + +@ConditionalDecorator(get_jit_enabled(), jit, nopython=True, parallel=False) +def metric_norm(norm_type: int, vector: np.ndarray) -> float: """ Calculates the selected norm of some vector. Note: For JIT to work, this must be declared at the top level. - @param norm_id: Norm ID + @param norm_type: Norm type @param vector: 3D vector """ - # Note: These have to match the norm IDs defined in the Constraint class - if norm_id == "X": + if norm_type == NORM_TYPE_X: value = vector[0] - elif norm_id == "Y": + elif norm_type == NORM_TYPE_Y: value = vector[1] - elif norm_id == "Z": + elif norm_type == NORM_TYPE_Z: value = vector[2] - elif norm_id == "Radius X": + elif norm_type == NORM_TYPE_RADIUS: + value = np.sqrt(vector[0] ** 2 + vector[1] ** 2 + vector[2] ** 2) + elif norm_type == NORM_TYPE_RADIUS_X: value = np.abs(vector[0]) - elif norm_id == "Radius Y": + elif norm_type == NORM_TYPE_RADIUS_Y: value = np.abs(vector[1]) - elif norm_id == "Radius Z": + elif norm_type == NORM_TYPE_RADIUS_Z: value = np.abs(vector[2]) - elif norm_id == "Radius XY": + elif norm_type == NORM_TYPE_RADIUS_XY: value = np.sqrt(vector[0] ** 2 + vector[1] ** 2) - elif norm_id == "Radius XZ": + elif norm_type == NORM_TYPE_RADIUS_XZ: value = np.sqrt(vector[1] ** 2 + vector[2] ** 2) - elif norm_id == "Radius YZ": + elif norm_type == NORM_TYPE_RADIUS_YZ: value = np.sqrt(vector[2] ** 2 + vector[0] ** 2) - elif norm_id == "Radius": - value = np.sqrt(vector[0] ** 2 + vector[1] ** 2 + vector[2] ** 2) - elif norm_id == "Angle XY": + elif norm_type == NORM_TYPE_ANGLE_XY: value = (np.arctan2(vector[0], vector[1]) + np.pi) / np.pi / 2 - elif norm_id == "Angle XZ": + elif norm_type == NORM_TYPE_ANGLE_XZ: value = (np.arctan2(vector[0], vector[2]) + np.pi) / np.pi / 2 - elif norm_id == "Angle YZ": + elif norm_type == NORM_TYPE_ANGLE_YZ: value = (np.arctan2(vector[1], vector[2]) + np.pi) / np.pi / 2 - elif norm_id == "Divergence": + elif norm_type == NORM_TYPE_DIVERGENCE: # Invalid norm ID for metric_norm(); divergence must be calculated using metric_divergence() value = None else: @@ -71,8 +80,8 @@ def metric_norm(norm_id: str, vector) -> float: return value -@jit(nopython=True, parallel=False) -def metric_divergence(neighborhood_vectors, dL: float, polarity: int) -> float: +@ConditionalDecorator(get_jit_enabled(), jit, nopython=True, parallel=False) +def metric_divergence(neighborhood_vectors: np.ndarray, dL: float, polarity: int) -> float: """ Calculates the divergence of a sampling volume neighborhood. @@ -107,7 +116,7 @@ def metric_divergence(neighborhood_vectors, dL: float, polarity: int) -> float: return value -@jit(nopython=True, parallel=False) +@ConditionalDecorator(get_jit_enabled(), jit, nopython=True, parallel=False) def color_map_divergent(color_normalized: float) -> (float, float, float): """ Maps normalized value to color, divergent. @@ -122,7 +131,7 @@ def color_map_divergent(color_normalized: float) -> (float, float, float): return rgb_0 + (rgb_1 - rgb_0) * color_normalized -@jit(nopython=True, parallel=False) +@ConditionalDecorator(get_jit_enabled(), jit, nopython=True, parallel=False) def color_map_cyclic(color_normalized: float) -> (float, float, float): """ Maps normalized value to color, cyclic. @@ -153,7 +162,7 @@ class Metric: # ------------------------------------------------------------------------------------------------------------------ - def __init__(self, color_preset, alpha_preset): + def __init__(self, color_preset: Dict, alpha_preset: Dict) -> None: """ This class holds a pair of metric presets. Using these metric presets, colors (including alpha channel) and field limits are calculated. @@ -179,16 +188,16 @@ def is_valid(self) -> bool: self._colors is not None and \ self._limits is not None - def invalidate(self): + def invalidate(self) -> None: """ Resets data, hiding from display. """ - Debug(self, ".invalidate()", color=Theme.InvalidColor) + Debug(self, ".invalidate()") self._colors = None self._limits = None - def get_color_preset(self): + def get_color_preset(self) -> Dict: """ Returns color metric preset. @@ -196,7 +205,7 @@ def get_color_preset(self): """ return self._color_preset - def get_alpha_preset(self): + def get_alpha_preset(self) -> Dict: """ Returns alpha metric preset. @@ -204,7 +213,7 @@ def get_alpha_preset(self): """ return self._alpha_preset - def get_colors(self): + def get_colors(self) -> np.ndarray: """ Returns calculated colors. @@ -214,7 +223,7 @@ def get_colors(self): return self._colors - def get_limits(self): + def get_limits(self) -> Dict: """ Returns calculated limits. @@ -227,25 +236,30 @@ def get_limits(self): # ------------------------------------------------------------------------------------------------------------------ @staticmethod - @jit(nopython=True, parallel=True) - def _norm_worker(norm_id: str, vectors): + @ConditionalDecorator(get_jit_enabled(), jit, nopython=True, parallel=True) + def _norm_worker(norm_type: int, vectors: np.ndarray) -> np.ndarray: """ Calculates the norm values of a list of vectors. - @param norm_id: Norm ID + @param norm_type: Norm type @param vectors: Ordered list of 3D vectors @return: Norm values """ values = np.zeros(len(vectors)) for i in prange(len(vectors)): - values[i] = metric_norm(norm_id, vectors[i]) + values[i] = metric_norm(norm_type, vectors[i]) return values @staticmethod - @jit(nopython=True, parallel=True) - def _divergence_worker(sampling_volume_neighborhood_indices, vectors, dL: int, polarity): + @ConditionalDecorator(get_jit_enabled(), jit, nopython=True, parallel=True) + def _divergence_worker( + sampling_volume_neighborhood_indices: List[np.ndarray], + vectors: np.ndarray, + dL: int, + polarity: int + ) -> np.ndarray: """ Calculates the divergence values of a list of vectors. @@ -275,7 +289,7 @@ def _divergence_worker(sampling_volume_neighborhood_indices, vectors, dL: int, p return values @staticmethod - @jit(nopython=True, parallel=True) + @ConditionalDecorator(get_jit_enabled(), jit, nopython=True, parallel=True) def _normalize_worker( color_map_id: str, color_is_log: bool, @@ -283,11 +297,11 @@ def _normalize_worker( color_norm_min: float, color_norm_max: float, alpha_is_log: bool, - alpha_norm_values, + alpha_norm_values: np.ndarray, alpha_norm_min: float, alpha_norm_max: float, - colors - ): + colors: np.ndarray + ) -> np.ndarray: """ Normalizes color and alpha norm values, populates final color values. @@ -355,7 +369,7 @@ def _normalize_worker( return colors - def recalculate(self, sampling_volume, field, progress_callback) -> bool: + def recalculate(self, sampling_volume: SamplingVolume, field: Field, progress_callback: Callable) -> bool: """ Recalculates color and alpha values for field. @@ -374,7 +388,7 @@ def recalculate(self, sampling_volume, field, progress_callback) -> bool: dL = Metric.LengthScale / sampling_volume.get_resolution() # Calculate color metric values - if self._color_preset["norm_id"] == "Divergence": + if self._color_preset["norm_type"] == NORM_TYPE_DIVERGENCE: # Calculate divergence color_norm_values = self._divergence_worker( sampling_volume.get_neighbor_indices(), @@ -385,14 +399,14 @@ def recalculate(self, sampling_volume, field, progress_callback) -> bool: else: # Calculate other norm color_norm_values = self._norm_worker( - self._color_preset["norm_id"], + self._color_preset["norm_type"], field.get_vectors() ) progress_callback(25) # Calculate alpha metric values - if self._alpha_preset["norm_id"] == "Divergence": + if self._alpha_preset["norm_type"] == NORM_TYPE_DIVERGENCE: # Calculate divergence alpha_norm_values = self._divergence_worker( sampling_volume.get_neighbor_indices(), @@ -403,7 +417,7 @@ def recalculate(self, sampling_volume, field, progress_callback) -> bool: else: # Calculate other norm alpha_norm_values = self._norm_worker( - self._alpha_preset["norm_id"], + self._alpha_preset["norm_type"], field.get_vectors() ) @@ -486,8 +500,8 @@ def recalculate(self, sampling_volume, field, progress_callback) -> bool: # ------------------------------------------------------------------------------------------------------------------ @staticmethod - @jit(nopython=True, parallel=True) - def boost_colors(boost: float, direction: float, colors): + @ConditionalDecorator(get_jit_enabled(), jit, nopython=True, parallel=True) + def boost_colors(boost: float, direction: float, colors: np.ndarray) -> np.ndarray: """ "Boosts" an array of color values. diff --git a/magneticalc/Metric_Presets.py b/magneticalc/Metric_Presets.py index e6fbb67..f7d1ffc 100644 --- a/magneticalc/Metric_Presets.py +++ b/magneticalc/Metric_Presets.py @@ -16,6 +16,9 @@ # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +from magneticalc.Norm_Types import * +from typing import Optional, Dict + class Metric_Presets: """ Metric_Presets class. """ @@ -23,17 +26,7 @@ class Metric_Presets: # Metric value: Magnitude in XYZ-space (linear) Magnitude = { "id" : "Magnitude", - "norm_id" : "Radius", - "polarity" : 0, # currently only used for divergence - "is_log" : False, - "is_angle" : False, - "colormap" : 0 # divergent - } - - # Metric value: Magnitude in XY-plane (linear) - MagnitudeXY = { - "id" : "Magnitude XY", - "norm_id" : "Radius XY", + "norm_type" : NORM_TYPE_RADIUS, "polarity" : 0, # currently only used for divergence "is_log" : False, "is_angle" : False, @@ -43,7 +36,7 @@ class Metric_Presets: # Metric value: Magnitude in X-direction (linear) MagnitudeX = { "id" : "Magnitude X", - "norm_id" : "Radius X", + "norm_type" : NORM_TYPE_RADIUS_X, "polarity" : 0, # currently only used for divergence "is_log" : False, "is_angle" : False, @@ -53,7 +46,7 @@ class Metric_Presets: # Metric value: Magnitude in Y-direction (linear) MagnitudeY = { "id" : "Magnitude Y", - "norm_id" : "Radius Y", + "norm_type" : NORM_TYPE_RADIUS_Y, "polarity" : 0, # currently only used for divergence "is_log" : False, "is_angle" : False, @@ -63,7 +56,17 @@ class Metric_Presets: # Metric value: Magnitude in Z-direction (linear) MagnitudeZ = { "id" : "Magnitude Z", - "norm_id" : "Radius Z", + "norm_type" : NORM_TYPE_RADIUS_Z, + "polarity" : 0, # currently only used for divergence + "is_log" : False, + "is_angle" : False, + "colormap" : 0 # divergent + } + + # Metric value: Magnitude in XY-plane (linear) + MagnitudeXY = { + "id" : "Magnitude XY", + "norm_type" : NORM_TYPE_RADIUS_XY, "polarity" : 0, # currently only used for divergence "is_log" : False, "is_angle" : False, @@ -73,7 +76,7 @@ class Metric_Presets: # Metric value: Magnitude in XZ-plane (linear) MagnitudeXZ = { "id" : "Magnitude XZ", - "norm_id" : "Radius XZ", + "norm_type" : NORM_TYPE_RADIUS_XZ, "polarity" : 0, # currently only used for divergence "is_log" : False, "is_angle" : False, @@ -83,7 +86,7 @@ class Metric_Presets: # Metric value: Magnitude in YZ-plane (linear) MagnitudeYZ = { "id" : "Magnitude YZ", - "norm_id" : "Radius YZ", + "norm_type" : NORM_TYPE_RADIUS_YZ, "polarity" : 0, # currently only used for divergence "is_log" : False, "is_angle" : False, @@ -93,7 +96,7 @@ class Metric_Presets: # Metric preset: Unipolar Divergence (linear) Divergence = { "id" : "Divergence", - "norm_id" : "Divergence", + "norm_type" : NORM_TYPE_DIVERGENCE, "polarity" : 0, "is_log" : False, "is_angle" : False, @@ -103,7 +106,7 @@ class Metric_Presets: # Metric preset: Negative Divergence (linear) NegDivergence = { "id" : "Divergence –", - "norm_id" : "Divergence", + "norm_type" : NORM_TYPE_DIVERGENCE, "polarity" : -1, "is_log" : False, "is_angle" : False, @@ -113,7 +116,7 @@ class Metric_Presets: # Metric preset: Positive Divergence (linear) PosDivergence = { "id" : "Divergence +", - "norm_id" : "Divergence", + "norm_type" : NORM_TYPE_DIVERGENCE, "polarity" : +1, "is_log" : False, "is_angle" : False, @@ -123,7 +126,7 @@ class Metric_Presets: # Metric value: Magnitude in XYZ-space (logarithmic) LogMagnitude = { "id" : "Log Magnitude", - "norm_id" : "Radius", + "norm_type" : NORM_TYPE_RADIUS, "polarity" : 0, # currently only used for divergence "is_log" : True, "is_angle" : False, @@ -133,7 +136,7 @@ class Metric_Presets: # Metric value: Magnitude in X-direction (logarithmic) LogMagnitudeX = { "id" : "Log Magnitude X", - "norm_id" : "Radius X", + "norm_type" : NORM_TYPE_RADIUS_X, "polarity" : 0, # currently only used for divergence "is_log" : True, "is_angle" : False, @@ -143,7 +146,7 @@ class Metric_Presets: # Metric value: Magnitude in Y-direction (logarithmic) LogMagnitudeY = { "id" : "Log Magnitude Y", - "norm_id" : "Radius Y", + "norm_type" : NORM_TYPE_RADIUS_Y, "polarity" : 0, # currently only used for divergence "is_log" : True, "is_angle" : False, @@ -153,7 +156,7 @@ class Metric_Presets: # Metric value: Magnitude in Z-direction (logarithmic) LogMagnitudeZ = { "id" : "Log Magnitude Z", - "norm_id" : "Radius Z", + "norm_type" : NORM_TYPE_RADIUS_Z, "polarity" : 0, # currently only used for divergence "is_log" : True, "is_angle" : False, @@ -163,7 +166,7 @@ class Metric_Presets: # Metric value: Magnitude in XY-plane (logarithmic) LogMagnitudeXY = { "id" : "Log Magnitude XY", - "norm_id" : "Radius XY", + "norm_type" : NORM_TYPE_RADIUS_XY, "polarity" : 0, # currently only used for divergence "is_log" : True, "is_angle" : False, @@ -173,7 +176,7 @@ class Metric_Presets: # Metric value: Magnitude in XZ-plane (logarithmic) LogMagnitudeXZ = { "id" : "Log Magnitude XZ", - "norm_id" : "Radius XZ", + "norm_type" : NORM_TYPE_RADIUS_XZ, "polarity" : 0, # currently only used for divergence "is_log" : True, "is_angle" : False, @@ -183,7 +186,7 @@ class Metric_Presets: # Metric preset: Magnitude in YZ-plane (logarithmic) LogMagnitudeYZ = { "id" : "Log Magnitude YZ", - "norm_id" : "Radius YZ", + "norm_type" : NORM_TYPE_RADIUS_YZ, "polarity" : 0, # currently only used for divergence "is_log" : True, "is_angle" : False, @@ -193,7 +196,7 @@ class Metric_Presets: # Metric preset: Unipolar Divergence (logarithmic) LogDivergence = { "id" : "Log Divergence", - "norm_id" : "Divergence", + "norm_type" : NORM_TYPE_DIVERGENCE, "polarity" : 0, "is_log" : True, "is_angle" : False, @@ -203,7 +206,7 @@ class Metric_Presets: # Metric preset: Positive Divergence (logarithmic) PosLogDivergence = { "id" : "Log Divergence +", - "norm_id" : "Divergence", + "norm_type" : NORM_TYPE_DIVERGENCE, "polarity" : +1, "is_log" : True, "is_angle" : False, @@ -213,7 +216,7 @@ class Metric_Presets: # Metric preset: Negative Divergence (logarithmic) NegLogDivergence = { "id" : "Log Divergence –", - "norm_id" : "Divergence", + "norm_type" : NORM_TYPE_DIVERGENCE, "polarity" : -1, "is_log" : True, "is_angle" : False, @@ -223,7 +226,7 @@ class Metric_Presets: # Metric preset: Angle in XY-plane AngleXY = { "id" : "Angle XY", - "norm_id" : "Angle XY", + "norm_type" : NORM_TYPE_ANGLE_XY, "polarity" : 0, # currently only used for divergence "is_log" : False, "is_angle" : True, @@ -233,7 +236,7 @@ class Metric_Presets: # Metric preset: Angle in XZ-plane AngleXZ = { "id" : "Angle XZ", - "norm_id" : "Angle XZ", + "norm_type" : NORM_TYPE_ANGLE_XZ, "polarity" : 0, # currently only used for divergence "is_log" : False, "is_angle" : True, @@ -243,7 +246,7 @@ class Metric_Presets: # Metric preset: Angle in YZ-plane AngleYZ = { "id" : "Angle YZ", - "norm_id" : "Angle YZ", + "norm_type" : NORM_TYPE_ANGLE_YZ, "polarity" : 0, # currently only used for divergence "is_log" : False, "is_angle" : True, @@ -282,7 +285,7 @@ class Metric_Presets: # ------------------------------------------------------------------------------------------------------------------ @staticmethod - def get_by_id(_id_: str): + def get_by_id(_id_: str) -> Optional[Dict]: """ Selects a preset by name. diff --git a/magneticalc/Metric_Widget.py b/magneticalc/Metric_Widget.py index 5530a43..a226861 100644 --- a/magneticalc/Metric_Widget.py +++ b/magneticalc/Metric_Widget.py @@ -16,19 +16,25 @@ # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +from __future__ import annotations import numpy as np import qtawesome as qta from si_prefix import si_format from PyQt5.QtCore import Qt, QSize from PyQt5.QtWidgets import QWidget, QHBoxLayout, QComboBox, QLabel -from magneticalc.Debug import Debug -from magneticalc.QIconLabel import QIconLabel from magneticalc.QGroupBox2 import QGroupBox2 from magneticalc.QHLine import QHLine +from magneticalc.QIconLabel import QIconLabel +from magneticalc.Debug import Debug from magneticalc.Metric import Metric from magneticalc.Metric_Presets import Metric_Presets from magneticalc.ModelAccess import ModelAccess +# Note: Workaround for type hinting +# noinspection PyUnreachableCode +if False: + from magneticalc.GUI import GUI + class Metric_Widget(QGroupBox2): """ Metric_Widget class. """ @@ -36,14 +42,14 @@ class Metric_Widget(QGroupBox2): # Formatting settings ValuePrecision = 1 - def __init__(self, gui): + def __init__(self, gui: GUI) -> None: """ Populates the widget. @param gui: GUI """ QGroupBox2.__init__(self, "Metric") - + Debug(self, ": Init") self.gui = gui # -------------------------------------------------------------------------------------------------------------- @@ -52,6 +58,7 @@ def __init__(self, gui): self.color_metric_combobox = QComboBox() for i, preset in enumerate(Metric_Presets.List): self.color_metric_combobox.addItem(preset["id"]) + # noinspection PyUnresolvedReferences self.color_metric_combobox.currentIndexChanged.connect( lambda: self.set_metric(color_preset=Metric_Presets.get_by_id(self.color_metric_combobox.currentText())) ) @@ -86,6 +93,7 @@ def __init__(self, gui): # Using angle metric for alpha transparency is discouraged and is not available in the combobox anymore. if not preset["is_angle"]: self.alpha_metric_combobox.addItem(preset["id"]) + # noinspection PyUnresolvedReferences self.alpha_metric_combobox.currentIndexChanged.connect( lambda: self.set_metric(alpha_preset=Metric_Presets.get_by_id(self.alpha_metric_combobox.currentText())) ) @@ -111,7 +119,7 @@ def __init__(self, gui): self.reinitialize() - def reinitialize(self): + def reinitialize(self) -> None: """ Re-initializes the widget. """ @@ -141,7 +149,7 @@ def set_metric( recalculate: bool = True, update_labels: bool = True, invalidate_self: bool = True - ): + ) -> None: """ Sets the metric. This will overwrite the currently set metric in the model. Any parameter may be left set to None in order to load its default value. @@ -155,6 +163,8 @@ def set_metric( if self.signalsBlocked(): return + Debug(self, ".set_metric()") + with ModelAccess(self.gui, recalculate): # Note: Not using self.gui.config.write_read_str here because we're translating between strings and presets @@ -206,10 +216,12 @@ def set_metric( ); """ - def update_labels(self): + def update_labels(self) -> None: """ Updates the labels. """ + Debug(self, ".update_labels()") + if self.gui.model.metric.is_valid(): limits = self.gui.model.metric.get_limits() diff --git a/magneticalc/Model.py b/magneticalc/Model.py index b778417..9bbafa6 100644 --- a/magneticalc/Model.py +++ b/magneticalc/Model.py @@ -16,12 +16,22 @@ # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -from typing import Optional, Dict +from __future__ import annotations +from typing import Optional, Dict, Any, Callable +from sty import fg from magneticalc.Debug import Debug -from magneticalc.Field import Field -from magneticalc.Field_Types import FIELD_TYPES_STR +from magneticalc.Field_Types import field_type_to_str from magneticalc.ModelAccess import ModelAccess -from magneticalc.Theme import Theme + +# Note: Workaround for type hinting +# noinspection PyUnreachableCode +if False: + from magneticalc.Field import Field + from magneticalc.GUI import GUI + from magneticalc.Metric import Metric + from magneticalc.Parameters import Parameters + from magneticalc.SamplingVolume import SamplingVolume + from magneticalc.Wire import Wire class Model: @@ -37,14 +47,16 @@ class Model: Invalidating the currently selected field also invalidates all the other cached fields. """ - def __init__(self, gui): + # Used by L{Debug} + DebugColor = fg.yellow + + def __init__(self, gui: GUI) -> None: """ Initializes the model. @param gui: GUI """ Debug(self, ": Init") - self.gui = gui self.wire = None # Set in L{set_wire} via L{Wire_Widget} @@ -89,7 +101,7 @@ def get_valid_field(self, field_type: int) -> Optional[Field]: # ------------------------------------------------------------------------------------------------------------------ @staticmethod - def safe_valid(obj) -> bool: + def safe_valid(obj: Any) -> bool: """ Safely checks the validity state of a possibly uninitialized object within the model. """ @@ -130,7 +142,7 @@ def invalidate( do_field: bool = False, do_metric: bool = False, do_parameters: bool = False - ): + ) -> None: """ Invalidates multiple modules at once, in descending order of hierarchy. @@ -140,6 +152,8 @@ def invalidate( @param do_metric: Enable to invalidate metric @param do_parameters: Enable to invalidate parameters """ + Debug(self, ".invalidate()") + if do_parameters: if self.parameters is not None: if self.parameters.is_valid(): @@ -157,7 +171,7 @@ def invalidate( for field_type, field in self._field_cache.items(): if field.is_valid(): field.invalidate() - Debug(self, f".invalidate(): Invalidated {FIELD_TYPES_STR[field_type]}", color=Theme.InvalidColor) + Debug(self, f".invalidate(): Invalidated {field_type_to_str(field_type)}") did_field_invalidation = True if did_field_invalidation: self.on_field_invalid() @@ -174,13 +188,15 @@ def invalidate( self.wire.invalidate() self.on_wire_invalid() - def set_wire(self, wire, invalidate_self: bool): + def set_wire(self, wire: Wire, invalidate_self: bool) -> None: """ Sets the wire. @param wire: Wire @param invalidate_self: Enable to invalidate the old object before setting a new one """ + Debug(self, ".set_wire()") + with ModelAccess(self.gui, recalculate=False): self.invalidate( @@ -192,13 +208,15 @@ def set_wire(self, wire, invalidate_self: bool): ) self.wire = wire - def set_sampling_volume(self, sampling_volume, invalidate_self: bool): + def set_sampling_volume(self, sampling_volume: SamplingVolume, invalidate_self: bool) -> None: """ Sets the sampling volume. @param sampling_volume: Sampling volume @param invalidate_self: Enable to invalidate the old object before setting a new one """ + Debug(self, ".set_sampling_volume()") + with ModelAccess(self.gui, recalculate=False): self.invalidate( @@ -209,13 +227,15 @@ def set_sampling_volume(self, sampling_volume, invalidate_self: bool): ) self.sampling_volume = sampling_volume - def set_field(self, field, invalidate_self: bool): + def set_field(self, field: Field, invalidate_self: bool) -> None: """ Sets the field. @param field: Field @param invalidate_self: Enable to invalidate the old object (including the cache) before setting a new one """ + Debug(self, ".set_field()") + with ModelAccess(self.gui, recalculate=False): self.invalidate( @@ -225,13 +245,15 @@ def set_field(self, field, invalidate_self: bool): ) self.field = field - def set_metric(self, metric, invalidate_self: bool): + def set_metric(self, metric: Metric, invalidate_self: bool) -> None: """ Sets the metric. @param metric: Metric @param invalidate_self: Enable to invalidate the old object before setting a new one """ + Debug(self, ".set_metric()") + with ModelAccess(self.gui, recalculate=False): self.invalidate( @@ -240,13 +262,15 @@ def set_metric(self, metric, invalidate_self: bool): ) self.metric = metric - def set_parameters(self, parameters, invalidate_self: bool): + def set_parameters(self, parameters: Parameters, invalidate_self: bool) -> None: """ Sets the parameters. @param parameters: Parameters @param invalidate_self: Enable to invalidate the old object before setting a new one """ + Debug(self, ".set_parameters()") + with ModelAccess(self.gui, recalculate=False): self.invalidate( @@ -256,29 +280,31 @@ def set_parameters(self, parameters, invalidate_self: bool): # ------------------------------------------------------------------------------------------------------------------ - def calculate_wire(self, progress_callback): + def calculate_wire(self, progress_callback: Callable) -> None: """ Calculates the wire. @param progress_callback: Progress callback @return: True if successful, False if interrupted """ - Debug(self, ".calculate_wire()", color=Theme.PrimaryColor) + Debug(self, ".calculate_wire()") + self.invalidate(do_sampling_volume=True, do_field=True, do_metric=True) return self.wire.recalculate(progress_callback) - def calculate_sampling_volume(self, progress_callback): + def calculate_sampling_volume(self, progress_callback: Callable) -> bool: """ Calculates the sampling volume. @param progress_callback: Progress callback @return: True if successful, False if interrupted """ - Debug(self, ".calculate_sampling_volume()", color=Theme.PrimaryColor) + Debug(self, ".calculate_sampling_volume()") + self.invalidate(do_field=True, do_metric=True) return self.sampling_volume.recalculate(progress_callback) - def calculate_field(self, progress_callback, num_cores: int): + def calculate_field(self, progress_callback: Callable, num_cores: int) -> bool: """ Calculates the field. @@ -286,98 +312,121 @@ def calculate_field(self, progress_callback, num_cores: int): @param num_cores: Number of CPU cores to use @return: True if successful, False if interrupted """ - Debug(self, f".calculate_field(num_cores={num_cores})", color=Theme.PrimaryColor) + Debug(self, f".calculate_field(num_cores={num_cores})") + self.invalidate(do_metric=True) return self.field.recalculate(self.wire, self.sampling_volume, progress_callback, num_cores) - def calculate_metric(self, progress_callback): + def calculate_metric(self, progress_callback: Callable) -> bool: """ Calculates the metric. @param progress_callback: Progress callback @return: True (currently non-interruptable) """ - Debug(self, ".calculate_metric()", color=Theme.PrimaryColor) + Debug(self, ".calculate_metric()") + return self.metric.recalculate(self.sampling_volume, self.field, progress_callback) - def calculate_parameters(self, progress_callback): + def calculate_parameters(self, progress_callback: Callable) -> bool: """ Calculates the parameters. @param progress_callback: Progress callback @return: True (currently non-interruptable) """ - Debug(self, ".calculate_parameters()", color=Theme.PrimaryColor) + Debug(self, ".calculate_parameters()") + return self.parameters.recalculate(self.wire, self.sampling_volume, self.field, progress_callback) # ------------------------------------------------------------------------------------------------------------------ - def on_wire_valid(self): + def on_wire_valid(self) -> None: """ Gets called when the wire was successfully calculated. """ + Debug(self, ".on_wire_valid()") + self.gui.sidebar_left.wire_widget.update_labels() self.gui.menu.update_wire_menu() - def on_sampling_volume_valid(self): + def on_sampling_volume_valid(self) -> None: """ Gets called when the sampling volume was successfully calculated. """ + Debug(self, ".on_sampling_volume_valid()") + self.gui.sidebar_left.sampling_volume_widget.update() self.gui.sidebar_right.display_widget.update() self.gui.sidebar_right.display_widget.prevent_excessive_field_labels(choice=False) - def on_field_valid(self): + def on_field_valid(self) -> None: """ Gets called when the field was successfully calculated. """ + Debug(self, ".on_field_valid()") + self.gui.sidebar_right.field_widget.update() - def on_metric_valid(self): + def on_metric_valid(self) -> None: """ Gets called when the metric was successfully calculated. """ + Debug(self, ".on_metric_valid()") + self.gui.sidebar_right.metric_widget.update_labels() # The field labels are now created on-demand inside VispyCanvas.redraw() # self.gui.vispy_canvas.create_field_labels() - def on_parameters_valid(self): + def on_parameters_valid(self) -> None: """ Gets called when the parameters were successfully calculated. """ + Debug(self, ".on_parameters_valid()") + self.gui.sidebar_right.parameters_widget.update_labels() # ------------------------------------------------------------------------------------------------------------------ - def on_wire_invalid(self): + def on_wire_invalid(self) -> None: """ Gets called when the wire was invalidated. """ + Debug(self, ".on_wire_invalid()") + self.gui.sidebar_left.wire_widget.update_labels() self.gui.menu.update_wire_menu() - def on_sampling_volume_invalid(self): + def on_sampling_volume_invalid(self) -> None: """ Gets called when the sampling volume was invalidated. """ + Debug(self, ".on_sampling_volume_invalid()") + self.gui.sidebar_left.sampling_volume_widget.update() - def on_field_invalid(self): + def on_field_invalid(self) -> None: """ Gets called when the field was invalidated. """ + Debug(self, ".on_field_invalid()") + self.gui.sidebar_right.field_widget.update() - def on_metric_invalid(self): + def on_metric_invalid(self) -> None: """ Gets called when the metric was invalidated. """ + Debug(self, ".on_metric_invalid()") + self.gui.sidebar_right.metric_widget.update_labels() self.gui.vispy_canvas.delete_field_labels() - def on_parameters_invalid(self): + def on_parameters_invalid(self) -> None: """ Gets called when the parameters were invalidated. """ + Debug(self, ".on_parameters_invalid()") + self.gui.sidebar_right.parameters_widget.update_labels() diff --git a/magneticalc/ModelAccess.py b/magneticalc/ModelAccess.py index 212971b..71e9406 100644 --- a/magneticalc/ModelAccess.py +++ b/magneticalc/ModelAccess.py @@ -16,18 +16,25 @@ # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -from magneticalc.Assert_Dialog import Assert_Dialog +from __future__ import annotations +from types import TracebackType +from typing import Optional, Type +from sty import fg from magneticalc.Debug import Debug -from magneticalc.Theme import Theme + +# Note: Workaround for type hinting +# noinspection PyUnreachableCode +if False: + from magneticalc.GUI import GUI class ModelAccess: """ Model access class. """ # Used by L{Debug} - DebugColor = "#0000e5" + DebugColor = fg.yellow - def __init__(self, gui, recalculate: bool): + def __init__(self, gui: GUI, recalculate: bool) -> None: """ Initializes model access. @@ -35,26 +42,32 @@ def __init__(self, gui, recalculate: bool): @param recalculate: Enable to recalculate upon exiting the context """ self.gui = gui - self.recalculate = recalculate + self._recalculate = recalculate - def __enter__(self): + def __enter__(self) -> None: """ Entering the context kills possibly running calculation if recalculation is enabled. """ Debug(self, ".enter()") - if self.recalculate: + if self._recalculate: if self.gui.calculation_thread is not None: self.gui.interrupt_calculation() - def __exit__(self, _exc_type, _exc_val, _exc_tb): + def __exit__( + self, + _exc_type: Optional[Type[BaseException]], + _exc_val: Optional[BaseException], + _exc_tb: Optional[TracebackType] + ) -> None: """ Leaving the context starts recalculation if enabled; otherwise, just redraw. """ - Debug(self, f".exit()") - Debug(self, f": NOW VALID: {'None' if str(self.gui.model) == '' else self.gui.model}") + Debug(self, ".exit()") + + Debug(self, f": Valid: {'None' if str(self.gui.model) == '' else self.gui.model}") - if self.recalculate: + if self._recalculate: if self.gui.config.get_bool("auto_calculation"): self.gui.recalculate() else: diff --git a/magneticalc/Norm_Types.py b/magneticalc/Norm_Types.py new file mode 100644 index 0000000..d228285 --- /dev/null +++ b/magneticalc/Norm_Types.py @@ -0,0 +1,74 @@ +""" Norm_Types module. """ + +# ISC License +# +# Copyright (c) 2020–2021, Paul Wilhelm, M. Sc. +# +# Permission to use, copy, modify, and/or distribute this software for any +# purpose with or without fee is hereby granted, provided that the above +# copyright notice and this permission notice appear in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +from typing import Optional + + +NORM_TYPE_X = 0 +NORM_TYPE_Y = 1 +NORM_TYPE_Z = 2 +NORM_TYPE_RADIUS = 3 +NORM_TYPE_RADIUS_X = 4 +NORM_TYPE_RADIUS_Y = 5 +NORM_TYPE_RADIUS_Z = 6 +NORM_TYPE_RADIUS_XY = 7 +NORM_TYPE_RADIUS_XZ = 8 +NORM_TYPE_RADIUS_YZ = 9 +NORM_TYPE_ANGLE_XY = 10 +NORM_TYPE_ANGLE_XZ = 11 +NORM_TYPE_ANGLE_YZ = 12 +NORM_TYPE_DIVERGENCE = 13 + + +Norm_Types_Str_Map = { + NORM_TYPE_X : "X", + NORM_TYPE_Y : "Y", + NORM_TYPE_Z : "Z", + NORM_TYPE_RADIUS : "Radius", + NORM_TYPE_RADIUS_X : "Radius X", + NORM_TYPE_RADIUS_Y : "Radius Y", + NORM_TYPE_RADIUS_Z : "Radius Z", + NORM_TYPE_RADIUS_XY : "Radius XY", + NORM_TYPE_RADIUS_XZ : "Radius XZ", + NORM_TYPE_RADIUS_YZ : "Radius YZ", + NORM_TYPE_ANGLE_XY : "Angle XY", + NORM_TYPE_ANGLE_XZ : "Angle XZ", + NORM_TYPE_ANGLE_YZ : "Angle YZ", + NORM_TYPE_DIVERGENCE : "Divergence", +} + + +def norm_type_to_str(norm_type: int) -> Optional[str]: + """ + Converts a norm type to a norm string. + + @param norm_type: Norm type + @return: Norm string, or None if norm type is invalid + """ + return Norm_Types_Str_Map.get(norm_type, None) + + +def norm_type_from_str(norm_str: str) -> Optional[int]: + """ + Converts a norm string to a norm type. + + @param norm_str: Norm string + @return Norm type, or None if norm string is invalid + """ + result = [_norm_type for _norm_type, _norm_str in Norm_Types_Str_Map.items() if _norm_str == norm_str] + return result[0] if len(result) == 1 else None diff --git a/magneticalc/OverridePadding_Dialog.py b/magneticalc/OverridePadding_Dialog.py index d4d19f7..1817c4c 100644 --- a/magneticalc/OverridePadding_Dialog.py +++ b/magneticalc/OverridePadding_Dialog.py @@ -16,12 +16,19 @@ # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +from __future__ import annotations from magneticalc.QDialog2 import QDialog2 from magneticalc.QHBoxLayout2 import QHBoxLayout2 from magneticalc.QLabel2 import QLabel2 from magneticalc.QSpinBox2 import QSpinBox2 +from magneticalc.Debug import Debug from magneticalc.Theme import Theme +# Note: Workaround for type hinting +# noinspection PyUnreachableCode +if False: + from magneticalc.GUI import GUI + class OverridePadding_Dialog(QDialog2): """ OverridePadding_Dialog class. """ @@ -29,20 +36,21 @@ class OverridePadding_Dialog(QDialog2): # Spinbox limits BoundsRange = [-1000, +1000] - def __init__(self, gui) -> None: + def __init__(self, gui: GUI) -> None: """ Initializes "Override Padding" dialog. @param gui: GUI """ QDialog2.__init__(self, title="Override Padding", width=420) + Debug(self, ": Init") self.gui = gui self.addWidget( - QLabel2("Please specify the sampling volume bounding box", bold=True, color=Theme.PrimaryColor) + QLabel2("Please specify the sampling volume bounding box", bold=True, color=Theme.MainColor) ) self.addSpacing(8) - self.addLayout(QHBoxLayout2(QLabel2("Units:", fixed=True), QLabel2("cm", bold=True))) + self.addLayout(QHBoxLayout2(QLabel2("Units:", expand=False), QLabel2("cm", bold=True))) self.addSpacing(16) bounding_box = self.gui.config.get_points("sampling_volume_bounding_box") @@ -54,7 +62,7 @@ def __init__(self, gui) -> None: for i in range(3): text = " ≤ " + ["X", "Y", "Z"][i] + " ≤ " self.addLayout( - QHBoxLayout2(self.bounds_min_spinbox[i], QLabel2(text, fixed=True), self.bounds_max_spinbox[i]) + QHBoxLayout2(self.bounds_min_spinbox[i], QLabel2(text, expand=False), self.bounds_max_spinbox[i]) ) self.addSpacing(16) diff --git a/magneticalc/Parameters.py b/magneticalc/Parameters.py index ecffd42..3fec010 100644 --- a/magneticalc/Parameters.py +++ b/magneticalc/Parameters.py @@ -16,19 +16,29 @@ # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +from __future__ import annotations +from typing import Callable import numpy as np from numba import jit, prange +from magneticalc.ConditionalDecorator import ConditionalDecorator +from magneticalc.Config import get_jit_enabled from magneticalc.Constants import Constants from magneticalc.Debug import Debug from magneticalc.Field_Types import A_FIELD, B_FIELD from magneticalc.Metric import Metric -from magneticalc.Theme import Theme + +# Note: Workaround for type hinting +# noinspection PyUnreachableCode +if False: + from magneticalc.Field import Field + from magneticalc.SamplingVolume import SamplingVolume + from magneticalc.Wire import Wire class Parameters: """ Parameters class. """ - def __init__(self): + def __init__(self) -> None: """ Initializes parameters class. """ @@ -48,11 +58,11 @@ def is_valid(self) -> bool: return \ self._magnetic_dipole_moment is not None - def invalidate(self): + def invalidate(self) -> None: """ Resets data, hiding from display. """ - Debug(self, ".invalidate()", color=Theme.InvalidColor) + Debug(self, ".invalidate()") self._energy = None self._self_inductance = None @@ -84,7 +94,7 @@ def get_magnetic_dipole_moment(self) -> float: # ------------------------------------------------------------------------------------------------------------------ - def get_squared_field(self, sampling_volume, field) -> float: + def get_squared_field(self, sampling_volume: SamplingVolume, field: Field) -> float: """ Returns the "squared" field scalar. @@ -95,8 +105,8 @@ def get_squared_field(self, sampling_volume, field) -> float: return self._get_squared_field_worker(sampling_volume.get_permeabilities(), field.get_vectors()) @staticmethod - @jit(nopython=True, parallel=True) - def _get_squared_field_worker(sampling_volume_permeabilities, field_vectors) -> float: + @ConditionalDecorator(get_jit_enabled(), jit, nopython=True, parallel=True) + def _get_squared_field_worker(sampling_volume_permeabilities: np.ndarray, field_vectors: np.ndarray) -> float: """ Returns the "squared" field scalar. @@ -111,7 +121,7 @@ def _get_squared_field_worker(sampling_volume_permeabilities, field_vectors) -> # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - def _get_magnetic_dipole_moment(self, wire, length_scale: float) -> float: + def _get_magnetic_dipole_moment(self, wire: Wire, length_scale: float) -> float: """ Returns the magnetic dipole moment scalar. @@ -125,8 +135,12 @@ def _get_magnetic_dipole_moment(self, wire, length_scale: float) -> float: return np.abs(wire.get_dc() * np.linalg.norm(vector) / 2) @staticmethod - @jit(nopython=True, parallel=True) - def _get_magnetic_dipole_moment_worker(elements_center, elements_direction, length_scale: float): + @ConditionalDecorator(get_jit_enabled(), jit, nopython=True, parallel=True) + def _get_magnetic_dipole_moment_worker( + elements_center: np.ndarray, + elements_direction: np.ndarray, + length_scale: float + ): """ Returns the (unscaled) magnetic dipole moment vector. @@ -142,7 +156,13 @@ def _get_magnetic_dipole_moment_worker(elements_center, elements_direction, leng # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - def recalculate(self, wire, sampling_volume, field, progress_callback) -> bool: + def recalculate( + self, + wire: Wire, + sampling_volume: SamplingVolume, + field: Field, + progress_callback: Callable + ) -> bool: """ Recalculates parameters. diff --git a/magneticalc/Parameters_Widget.py b/magneticalc/Parameters_Widget.py index 22c3219..ac2d6b1 100644 --- a/magneticalc/Parameters_Widget.py +++ b/magneticalc/Parameters_Widget.py @@ -16,16 +16,22 @@ # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +from __future__ import annotations import numpy as np from si_prefix import si_format -from PyQt5.QtCore import Qt -from PyQt5.QtWidgets import QVBoxLayout, QHBoxLayout, QLabel, QSizePolicy +from PyQt5.QtWidgets import QVBoxLayout, QHBoxLayout +from magneticalc.QGroupBox2 import QGroupBox2 +from magneticalc.QLabel2 import QLabel2 from magneticalc.Debug import Debug from magneticalc.Field_Types import A_FIELD, B_FIELD -from magneticalc.QGroupBox2 import QGroupBox2 from magneticalc.Parameters import Parameters from magneticalc.Theme import Theme +# Note: Workaround for type hinting +# noinspection PyUnreachableCode +if False: + from magneticalc.GUI import GUI + class Parameters_Widget(QGroupBox2): """ Parameters_Widget class. """ @@ -33,21 +39,19 @@ class Parameters_Widget(QGroupBox2): # Formatting settings ValuePrecision = 1 - def __init__(self, gui): + def __init__(self, gui: GUI) -> None: """ Populates the widget. @param gui: GUI """ QGroupBox2.__init__(self, "Parameters") - + Debug(self, ": Init") self.gui = gui - # Assign the Parameters container class + # Assign the "Parameters" container class self.gui.model.set_parameters(Parameters(), invalidate_self=False) - # -------------------------------------------------------------------------------------------------------------- - results_layout = QHBoxLayout() results_left = QVBoxLayout() results_middle = QVBoxLayout() @@ -57,107 +61,55 @@ def __init__(self, gui): results_layout.addLayout(results_right) self.addLayout(results_layout) - # -------------------------------------------------------------------------------------------------------------- - - wire_length_label = QLabel("Wire length:") - wire_length_label.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) - results_left.addWidget(wire_length_label) - - self.wire_length_value_label = QLabel("") - self.wire_length_value_label.setStyleSheet(f"color: {Theme.PrimaryColor};") - self.wire_length_value_label.setAlignment(Qt.AlignRight | Qt.AlignVCenter) - self.wire_length_value_label.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) - results_middle.addWidget(self.wire_length_value_label, alignment=Qt.AlignVCenter | Qt.AlignRight) - - self.wire_length_units_label = QLabel("N/A") - self.wire_length_units_label.setStyleSheet(f"color: {Theme.PrimaryColor};") - self.wire_length_units_label.setAlignment(Qt.AlignLeft | Qt.AlignVCenter) - self.wire_length_units_label.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Expanding) - results_right.addWidget(self.wire_length_units_label, alignment=Qt.AlignVCenter) - - # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - magnetic_dipole_moment_label = QLabel("Magnetic Dipole Moment:") - magnetic_dipole_moment_label.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) - results_left.addWidget(magnetic_dipole_moment_label) - - self.magnetic_dipole_moment_value_label = QLabel("") - self.magnetic_dipole_moment_value_label.setStyleSheet(f"color: {Theme.PrimaryColor};") - self.magnetic_dipole_moment_value_label.setAlignment(Qt.AlignRight | Qt.AlignVCenter) - self.magnetic_dipole_moment_value_label.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) - results_middle.addWidget(self.magnetic_dipole_moment_value_label, alignment=Qt.AlignVCenter | Qt.AlignRight) - - self.magnetic_dipole_moment_units_label = QLabel("N/A") - self.magnetic_dipole_moment_units_label.setStyleSheet(f"color: {Theme.PrimaryColor};") - self.magnetic_dipole_moment_units_label.setAlignment(Qt.AlignLeft | Qt.AlignVCenter) - self.magnetic_dipole_moment_units_label.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Expanding) - results_right.addWidget(self.magnetic_dipole_moment_units_label, alignment=Qt.AlignVCenter) - - # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - energy_label = QLabel("Energy:") - energy_label.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) - results_left.addWidget(energy_label) - - self.energy_value_label = QLabel("") - self.energy_value_label.setStyleSheet(f"color: {Theme.PrimaryColor};") - self.energy_value_label.setAlignment(Qt.AlignRight | Qt.AlignVCenter) - self.energy_value_label.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) - results_middle.addWidget(self.energy_value_label, alignment=Qt.AlignVCenter | Qt.AlignRight) - - self.energy_units_label = QLabel("N/A") - self.energy_units_label.setStyleSheet(f"color: {Theme.PrimaryColor};") - self.energy_units_label.setAlignment(Qt.AlignLeft | Qt.AlignVCenter) - self.energy_units_label.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Expanding) - results_right.addWidget(self.energy_units_label, alignment=Qt.AlignVCenter) - - # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - self_inductance_label = QLabel("Self-inductance:") - self_inductance_label.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) - results_left.addWidget(self_inductance_label) - - self.self_inductance_value_label = QLabel("") - self.self_inductance_value_label.setStyleSheet(f"color: {Theme.PrimaryColor};") - self.self_inductance_value_label.setAlignment(Qt.AlignRight | Qt.AlignVCenter) - self.self_inductance_value_label.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) - results_middle.addWidget(self.self_inductance_value_label, alignment=Qt.AlignVCenter | Qt.AlignRight) - - self.self_inductance_units_label = QLabel("N/A") - self.self_inductance_units_label.setStyleSheet(f"color: {Theme.PrimaryColor};") - self.self_inductance_units_label.setAlignment(Qt.AlignLeft | Qt.AlignVCenter) - self.self_inductance_units_label.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Expanding) - results_right.addWidget(self.self_inductance_units_label, alignment=Qt.AlignVCenter) + results_left.addWidget(QLabel2("Wire length:")) + self.wire_length_value_label = QLabel2("", color=Theme.MainColor, align_right=True) + results_middle.addWidget(self.wire_length_value_label) + self.wire_length_units_label = QLabel2("N/A", color=Theme.MainColor, expand=False) + results_right.addWidget(self.wire_length_units_label) + + results_left.addWidget(QLabel2("Magnetic Dipole Moment:")) + self.magnetic_dipole_moment_value_label = QLabel2("", color=Theme.MainColor, align_right=True) + results_middle.addWidget(self.magnetic_dipole_moment_value_label) + self.magnetic_dipole_moment_units_label = QLabel2("N/A", color=Theme.MainColor, expand=False) + results_right.addWidget(self.magnetic_dipole_moment_units_label) + + results_left.addWidget(QLabel2("Energy:")) + self.energy_value_label = QLabel2("", color=Theme.MainColor, align_right=True) + results_middle.addWidget(self.energy_value_label) + self.energy_units_label = QLabel2("N/A", color=Theme.MainColor, expand=False) + results_right.addWidget(self.energy_units_label) + + results_left.addWidget(QLabel2("Self-inductance:")) + self.self_inductance_value_label = QLabel2("", color=Theme.MainColor, align_right=True) + results_middle.addWidget(self.self_inductance_value_label) + self.self_inductance_units_label = QLabel2("N/A", color=Theme.MainColor, expand=False) + results_right.addWidget(self.self_inductance_units_label) # ------------------------------------------------------------------------------------------------------------------ - def update_labels(self): + def update_labels(self) -> None: """ Updates the labels. """ + Debug(self, ".update_labels()") + if self.gui.model.parameters.is_valid(): - self.wire_length_value_label.setText(f"{self.gui.model.wire.get_length():.2f}") - self.wire_length_value_label.setStyleSheet(f"color: {Theme.PrimaryColor}; font-weight: bold;") - self.wire_length_units_label.setText("cm") - self.wire_length_units_label.setStyleSheet(f"color: {Theme.PrimaryColor}; font-weight: bold;") + self.wire_length_value_label.set( + f"{self.gui.model.wire.get_length():.2f}", color=Theme.MainColor, bold=True + ) + self.wire_length_units_label.set("cm", color=Theme.MainColor, bold=True) if self.gui.model.field.get_type() == A_FIELD: - self.energy_value_label.setText("") - self.energy_value_label.setStyleSheet(f"color: {Theme.PrimaryColor};") - self.energy_units_label.setText("N/A") - self.energy_units_label.setStyleSheet(f"color: {Theme.PrimaryColor};") + self.energy_value_label.set("", color=Theme.MainColor) + self.energy_units_label.set("N/A", color=Theme.MainColor) - self.self_inductance_value_label.setText("") - self.self_inductance_value_label.setStyleSheet(f"color: {Theme.PrimaryColor};") - self.self_inductance_units_label.setText("N/A") - self.self_inductance_units_label.setStyleSheet(f"color: {Theme.PrimaryColor};") + self.self_inductance_value_label.set("", color=Theme.MainColor) + self.self_inductance_units_label.set("N/A", color=Theme.MainColor) - self.magnetic_dipole_moment_value_label.setText("") - self.magnetic_dipole_moment_value_label.setStyleSheet(f"color: {Theme.PrimaryColor};") - self.magnetic_dipole_moment_units_label.setText("N/A") - self.magnetic_dipole_moment_units_label.setStyleSheet(f"color: {Theme.PrimaryColor};") + self.magnetic_dipole_moment_value_label.set("", color=Theme.MainColor) + self.magnetic_dipole_moment_units_label.set("N/A", color=Theme.MainColor) elif self.gui.model.field.get_type() == B_FIELD: @@ -170,10 +122,8 @@ def update_labels(self): precision=self.ValuePrecision, exp_format_str="{value}e{expof10} " ) + "J" - self.energy_value_label.setText(energy_value.split(" ")[0]) - self.energy_value_label.setStyleSheet(f"color: {Theme.PrimaryColor}; font-weight: bold;") - self.energy_units_label.setText(energy_value.split(" ")[1]) - self.energy_units_label.setStyleSheet(f"color: {Theme.PrimaryColor}; font-weight: bold;") + self.energy_value_label.set(energy_value.split(" ")[0], color=Theme.MainColor, bold=True) + self.energy_units_label.set(energy_value.split(" ")[1], color=Theme.MainColor, bold=True) self_inductance_value = self.gui.model.parameters.get_self_inductance() if np.isnan(self_inductance_value): @@ -184,10 +134,11 @@ def update_labels(self): precision=self.ValuePrecision, exp_format_str="{value}e{expof10} " ) + "H" - self.self_inductance_value_label.setText(self_inductance_value.split(" ")[0]) - self.self_inductance_value_label.setStyleSheet(f"color: {Theme.PrimaryColor}; font-weight: bold;") - self.self_inductance_units_label.setText(self_inductance_value.split(" ")[1]) - self.self_inductance_units_label.setStyleSheet(f"color: {Theme.PrimaryColor}; font-weight: bold;") + self.self_inductance_value_label.set( + self_inductance_value.split(" ")[0], color=Theme.MainColor, bold=True + ) + self.self_inductance_units_label.set( + self_inductance_value.split(" ")[1], color=Theme.MainColor, bold=True) magnetic_dipole_moment_value = self.gui.model.parameters.get_magnetic_dipole_moment() if np.isnan(magnetic_dipole_moment_value): @@ -198,37 +149,23 @@ def update_labels(self): precision=self.ValuePrecision, exp_format_str="{value}e{expof10} " ) + "A·m²" - self.magnetic_dipole_moment_value_label.setText(magnetic_dipole_moment_value.split(" ")[0]) - self.magnetic_dipole_moment_value_label.setStyleSheet( - f"color: {Theme.PrimaryColor}; font-weight: bold;" + self.magnetic_dipole_moment_value_label.set( + magnetic_dipole_moment_value.split(" ")[0], color=Theme.MainColor, bold=True ) - self.magnetic_dipole_moment_units_label.setText(magnetic_dipole_moment_value.split(" ")[1]) - self.magnetic_dipole_moment_units_label.setStyleSheet( - f"color: {Theme.PrimaryColor}; font-weight: bold;" + self.magnetic_dipole_moment_units_label.set( + magnetic_dipole_moment_value.split(" ")[1], color=Theme.MainColor, bold=True ) - else: + else: - Debug(self, ".update_labels(): FATAL: Invalid field type", color=Theme.WarningColor, force=True) + self.wire_length_value_label.set("", color=Theme.MainColor) + self.wire_length_units_label.set("N/A", color=Theme.MainColor) - else: + self.energy_value_label.set("", color=Theme.MainColor) + self.energy_units_label.set("N/A", color=Theme.MainColor) + + self.self_inductance_value_label.set("", color=Theme.MainColor) + self.self_inductance_units_label.set("N/A", color=Theme.MainColor) - self.wire_length_value_label.setText("") - self.wire_length_value_label.setStyleSheet(f"color: {Theme.PrimaryColor};") - self.wire_length_units_label.setText("N/A") - self.wire_length_units_label.setStyleSheet(f"color: {Theme.PrimaryColor};") - - self.energy_value_label.setText("") - self.energy_value_label.setStyleSheet(f"color: {Theme.PrimaryColor};") - self.energy_units_label.setText("N/A") - self.energy_units_label.setStyleSheet(f"color: {Theme.PrimaryColor};") - - self.self_inductance_value_label.setText("") - self.self_inductance_value_label.setStyleSheet(f"color: {Theme.PrimaryColor};") - self.self_inductance_units_label.setText("N/A") - self.self_inductance_units_label.setStyleSheet(f"color: {Theme.PrimaryColor};") - - self.magnetic_dipole_moment_value_label.setText("") - self.magnetic_dipole_moment_value_label.setStyleSheet(f"color: {Theme.PrimaryColor};") - self.magnetic_dipole_moment_units_label.setText("N/A") - self.magnetic_dipole_moment_units_label.setStyleSheet(f"color: {Theme.PrimaryColor};") + self.magnetic_dipole_moment_value_label.set("", color=Theme.MainColor) + self.magnetic_dipole_moment_units_label.set("N/A", color=Theme.MainColor) diff --git a/magneticalc/Perspective_Presets.py b/magneticalc/Perspective_Presets.py index 1a7d28a..a9f8882 100644 --- a/magneticalc/Perspective_Presets.py +++ b/magneticalc/Perspective_Presets.py @@ -16,6 +16,7 @@ # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +from typing import Optional, Dict import numpy as np @@ -63,7 +64,7 @@ class Perspective_Presets: # ------------------------------------------------------------------------------------------------------------------ @staticmethod - def get_by_id(_id_: str): + def get_by_id(_id_: str) -> Optional[Dict]: """ Selects a preset by name. diff --git a/magneticalc/Perspective_Widget.py b/magneticalc/Perspective_Widget.py index c743240..3890681 100644 --- a/magneticalc/Perspective_Widget.py +++ b/magneticalc/Perspective_Widget.py @@ -16,26 +16,34 @@ # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +from __future__ import annotations +from typing import Dict from functools import partial from PyQt5.QtCore import Qt from PyQt5.QtWidgets import QVBoxLayout, QHBoxLayout, QLabel, QPushButton from magneticalc.QGroupBox2 import QGroupBox2 from magneticalc.QHLine import QHLine +from magneticalc.Debug import Debug from magneticalc.Perspective_Presets import Perspective_Presets from magneticalc.Theme import Theme +# Note: Workaround for type hinting +# noinspection PyUnreachableCode +if False: + from magneticalc.GUI import GUI + class Perspective_Widget(QGroupBox2): """ Perspective_Widget class. """ - def __init__(self, gui): + def __init__(self, gui: GUI) -> None: """ Populates the widget. @param gui: GUI """ QGroupBox2.__init__(self, "Perspective") - + Debug(self, ": Init") self.gui = gui # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -46,6 +54,7 @@ def __init__(self, gui): button = QPushButton(preset["id"]) button.setStyleSheet("background-color: lightgrey") + # noinspection PyUnresolvedReferences button.clicked.connect( partial(self.set_perspective, preset) ) @@ -62,7 +71,7 @@ def __init__(self, gui): x_label = QLabel("X") y_label = QLabel("Y") z_label = QLabel("Z") - hint_label.setStyleSheet(f"color: {Theme.LightColor}; font-style: italic;") + hint_label.setStyleSheet(f"color: {Theme.LiteColor}; font-style: italic;") x_label.setStyleSheet("color: #cc0000; font-weight: bold;") y_label.setStyleSheet("color: #00cc00; font-weight: bold;") z_label.setStyleSheet("color: #0000cc; font-weight: bold;") @@ -73,7 +82,7 @@ def __init__(self, gui): xyz_hint_layout.addWidget(z_label, alignment=Qt.AlignRight | Qt.AlignVCenter) self.addLayout(xyz_hint_layout) - def set_perspective(self, preset): + def set_perspective(self, preset: Dict) -> None: """ Sets display perspective. diff --git a/magneticalc/QDialog2.py b/magneticalc/QDialog2.py index 9b302a4..fb0a244 100644 --- a/magneticalc/QDialog2.py +++ b/magneticalc/QDialog2.py @@ -20,6 +20,7 @@ from PyQt5.QtCore import QEvent, pyqtSignal from PyQt5.QtWidgets import QDialog from magneticalc.QLayouted import QLayouted +from magneticalc.Debug import Debug class QDialog2(QDialog, QLayouted): @@ -43,6 +44,8 @@ def __init__( QLayouted.__init__(self) self.install_layout(self) + Debug(self, f": Init: {title}") + if title: self.setWindowTitle(title) @@ -55,14 +58,20 @@ def show(self): """ Shows this dialog. """ + Debug(self, ".show()") + self.success = self.exec() == 1 + Debug(self, f".show(): Dialog closed: success={self.success}") + def showEvent(self, event: QEvent) -> None: """ Overrides the showEvent method. @param event: QEvent """ + Debug(self, ".showEvent(): Dialog opened") + # noinspection PyTypeChecker super(QDialog, self).showEvent(event) # noinspection PyUnresolvedReferences diff --git a/magneticalc/QGroupBox2.py b/magneticalc/QGroupBox2.py index ab96b2c..3b18746 100644 --- a/magneticalc/QGroupBox2.py +++ b/magneticalc/QGroupBox2.py @@ -24,7 +24,7 @@ class QGroupBox2(QGroupBox, QLayouted): """ QGroupBox2 class. """ - def __init__(self, title): + def __init__(self, title: str) -> None: """ Initializes a groupbox. @@ -41,7 +41,7 @@ def __init__(self, title): border: 1px solid #cccccc; border-radius: 3px; margin-top: 20px; - color: {Theme.PrimaryColor}; + color: {Theme.MainColor}; font-weight: bold; background-color: #e5e5e5; }} diff --git a/magneticalc/QHLine.py b/magneticalc/QHLine.py index dbe48af..ac9d8c1 100644 --- a/magneticalc/QHLine.py +++ b/magneticalc/QHLine.py @@ -25,11 +25,11 @@ class QHLine(QFrame): # Default spacing VerticalSpacing = 12 - def __init__(self): + def __init__(self) -> None: """ Creates a horizontal line. """ - super().__init__() + QFrame.__init__(self) self.setFixedHeight(self.VerticalSpacing) self.setFrameShape(QFrame.HLine) diff --git a/magneticalc/QIconLabel.py b/magneticalc/QIconLabel.py index 982d4e7..3bd8fa6 100644 --- a/magneticalc/QIconLabel.py +++ b/magneticalc/QIconLabel.py @@ -40,7 +40,7 @@ def __init__( icon_size: QSize = QSize(16, 16), final_stretch: bool = True, font: Optional[QFont] = None - ): + ) -> None: """ Initializes the icon label. diff --git a/magneticalc/QLabel2.py b/magneticalc/QLabel2.py index 43be383..a827870 100644 --- a/magneticalc/QLabel2.py +++ b/magneticalc/QLabel2.py @@ -18,6 +18,7 @@ from typing import Optional, Union, Tuple from PyQt5.Qt import QFont +from PyQt5.QtCore import Qt from PyQt5.QtWidgets import QLabel, QSizePolicy @@ -25,25 +26,53 @@ class QLabel2(QLabel): """ QLabel2 class. """ def __init__( + self, + text: str, + expand: bool = True, + align_right: bool = False, + **kwargs, + ) -> None: + """ + Initializes a QLabel. + + Please see L{set()} for supported arguments. + + @param text: Text + @param expand: Enable to expand + @param align_right: Enable to align right + """ + QLabel.__init__(self) + + if expand: + self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Minimum) + else: + self.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum) + + if align_right: + self.setAlignment(Qt.AlignRight | Qt.AlignVCenter) + else: + self.setAlignment(Qt.AlignVCenter) + + self.set(text, **kwargs) + + def set( self, text: str, font: Optional[QFont] = None, bold: bool = False, italic: bool = False, - color: Union[str, Tuple[int, int, int]] = None, - fixed: bool = False + color: Union[str, Tuple[int, int, int]] = "black" ) -> None: """ - Initializes a QLabel. + Sets the label properties. @param text: Text @param font: QFont @param bold: Enable for bold text @param italic: Enable for italic text @param color: Text color - @param fixed: Enable to set fixed layout size (don't expand) """ - QLabel.__init__(self, text=text) + self.setText(text) if font: self.setFont(font) @@ -54,6 +83,3 @@ def __init__( f"color: {color}": color } self.setStyleSheet(";".join([string for string, condition in stylesheet_map.items() if condition])) - - if fixed: - self.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Expanding) diff --git a/magneticalc/QLayouted.py b/magneticalc/QLayouted.py index c6c47fd..6a15a24 100644 --- a/magneticalc/QLayouted.py +++ b/magneticalc/QLayouted.py @@ -16,29 +16,32 @@ # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -from PyQt5.QtCore import Qt from typing import Dict, Tuple, Callable, Union, Optional -from magneticalc.QButtons import QButtons +from PyQt5.QtCore import Qt from PyQt5.QtWidgets import QVBoxLayout, QHBoxLayout, QLayout, QWidget, QPushButton +from magneticalc.QButtons import QButtons class QLayouted: """ QLayouted class. """ - def __init__(self, direction: str = "vertical"): + def __init__(self, direction: str = "vertical") -> None: """ Initializes the QLayouted class. + This adds a layout and several related functions like addWidget() to the parent class. + + @param direction: Sets "vertical" or "horizontal" layout """ - self.layout = QVBoxLayout() if direction == "vertical" else QHBoxLayout() + self._layout = QVBoxLayout() if direction == "vertical" else QHBoxLayout() - def install_layout(self, parent: QWidget): + def install_layout(self, parent: QWidget) -> None: """ Installs this layout in the parent. """ - parent.setLayout(self.layout) + parent.setLayout(self._layout) # noinspection PyPep8Naming - def addWidget(self, widget, alignment: Optional[Union[Qt.Alignment, Qt.AlignmentFlag]] = None): + def addWidget(self, widget, alignment: Optional[Union[Qt.Alignment, Qt.AlignmentFlag]] = None) -> None: """ Adds widget. @@ -46,9 +49,9 @@ def addWidget(self, widget, alignment: Optional[Union[Qt.Alignment, Qt.Alignment @param alignment: Alignment """ if alignment: - self.layout.addWidget(widget, alignment=alignment) + self._layout.addWidget(widget, alignment=alignment) else: - self.layout.addWidget(widget) + self._layout.addWidget(widget) # noinspection PyPep8Naming def addLayout(self, layout: QLayout) -> None: @@ -57,7 +60,7 @@ def addLayout(self, layout: QLayout) -> None: @param layout: QLayout """ - self.layout.addLayout(layout) + self._layout.addLayout(layout) # noinspection PyPep8Naming def addSpacing(self, spacing: float) -> None: @@ -66,7 +69,7 @@ def addSpacing(self, spacing: float) -> None: @param spacing: Spacing value """ - self.layout.addSpacing(spacing) + self._layout.addSpacing(spacing) # noinspection PyPep8Naming def addButtons(self, data: Dict[str, Tuple[str, Callable]]) -> Dict[Union[int, str], QPushButton]: diff --git a/magneticalc/QSaveAction.py b/magneticalc/QSaveAction.py index 072ed48..c5e0ff0 100644 --- a/magneticalc/QSaveAction.py +++ b/magneticalc/QSaveAction.py @@ -18,8 +18,7 @@ import os from datetime import datetime -from PyQt5.QtWidgets import QFileDialog, QMessageBox -from magneticalc.QMessageBox2 import QMessageBox2 +from PyQt5.QtWidgets import QFileDialog class QSaveAction: diff --git a/magneticalc/QSliderFloat.py b/magneticalc/QSliderFloat.py index 66b73e2..a689f8a 100644 --- a/magneticalc/QSliderFloat.py +++ b/magneticalc/QSliderFloat.py @@ -16,13 +16,14 @@ # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +from PyQt5.QtCore import Qt from PyQt5.QtWidgets import QSlider class QSliderFloat(QSlider): """ QSliderFloat class. """ - def __init__(self, orientation): + def __init__(self, orientation: Qt.Orientation) -> None: """ Initializes a slider supporting float values. @@ -32,7 +33,7 @@ def __init__(self, orientation): self._step = 0 - def set_range_step(self, minimum: float, maximum: float, step: float): + def set_range_step(self, minimum: float, maximum: float, step: float) -> None: """ Sets the float step. @@ -46,7 +47,7 @@ def set_range_step(self, minimum: float, maximum: float, step: float): super().setMaximum(round(maximum / self._step)) super().setSingleStep(1) - def setValue(self, value: float): + def setValue(self, value: float) -> None: """ Sets the slider value. diff --git a/magneticalc/QTableWidget2.py b/magneticalc/QTableWidget2.py index 59eb38a..bad19a0 100644 --- a/magneticalc/QTableWidget2.py +++ b/magneticalc/QTableWidget2.py @@ -16,14 +16,22 @@ # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +from __future__ import annotations +from typing import Optional, List, Dict, Union from functools import partial import qtawesome as qta -from PyQt5.QtCore import Qt, QItemSelectionModel +from PyQt5.Qt import QFocusEvent +from PyQt5.QtCore import Qt, QItemSelectionModel, QItemSelection from PyQt5.QtWidgets import QTableWidget, QTableWidgetItem, QHeaderView, QPushButton, QAbstractItemView, QComboBox from magneticalc.Config import Config from magneticalc.Debug import Debug from magneticalc.Theme import Theme +# Note: Workaround for type hinting +# noinspection PyUnreachableCode +if False: + from magneticalc.GUI import GUI + class QTableWidget2(QTableWidget): """ QTableWidget2 class. """ @@ -31,18 +39,15 @@ class QTableWidget2(QTableWidget): # Display settings MinimumHeight = 150 - # Used by L{Debug} - DebugColor = (128, 0, 128) - def __init__( self, - gui, + gui: GUI, enabled=True, cell_edited_callback=None, selection_changed_callback=None, row_deleted_callback=None, minimum_rows: int = 0, - ): + ) -> None: """ Initializes a table. @@ -53,9 +58,7 @@ def __init__( @param minimum_rows: Minimum number of rows (no further rows can be deleted) """ QTableWidget.__init__(self) - Debug(self, ": Init") - self.gui = gui self._enabled = enabled @@ -89,7 +92,7 @@ def __init__( # ------------------------------------------------------------------------------------------------------------------ - def on_cell_changed(self, row: int, column: int): + def on_cell_changed(self, row: int, column: int) -> None: """ Gets called when a cell changed. This is only used to correct the strange behaviour after editing a cell. @@ -104,7 +107,7 @@ def on_cell_changed(self, row: int, column: int): # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - def on_numerical_cell_edited(self, item): + def on_numerical_cell_edited(self, item: QTableWidgetItem) -> None: """ Gets called when a numerical cell has been edited. @@ -125,13 +128,13 @@ def on_numerical_cell_edited(self, item): self._cell_edited_callback(value, row, column) - def on_combobox_cell_edited(self, combobox, row, column): + def on_combobox_cell_edited(self, combobox: QComboBox, row: int, column: int) -> None: """ Gets called when a combobox cell has been edited. @param combobox: QCombobox - @param row: Row - @param column: Column + @param row: Row index + @param column: Column index """ Debug(self, f".on_combobox_cell_edited()") @@ -139,7 +142,7 @@ def on_combobox_cell_edited(self, combobox, row, column): # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - def on_selection_changed(self, _selected, _deselected): + def on_selection_changed(self, _selected: QItemSelection, _deselected: QItemSelection) -> None: """ Gets called when the selection changed. @@ -153,7 +156,7 @@ def on_selection_changed(self, _selected, _deselected): Debug(self, f".on_selection_changed()") self._selection_changed_callback() - def on_row_deleted(self, row: int): + def on_row_deleted(self, row: int) -> None: """ Gets called when a row was deleted. @@ -166,7 +169,7 @@ def on_row_deleted(self, row: int): # ------------------------------------------------------------------------------------------------------------------ - def get_selected_row(self): + def get_selected_row(self) -> Optional[int]: """ Returns the currently selected row index. @@ -177,7 +180,7 @@ def get_selected_row(self): else: return None - def is_cell_widget_selected(self): + def is_cell_widget_selected(self) -> bool: """ Indicates whether a cell widget is selected (as opposed to a cell item). """ @@ -195,7 +198,7 @@ def is_cell_widget_selected(self): item = self.item(row, column) return item is None - def select_cell(self, row=None, column=None): + def select_cell(self, row: Optional[int] = None, column: Optional[int] = None) -> None: """ Selects a cell. Any parameter may be left set to None in order to load its value from the selection model. @@ -210,7 +213,7 @@ def select_cell(self, row=None, column=None): column = self.selectionModel().currentIndex().column() if row == -1 or column == -1: - Debug(self, f".select_cell({row}, {column}): WARNING: Skipped", color=Theme.WarningColor, force=True) + Debug(self, f".select_cell({row}, {column}): WARNING: Skipped", warning=True) return item = self.item(row, column) @@ -235,7 +238,7 @@ def select_cell(self, row=None, column=None): self.scrollToItem(item, QAbstractItemView.PositionAtCenter) self.selectionModel().setCurrentIndex(self.selectedIndexes()[0], QItemSelectionModel.SelectCurrent) - def select_last_row(self, focus: bool = True): + def select_last_row(self, focus: bool = True) -> None: """ Selects the last row. @@ -261,7 +264,7 @@ def select_last_row(self, focus: bool = True): # ------------------------------------------------------------------------------------------------------------------ - def set_horizontal_header(self, header): + def set_horizontal_header(self, header: List[str]) -> None: """ Sets horizontal header. @@ -282,7 +285,7 @@ def set_horizontal_header(self, header): # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - def set_vertical_prefix(self, prefix: str): + def set_vertical_prefix(self, prefix: str) -> None: """ Sets the per-row table prefix. Used for mapping cells to configuration; configuration key = prefix + column key + "_" + row index. @@ -291,7 +294,7 @@ def set_vertical_prefix(self, prefix: str): """ self._prefix = prefix - def set_horizontal_types(self, types): + def set_horizontal_types(self, types: Optional[Dict]) -> None: """ Sets the per-column cell types. Used for mapping cells to configuration. @@ -303,7 +306,7 @@ def set_horizontal_types(self, types): """ self._types = types - def set_horizontal_options(self, options): + def set_horizontal_options(self, options: List) -> None: """ Sets the per-column cell options. This determines if the cell type, i.e. numerical or combobox. @@ -314,7 +317,7 @@ def set_horizontal_options(self, options): # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - def set_vertical_header(self, header): + def set_vertical_header(self, header: List) -> None: """ Sets vertical header. @@ -338,7 +341,7 @@ def set_vertical_header(self, header): # ------------------------------------------------------------------------------------------------------------------ - def clear_rows(self): + def clear_rows(self) -> None: """ Clears all table rows. """ @@ -348,7 +351,7 @@ def clear_rows(self): # ------------------------------------------------------------------------------------------------------------------ - def set_contents(self, contents): + def set_contents(self, contents: Union[List[List[str]], List[Dict]]) -> None: """ Sets the table contents. @@ -434,7 +437,7 @@ def set_contents(self, contents): # ------------------------------------------------------------------------------------------------------------------ - def set_style(self, border_color: str, border_width: int): + def set_style(self, border_color: str, border_width: int) -> None: """ Sets this widget's style. @@ -462,26 +465,26 @@ def set_style(self, border_color: str, border_width: int): # ------------------------------------------------------------------------------------------------------------------ - def focusInEvent(self, _event): + def focusInEvent(self, _event: QFocusEvent) -> None: """ Gets called when the table gained focus. This highlights the border and selects the last-selected cell (if any). - @param _event: Event + @param _event: QFocusEvent """ Debug(self, f".focusInEvent()") if self.rowCount() > 0: self.select_cell() - self.set_style(border_color=Theme.PrimaryColor, border_width=2) + self.set_style(border_color=Theme.MainColor, border_width=2) - def focusOutEvent(self, _event): + def focusOutEvent(self, _event: QFocusEvent) -> None: """ Gets called when the table lost focus, or when a cell item is being edited, or when a cell widget is selected. When not editing, this clears the selection, triggering L{on_selection_changed} - @param _event: Event + @param _event: QFocusEvent """ if self.state() == QAbstractItemView.EditingState: Debug(self, f".focusOutEvent(): Ignored in editing mode") diff --git a/magneticalc/SamplingVolume.py b/magneticalc/SamplingVolume.py index a2c62da..34acfc7 100644 --- a/magneticalc/SamplingVolume.py +++ b/magneticalc/SamplingVolume.py @@ -16,12 +16,12 @@ # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -from typing import Tuple, List, Optional +from typing import Tuple, List, Optional, Callable, Dict import numpy as np from PyQt5.QtCore import QThread from magneticalc.Assert_Dialog import Assert_Dialog +from magneticalc.Constraint import Constraint from magneticalc.Debug import Debug -from magneticalc.Theme import Theme class SamplingVolume: @@ -30,7 +30,7 @@ class SamplingVolume: # Enable to show additional debug info during constraint calculation Debug_Constraints = False - def __init__(self, resolution: float, label_resolution: float): + def __init__(self, resolution: float, label_resolution: float) -> None: """ Initializes an empty sampling volume, with zero bounds and no constraints. @@ -78,11 +78,11 @@ def is_valid(self) -> bool: self._labeled_indices is not None and \ self._neighbor_indices is not None - def invalidate(self): + def invalidate(self) -> None: """ Resets data, hiding from display. """ - Debug(self, ".invalidate()", color=Theme.InvalidColor) + Debug(self, ".invalidate()") self._dimension = None self._points = None @@ -116,11 +116,11 @@ def get_extent(self) -> List: """ return self._bounds_max - self._bounds_min - def get_points(self) -> List: + def get_points(self) -> np.array: """ Returns this sampling volume's points. - @return: Ordered list of 3D points + @return: Array of 3D points """ Assert_Dialog(self.is_valid(), "Accessing invalidated sampling volume") @@ -136,7 +136,7 @@ def get_points_count(self) -> int: return len(self._points) - def get_permeabilities(self) -> List: + def get_permeabilities(self) -> np.ndarray: """ Returns this sampling volume's relative permeabilities µ_r. @@ -166,7 +166,7 @@ def get_labels_count(self) -> int: return len(self._labeled_indices) - def get_neighbor_indices(self) -> List: + def get_neighbor_indices(self) -> List[np.ndarray]: """ Returns this sampling volume's neighborhood indices. @@ -178,7 +178,7 @@ def get_neighbor_indices(self) -> List: # ------------------------------------------------------------------------------------------------------------------ - def set_bounds_nearest(self, bounds_min, bounds_max) -> None: + def set_bounds_nearest(self, bounds_min: np.ndarray, bounds_max: np.ndarray) -> None: """ Adjusts this volume's bounding box to fully enclose a 3D wire curve. This expands the bounding box to the next integer grid coordinates. @@ -189,10 +189,12 @@ def set_bounds_nearest(self, bounds_min, bounds_max) -> None: @param bounds_max: Maximum bounding box point @return: Rounded (_bounds_min, _bounds_max) """ + Debug(self, ".set_bounds_nearest()") + self._bounds_min = np.array([np.floor(x) for x in bounds_min]) self._bounds_max = np.array([np.ceil(x) for x in bounds_max]) - def set_padding_nearest(self, padding) -> None: + def set_padding_nearest(self, padding: np.ndarray) -> None: """ Shrinks or enlarges this volume's bounding box by some amount, in each direction, symmetrically. This shrinks or expands the bounding box to the next integer grid coordinates. @@ -201,24 +203,26 @@ def set_padding_nearest(self, padding) -> None: @param padding: Amount of padding (3D point) """ + Debug(self, ".set_padding_nearest()") + self._bounds_min -= np.array([np.floor(x) for x in padding]) self._bounds_max += np.array([np.ceil(x) for x in padding]) # ------------------------------------------------------------------------------------------------------------------ - def add_constraint(self, constraint) -> None: + def add_constraint(self, constraint: Constraint) -> None: """ Adds some constraint to this volume's point generator. @param constraint: Constraint """ - Debug(self, f".add_constraint()") + Debug(self, ".add_constraint()") self.constraints.append(constraint) # ------------------------------------------------------------------------------------------------------------------ - def recalculate(self, progress_callback) -> bool: + def recalculate(self, progress_callback: Callable) -> bool: """ Recalculates the sampling volume points, permeabilities, labels and neighborhoods according to the constraints. @@ -228,7 +232,7 @@ def recalculate(self, progress_callback) -> bool: Debug(self, ".recalculate()") # Group constraints by permeability - constraints_precedence_dict = {} + constraints_precedence_dict: Dict = {} for constraint in self.constraints: if constraint.permeability in constraints_precedence_dict: constraints_precedence_dict[constraint.permeability].append(constraint) @@ -236,12 +240,7 @@ def recalculate(self, progress_callback) -> bool: constraints_precedence_dict[constraint.permeability] = [constraint] if self.Debug_Constraints: - Debug( - self, - f".recalculate(): Created {len(constraints_precedence_dict)} constraint group(s)", - color=Theme.PrimaryColor, - force=True - ) + Debug(self, f".recalculate(): Created {len(constraints_precedence_dict)} constraint group(s)") # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -260,7 +259,7 @@ def recalculate(self, progress_callback) -> bool: labeled_indices = [] - def i_to_xyz(_i: int): + def i_to_xyz(_i: int) -> List: """ Convert 1D index to 3D indices. @@ -272,7 +271,7 @@ def i_to_xyz(_i: int): _z = _i // (self._dimension[0] * self._dimension[1]) return [_x, _y, _z] - def xyz_to_i(xyz) -> int: + def xyz_to_i(xyz: List) -> int: """ Convert 3D indices to 1D index. @@ -300,9 +299,7 @@ def xyz_to_i(xyz) -> int: self, f".recalculate(): Point = {point}: " f"Calculating {len(constraints_precedence_dict[permeability_key])} constraint(s) " - f"for permeability = {permeability_key} …", - color=Theme.PrimaryColor, - force=True + f"for permeability = {permeability_key} …" ) # Calculate the inclusion relation for the current group @@ -311,12 +308,7 @@ def xyz_to_i(xyz) -> int: if not constraint.evaluate(point): if self.Debug_Constraints: - Debug( - self, - f".recalculate(): Point = {point}: Constraint evaluated to False (breaking)", - color=Theme.WarningColor, - force=True - ) + Debug(self, f".recalculate(): Point = {point}: Constraint evaluated to False (breaking)") # Exclude this point within the current group included = False @@ -325,22 +317,12 @@ def xyz_to_i(xyz) -> int: else: if self.Debug_Constraints: - Debug( - self, - f".recalculate(): Point = {point}: Constraint evaluated to True", - color=Theme.SuccessColor, - force=True - ) + Debug(self, f".recalculate(): Point = {point}: Constraint evaluated to True", success=True) if included: if self.Debug_Constraints: - Debug( - self, - f".recalculate(): Point = {point}: Included by precedence grouping", - color=Theme.SuccessColor, - force=True - ) + Debug(self, f".recalculate(): Point = {point}: Included by precedence grouping", success=True) permeability = permeability_key break @@ -348,22 +330,12 @@ def xyz_to_i(xyz) -> int: else: if self.Debug_Constraints: - Debug( - self, - f".recalculate(): Point = {point}: Excluded by precedence grouping", - color=Theme.WarningColor, - force=True - ) + Debug(self, f".recalculate(): Point = {point}: Excluded by precedence grouping") if permeability != 0: if self.Debug_Constraints: - Debug( - self, - f".recalculate(): Point = {point}: Finally included with permeability = {permeability}", - color=Theme.SuccessColor, - force=True - ) + Debug(self, f".recalculate(): Point = {point}: Finally included with permeability = {permeability}") # Include this point points_all[i] = point @@ -391,19 +363,14 @@ def xyz_to_i(xyz) -> int: else: if self.Debug_Constraints: - Debug( - self, - f".recalculate(): Point = {point}: Finally excluded with permeability = 0", - color=Theme.WarningColor, - force=True - ) + Debug(self, f".recalculate(): Point = {point}: Finally excluded with permeability = 0") # Signal progress update, handle interrupt (every 16 iterations to keep overhead low) if i & 0xf == 0: progress_callback(100 * (i + 1) / n) if QThread.currentThread().isInterruptionRequested(): - Debug(self, ".recalculate(): Interruption requested, exiting now", color=Theme.PrimaryColor) + Debug(self, ".recalculate(): WARNING: Interruption requested, exiting now", warning=True) return False # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -468,12 +435,7 @@ def xyz_to_i(xyz) -> int: ) if len(self._points) == 0: - Debug( - self, - ".recalculate: USER WARNING: Avoiding empty sampling volume by adding origin", - color=Theme.WarningColor, - force=True - ) + Debug(self, ".recalculate: USER WARNING: Avoiding empty sampling volume by adding origin", warning=True) origin = np.zeros(3) self._points = np.array([origin]) self._permeabilities = np.array([0]) diff --git a/magneticalc/SamplingVolume_Widget.py b/magneticalc/SamplingVolume_Widget.py index 989350c..bd24405 100644 --- a/magneticalc/SamplingVolume_Widget.py +++ b/magneticalc/SamplingVolume_Widget.py @@ -16,22 +16,30 @@ # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +from __future__ import annotations from typing import Optional, List, Tuple import numpy as np import qtawesome as qta from PyQt5.QtCore import Qt from PyQt5.QtWidgets import QHBoxLayout, QLabel, QPushButton, QSpinBox, QComboBox, QSizePolicy, QWidget +from magneticalc.QGroupBox2 import QGroupBox2 +from magneticalc.QHLine import QHLine +from magneticalc.QIconLabel import QIconLabel +from magneticalc.Comparison_Types import comparison_type_from_str from magneticalc.Constraint import Constraint from magneticalc.Constraint_Editor import Constraint_Editor from magneticalc.Debug import Debug -from magneticalc.QIconLabel import QIconLabel -from magneticalc.QGroupBox2 import QGroupBox2 -from magneticalc.QHLine import QHLine from magneticalc.ModelAccess import ModelAccess +from magneticalc.Norm_Types import norm_type_from_str from magneticalc.OverridePadding_Dialog import OverridePadding_Dialog from magneticalc.SamplingVolume import SamplingVolume from magneticalc.Theme import Theme +# Note: Workaround for type hinting +# noinspection PyUnreachableCode +if False: + from magneticalc.GUI import GUI + class SamplingVolume_Widget(QGroupBox2): """ SamplingVolume_Widget class. """ @@ -64,14 +72,14 @@ class SamplingVolume_Widget(QGroupBox2): "1 / 256" : -8, } - def __init__(self, gui): + def __init__(self, gui: GUI) -> None: """ Populates the widget. @param gui: GUI """ QGroupBox2.__init__(self, "Sampling Volume") - + Debug(self, ": Init") self.gui = gui # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -83,11 +91,13 @@ def __init__(self, gui): padding_icon_label = QIconLabel("Padding", "mdi.arrow-expand-all") padding_override_button = QPushButton(" Override … ") + # noinspection PyUnresolvedReferences padding_override_button.clicked.connect(self.override_padding) padding_override_button.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) padding_icon_label.addWidget(padding_override_button) padding_clear_button = QPushButton() padding_clear_button.setIcon(qta.icon("fa.eraser")) + # noinspection PyUnresolvedReferences padding_clear_button.clicked.connect(self.clear_padding) padding_icon_label.addWidget(padding_clear_button) padding_units_label = QLabel("cm") @@ -104,6 +114,7 @@ def __init__(self, gui): self.padding_spinbox[i] = QSpinBox(self.gui) self.padding_spinbox[i].setMinimum(self.PaddingMin) self.padding_spinbox[i].setMaximum(self.PaddingMax) + # noinspection PyUnresolvedReferences self.padding_spinbox[i].valueChanged.connect(self.update_padding) padding_label[i] = QLabel(["X", "Y", "Z"][i] + ":") padding_label[i].setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Expanding) @@ -114,9 +125,9 @@ def __init__(self, gui): total_extent_layout = QHBoxLayout() total_extent_label_left = QLabel("Total extent:") - total_extent_label_left.setStyleSheet(f"color: {Theme.LightColor}; font-style: italic;") + total_extent_label_left.setStyleSheet(f"color: {Theme.LiteColor}; font-style: italic;") self.total_extent_label = QLabel("N/A") - self.total_extent_label.setStyleSheet(f"color: {Theme.PrimaryColor};") + self.total_extent_label.setStyleSheet(f"color: {Theme.MainColor};") self.total_extent_label.setAlignment(Qt.AlignRight | Qt.AlignVCenter) total_extent_layout.addWidget(total_extent_label_left, alignment=Qt.AlignVCenter) total_extent_layout.addWidget(self.total_extent_label, alignment=Qt.AlignVCenter) @@ -128,10 +139,11 @@ def __init__(self, gui): constraints_icon_label = QIconLabel("Constraints", "mdi.playlist-edit") constraint_shortcut_label = QLabel("⟨F3⟩") - constraint_shortcut_label.setStyleSheet(f"font-size: 13px; color: {Theme.LightColor}") + constraint_shortcut_label.setStyleSheet(f"font-size: 13px; color: {Theme.LiteColor}") constraints_icon_label.addWidget(constraint_shortcut_label) constraint_edit_button = QPushButton("Edit …") + # noinspection PyUnresolvedReferences constraint_edit_button.clicked.connect(self.open_constraint_editor) constraints_icon_label.addWidget(constraint_edit_button) @@ -139,9 +151,9 @@ def __init__(self, gui): total_constraints_layout = QHBoxLayout() total_constraints_label_left = QLabel("Total constraints:") - total_constraints_label_left.setStyleSheet(f"color: {Theme.LightColor}; font-style: italic;") + total_constraints_label_left.setStyleSheet(f"color: {Theme.LiteColor}; font-style: italic;") self.total_constraints_label = QLabel("N/A") - self.total_constraints_label.setStyleSheet(f"color: {Theme.PrimaryColor};") + self.total_constraints_label.setStyleSheet(f"color: {Theme.MainColor};") self.total_constraints_label.setAlignment(Qt.AlignRight | Qt.AlignVCenter) total_constraints_layout.addWidget(total_constraints_label_left, alignment=Qt.AlignVCenter) total_constraints_layout.addWidget(self.total_constraints_label, alignment=Qt.AlignVCenter) @@ -164,6 +176,7 @@ def __init__(self, gui): # Populate resolution combobox for i, value in enumerate(self.ResolutionOptionsDict): self.resolution_combobox.addItem(str(value)) + # noinspection PyUnresolvedReferences self.resolution_combobox.currentIndexChanged.connect( lambda: self.set_sampling_volume( resolution_exponent=self.ResolutionOptionsDict.get( @@ -175,9 +188,9 @@ def __init__(self, gui): total_points_layout = QHBoxLayout() total_points_label_left = QLabel("Total sampling points:") - total_points_label_left.setStyleSheet(f"color: {Theme.LightColor}; font-style: italic;") + total_points_label_left.setStyleSheet(f"color: {Theme.LiteColor}; font-style: italic;") self.total_points_label = QLabel("N/A") - self.total_points_label.setStyleSheet(f"color: {Theme.PrimaryColor};") + self.total_points_label.setStyleSheet(f"color: {Theme.MainColor};") self.total_points_label.setAlignment(Qt.AlignRight | Qt.AlignVCenter) total_points_layout.addWidget(total_points_label_left, alignment=Qt.AlignVCenter) total_points_layout.addWidget(self.total_points_label, alignment=Qt.AlignVCenter) @@ -187,7 +200,7 @@ def __init__(self, gui): self.reinitialize() - def reinitialize(self): + def reinitialize(self) -> None: """ Re-initializes the widget and the constraint editor """ @@ -201,12 +214,7 @@ def reinitialize(self): # Set default resolution if it is not available anymore target = self.gui.config.get_int("sampling_volume_resolution_exponent") if target not in self.ResolutionOptionsDict.values(): - Debug( - self, - f": Invalid: sampling_volume_resolution_exponent = {target}", - color=Theme.WarningColor, - force=True - ) + Debug(self, f": WARNING: Invalid: sampling_volume_resolution_exponent = {target}", warning=True) self.gui.config.set_int("sampling_volume_resolution_exponent", 0) # Select the resolution @@ -225,19 +233,23 @@ def reinitialize(self): # ------------------------------------------------------------------------------------------------------------------ - def update_padding(self): + def update_padding(self) -> None: """ Updates padding. """ if self.signalsBlocked(): return + Debug(self, ".update_padding()") + self.set_sampling_volume(padding=[self.padding_spinbox[i].value() for i in range(3)]) - def clear_padding(self): + def clear_padding(self) -> None: """ Clears the padding values. """ + Debug(self, ".clear_padding()") + self.gui.config.set_bool("sampling_volume_override_padding", False) self.gui.config.set_points("sampling_volume_bounding_box", [np.zeros(3), np.zeros(3)]) @@ -252,6 +264,8 @@ def override_padding(self) -> None: """ Override padding, setting the bounding box directly. """ + Debug(self, ".override_padding()") + dialog = OverridePadding_Dialog(self.gui) dialog.show() @@ -282,7 +296,7 @@ def set_sampling_volume( bounding_box: List[List] = None, recalculate: bool = True, invalidate_self: bool = True - ): + ) -> None: """ Sets the sampling volume. This will overwrite the currently set sampling volume in the model. Parameters may be left set to None in order to load their default value. @@ -298,6 +312,8 @@ def set_sampling_volume( if self.signalsBlocked(): return + Debug(self, ".set_sampling_volume()") + with ModelAccess(self.gui, recalculate): resolution_exponent = self.gui.config.set_get_int( @@ -321,19 +337,12 @@ def set_sampling_volume( self.readjust(padding, override_padding, bounding_box) # Load sampling volume constraints from configuration - for i, constraint in enumerate(self.constraint_editor.get_constraints()): - - constraint = self.gui.config.set_get_dict( - prefix=f"constraint_", - suffix=f"_{i}", - types=self.constraint_editor.Constraint_Types, - values=None - ) - + for constraint in self.constraint_editor.get_constraints(): + Debug(self, f".set_sampling_volume(): Loading Constraint: {constraint}") self.gui.model.sampling_volume.add_constraint( Constraint( - constraint["norm"], - constraint["comparison"], + norm_type_from_str(constraint["norm"]), + comparison_type_from_str(constraint["comparison"]), constraint["min"], constraint["max"], constraint["permeability"] @@ -351,7 +360,7 @@ def readjust( padding: Optional[List] = None, override_padding: Optional[bool] = None, bounding_box: Optional[Tuple[np.ndarray, np.ndarray]] = None, - ): + ) -> None: """ Readjusts the sampling volume to the currently set wire bounds and padding. This also readjusts the minimum padding bounds in case the wire bounds have shrunk too far. @@ -403,20 +412,26 @@ def update(self) -> None: """ Updates the widget. """ + Debug(self, ".update()") + self.update_controls() self.update_labels() - def update_controls(self): + def update_controls(self) -> None: """ Updates the controls. """ + Debug(self, ".update_controls()") + override_padding = self.gui.config.get_bool("sampling_volume_override_padding") self.padding_widget.setEnabled(not override_padding) - def update_labels(self): + def update_labels(self) -> None: """ Updates the labels. """ + Debug(self, ".update_labels()") + if self.gui.model.sampling_volume.is_valid(): self.total_extent_label.setText( " × ".join([f"{extent:.0f}" for extent in self.gui.model.sampling_volume.get_extent()]) + " cm³" @@ -428,15 +443,16 @@ def update_labels(self): self.total_extent_label.setText("N/A") self.total_points_label.setText("N/A") - self.total_constraints_label.setText(str(len(self.constraint_editor.get_constraints()))) + self.total_constraints_label.setText(str(self.constraint_editor.get_count())) # ------------------------------------------------------------------------------------------------------------------ - def open_constraint_editor(self): + def open_constraint_editor(self) -> None: """ Opens the constraint editor. Recalculates the sampling volume if the constraints changed. """ + Debug(self, ".open_constraint_editor()") self.constraint_editor.show() diff --git a/magneticalc/SidebarLeft.py b/magneticalc/SidebarLeft.py index 084a169..5076c8e 100644 --- a/magneticalc/SidebarLeft.py +++ b/magneticalc/SidebarLeft.py @@ -16,11 +16,18 @@ # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +from __future__ import annotations from PyQt5.QtCore import Qt from PyQt5.QtWidgets import QWidget, QScrollArea, QVBoxLayout, QSizePolicy +from magneticalc.Debug import Debug from magneticalc.SamplingVolume_Widget import SamplingVolume_Widget from magneticalc.Wire_Widget import Wire_Widget +# Note: Workaround for type hinting +# noinspection PyUnreachableCode +if False: + from magneticalc.GUI import GUI + class SidebarLeft(QScrollArea): """ SidebarLeft class. """ @@ -29,14 +36,14 @@ class SidebarLeft(QScrollArea): MaximumWidth = 370 VerticalSpacing = 12 - def __init__(self, gui): + def __init__(self, gui: GUI) -> None: """ Populates the left sidebar. @param gui: GUI """ QScrollArea.__init__(self) - + Debug(self, ": Init") self.gui = gui layout = QVBoxLayout() diff --git a/magneticalc/SidebarRight.py b/magneticalc/SidebarRight.py index 282f467..42db1aa 100644 --- a/magneticalc/SidebarRight.py +++ b/magneticalc/SidebarRight.py @@ -16,14 +16,21 @@ # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +from __future__ import annotations from PyQt5.QtCore import Qt from PyQt5.QtWidgets import QWidget, QScrollArea, QVBoxLayout, QSizePolicy +from magneticalc.Debug import Debug from magneticalc.Display_Widget import Display_Widget from magneticalc.Field_Widget import Field_Widget from magneticalc.Metric_Widget import Metric_Widget from magneticalc.Parameters_Widget import Parameters_Widget from magneticalc.Perspective_Widget import Perspective_Widget +# Note: Workaround for type hinting +# noinspection PyUnreachableCode +if False: + from magneticalc.GUI import GUI + class SidebarRight(QScrollArea): """ SidebarRight class. """ @@ -32,14 +39,14 @@ class SidebarRight(QScrollArea): MaximumWidth = 370 VerticalSpacing = 12 - def __init__(self, gui): + def __init__(self, gui: GUI) -> None: """ Populates the right sidebar. @param gui: GUI """ QScrollArea.__init__(self) - + Debug(self, ": Init") self.gui = gui layout = QVBoxLayout() diff --git a/magneticalc/Statusbar.py b/magneticalc/Statusbar.py index f599d78..1a58644 100644 --- a/magneticalc/Statusbar.py +++ b/magneticalc/Statusbar.py @@ -16,78 +16,93 @@ # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -import qtawesome as qta +from __future__ import annotations from multiprocessing import cpu_count +from sty import fg +import qtawesome as qta from PyQt5.QtCore import Qt from PyQt5.QtWidgets import QWidget, QHBoxLayout, QPushButton, QCheckBox, QComboBox, QProgressBar, QLabel from magneticalc.Debug import Debug from magneticalc.Theme import Theme +# Note: Workaround for type hinting +# noinspection PyUnreachableCode +if False: + from magneticalc.GUI import GUI + class Statusbar: """ Statusbar class. """ - def __init__(self, gui): + # Used by L{Debug} + DebugColor = fg.blue + + def __init__(self, gui: GUI) -> None: """ Initializes statusbar. @param gui: GUI """ + Debug(self, ": Init") self.gui = gui # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # Start button - self.start_button = QPushButton(qta.icon("fa.play-circle"), " ⟨F5⟩ ", self.gui) - self.start_button.setStyleSheet(f"padding: 3px; font-size: 13px;") - self.start_button.clicked.connect(self.start) + self._start_button = QPushButton(qta.icon("fa.play-circle"), " ⟨F5⟩ ", self.gui) + self._start_button.setStyleSheet(f"padding: 3px; font-size: 13px;") + # noinspection PyUnresolvedReferences + self._start_button.clicked.connect(self.start) # Cancel button - self.cancel_button = QPushButton(qta.icon("fa.stop-circle"), "⟨ESC⟩", self.gui) - self.cancel_button.setStyleSheet(f"padding: 3px; font-size: 13px;") - self.cancel_button.clicked.connect(self.cancel) + self._cancel_button = QPushButton(qta.icon("fa.stop-circle"), "⟨ESC⟩", self.gui) + self._cancel_button.setStyleSheet(f"padding: 3px; font-size: 13px;") + # noinspection PyUnresolvedReferences + self._cancel_button.clicked.connect(self.cancel) # Auto-calculation checkbox - self.auto_calculation_checkbox = QCheckBox("Auto-Calculation") - self.auto_calculation_checkbox.toggled.connect(self._auto_calculation_changed) + self._auto_calculation_checkbox = QCheckBox("Auto-Calculation") + # noinspection PyUnresolvedReferences + self._auto_calculation_checkbox.toggled.connect(self._auto_calculation_changed) # Number-of-cores combobox - self.cores_combobox = QComboBox() + self._cores_combobox = QComboBox() # "Auto" setting num_cores_auto = max(1, cpu_count() - 1) for i in range(0, cpu_count() + 1): if i == 0: - self.cores_combobox.addItem(f"Auto ({num_cores_auto} Core" + ("s" if num_cores_auto > 1 else "") + ")") + self._cores_combobox.addItem(f"Auto ({num_cores_auto} Core" + ("s" if num_cores_auto > 1 else "") + ")") else: - self.cores_combobox.addItem(f"{i} Core" + ("s" if i > 1 else "")) + self._cores_combobox.addItem(f"{i} Core" + ("s" if i > 1 else "")) - self.cores_combobox.currentIndexChanged.connect( - lambda: self.gui.config.set_int("num_cores", self.cores_combobox.currentIndex()) + # noinspection PyUnresolvedReferences + self._cores_combobox.currentIndexChanged.connect( + lambda: self.gui.config.set_int("num_cores", self._cores_combobox.currentIndex()) ) # Progress bar - self.progressbar = QProgressBar() + self._progressbar = QProgressBar() # Status text - self.label = QLabel() + self._label = QLabel() # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # Populate statusbar layout layout = QHBoxLayout() - layout.addWidget(self.start_button, alignment=Qt.AlignVCenter) + layout.addWidget(self._start_button, alignment=Qt.AlignVCenter) layout.addSpacing(4) - layout.addWidget(self.cancel_button, alignment=Qt.AlignVCenter) + layout.addWidget(self._cancel_button, alignment=Qt.AlignVCenter) layout.addSpacing(4) - layout.addWidget(self.auto_calculation_checkbox, alignment=Qt.AlignVCenter) + layout.addWidget(self._auto_calculation_checkbox, alignment=Qt.AlignVCenter) layout.addSpacing(-4) - layout.addWidget(self.cores_combobox, alignment=Qt.AlignVCenter) + layout.addWidget(self._cores_combobox, alignment=Qt.AlignVCenter) layout.addSpacing(4) - layout.addWidget(self.progressbar, alignment=Qt.AlignVCenter) + layout.addWidget(self._progressbar, alignment=Qt.AlignVCenter) layout.addSpacing(4) - layout.addWidget(self.label, alignment=Qt.AlignVCenter) + layout.addWidget(self._label, alignment=Qt.AlignVCenter) layout.setContentsMargins(8, 2, 10, 2) container_widget = QWidget() @@ -100,7 +115,7 @@ def __init__(self, gui): self.reinitialize() - def reinitialize(self): + def reinitialize(self) -> None: """ Re-initializes the statusbar. """ @@ -108,88 +123,106 @@ def reinitialize(self): self.gui.blockSignals(True) - self.auto_calculation_checkbox.setChecked(self.gui.config.get_bool("auto_calculation")) + self._auto_calculation_checkbox.setChecked(self.gui.config.get_bool("auto_calculation")) if 0 > self.gui.config.get_int("num_cores") > cpu_count(): self.gui.config.set_int("num_cores", 0) for i in range(0, cpu_count() + 1): if i == self.gui.config.get_int("num_cores"): - self.cores_combobox.setCurrentIndex(i) + self._cores_combobox.setCurrentIndex(i) self.gui.blockSignals(False) # ------------------------------------------------------------------------------------------------------------------ - def _auto_calculation_changed(self): + def _auto_calculation_changed(self) -> None: """ Handles changed auto-calculation setting. """ if self.gui.signalsBlocked(): return - self.gui.config.set_bool("auto_calculation", self.auto_calculation_checkbox.isChecked()) - if self.auto_calculation_checkbox.isChecked(): + self.gui.config.set_bool("auto_calculation", self._auto_calculation_checkbox.isChecked()) + if self._auto_calculation_checkbox.isChecked(): if not self.gui.model.is_valid(): self.gui.recalculate() # ------------------------------------------------------------------------------------------------------------------ - def arm(self): + def arm(self) -> None: """ "Arms" the statusbar before calculation. """ - self.start_button.setEnabled(False) - self.cancel_button.setEnabled(True) - self.auto_calculation_checkbox.setEnabled(False) - self.cores_combobox.setEnabled(False) - self.progressbar.setValue(0) - self.set_progressbar_color(Theme.PrimaryColor) + Debug(self, f".arm()") - def disarm(self, success: bool): + self._start_button.setEnabled(False) + self._cancel_button.setEnabled(True) + self._auto_calculation_checkbox.setEnabled(False) + self._cores_combobox.setEnabled(False) + self._progressbar.setValue(0) + self.set_progressbar_color(Theme.MainColor) + + def disarm(self, success: bool) -> None: """ "Disarms" the statusbar after calculation. @param success: Reflects calculation success or failure """ - self.start_button.setEnabled(True) - self.cancel_button.setEnabled(False) - self.auto_calculation_checkbox.setEnabled(True) - self.cores_combobox.setEnabled(True) - self.text("Ready." if success else "Canceled!") - self.set_progressbar_color(Theme.SuccessColor if success else Theme.WarningColor) + Debug(self, f".disarm(success={success})") + + self._start_button.setEnabled(True) + self._cancel_button.setEnabled(False) + self._auto_calculation_checkbox.setEnabled(True) + self._cores_combobox.setEnabled(True) + self.set_text("Ready." if success else "Canceled!") + self.set_progressbar_color(Theme.SuccessColor if success else Theme.FailureColor) if success: - self.progressbar.setValue(100) + self._progressbar.setValue(100) - def start(self): + def start(self) -> None: """ Starts the calculation. """ + Debug(self, f".start()") + self.gui.recalculate() self.disarm(True) - def cancel(self): + def cancel(self) -> None: """ Cancels the ongoing calculation. """ + Debug(self, f".cancel()") + self.gui.interrupt_calculation() self.disarm(False) - def text(self, text: str): + def set_text(self, text: str) -> None: """ Updates the statusbar text. @param text: Text """ - self.label.setText(text) + Debug(self, f": {text}") + + self._label.setText(text) + + def set_progress(self, percentage: int) -> None: + """ + Updates the progress percentage. + + @param percentage: Percentage + """ + self._progressbar.setValue(percentage) - def set_progressbar_color(self, color: str): + def set_progressbar_color(self, color: str) -> None: """ Sets the progressbar color & style. @param color: Color """ - self.progressbar.setStyleSheet( + self._progressbar.setStyleSheet( f""" QProgressBar {{ diff --git a/magneticalc/Theme.py b/magneticalc/Theme.py index 1377923..ae83619 100644 --- a/magneticalc/Theme.py +++ b/magneticalc/Theme.py @@ -21,11 +21,11 @@ class Theme: """ Theme class. """ # Theme colors - - PrimaryColor = "#2c82b8" - LightColor = "#555555" + MainColor = "#2c82b8" + LiteColor = "#555555" DarkColor = "#12344a" - SuccessColor = "#2e7d32" - WarningColor = "#c62828" - InvalidColor = "#a00000" + FailureColor = "#c62828" + + # Default font + DefaultFontFace = "DejaVu Sans Mono" diff --git a/magneticalc/Usage_Dialog.py b/magneticalc/Usage_Dialog.py index c3a2198..9a5bf19 100644 --- a/magneticalc/Usage_Dialog.py +++ b/magneticalc/Usage_Dialog.py @@ -18,7 +18,7 @@ from magneticalc.QDialog2 import QDialog2 from magneticalc.QTextBrowser2 import QTextBrowser2 - +from magneticalc.Debug import Debug from magneticalc.Theme import Theme @@ -27,7 +27,7 @@ class Usage_Dialog(QDialog2): # HTML content HTML = f""" -

    First Steps

    +

    First Steps

    • Go to Wire › Load Preset to select a basic wire shape.
      @@ -96,7 +96,7 @@ class Usage_Dialog(QDialog2): All settings (including your wire shape) are stored in the MagnetiCalc.ini file by default.
      Deleting or renaming this file will restore the default settings. -

      What does MagnetiCalc do?

      +

      What does MagnetiCalc do?

      MagnetiCalc calculates the static magnetic flux density, vector potential, energy, self-inductance and magnetic dipole moment of arbitrary coils. @@ -109,13 +109,13 @@ class Usage_Dialog(QDialog2): materials, different core media can be modeled as regions of variable relative permeability; however, core saturation is currently not modeled, resulting in excessive flux density values. -

      Who needs MagnetiCalc?

      +

      Who needs MagnetiCalc?

      MagnetiCalc does its job for hobbyists, students, engineers and researchers of magnetic phenomena. I designed MagnetiCalc from scratch, because I didn't want to mess around with expensive and/or overly complex simulation software whenever I needed to solve a magnetostatic problem. -

      How does it work?

      +

      How does it work?

      The B-field calculation is implemented using the Biot-Savart law [1], employing multiprocessing techniques; @@ -144,16 +144,18 @@ class Usage_Dialog(QDialog2): [3]: Jackson, Klassische Elektrodynamik, 5. Auflage, S. 252, (5.157).
      [4]: Jackson, Klassische Elektrodynamik, 5. Auflage, S. 216, (5.54).
      -

      +

      This and more information about MagnetiCalc can be found in the README.md file and on GitHub.
      """ - def __init__(self): + def __init__(self) -> None: """ Initializes "Usage" dialog. """ QDialog2.__init__(self, title="Usage", width=850) + Debug(self, ": Init") + text_browser = QTextBrowser2(html=self.HTML) text_browser.setMinimumHeight(600) self.addWidget(text_browser) diff --git a/magneticalc/Version.py b/magneticalc/Version.py index e14d4b9..17c293c 100644 --- a/magneticalc/Version.py +++ b/magneticalc/Version.py @@ -17,7 +17,7 @@ # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -__VERSION__ = "v1.12.0" # MAJ.MIN.REV +__VERSION__ = "v1.12.1" # MAJ.MIN.REV __URL__ = "https://github.com/shredEngineer/MagnetiCalc" diff --git a/magneticalc/VispyCanvas.py b/magneticalc/VispyCanvas.py index 4f21f3f..e42c03f 100644 --- a/magneticalc/VispyCanvas.py +++ b/magneticalc/VispyCanvas.py @@ -16,23 +16,30 @@ # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +from __future__ import annotations import time import numpy as np from typing import Optional from si_prefix import si_format from vispy import io, scene, visuals from vispy.scene.cameras import TurntableCamera +from vispy.visuals.visual import Visual from magneticalc.Debug import Debug from magneticalc.Field import Field from magneticalc.Metric import Metric from magneticalc.Theme import Theme +# Note: Workaround for type hinting +# noinspection PyUnreachableCode +if False: + from magneticalc.GUI import GUI + class VispyCanvas(scene.SceneCanvas): """ VispyCanvas class. """ # Font - DefaultFontFace = "DejaVu Sans Mono" + DefaultFontFace = Theme.DefaultFontFace DefaultFontSize = 9 # Enable to additionally debug drawing of visuals @@ -64,13 +71,14 @@ class VispyCanvas(scene.SceneCanvas): # ------------------------------------------------------------------------------------------------------------------ - def __init__(self, gui): + def __init__(self, gui: GUI) -> None: """ Initialize VisPy canvas. @param gui: GUI """ scene.SceneCanvas.__init__(self) + Debug(self, ": Init") self.unfreeze() @@ -114,12 +122,12 @@ def __init__(self, gui): self.visual_field_arrow_heads = scene.visuals.create_visual_node(visuals.MarkersVisual)() if self.DebugVisuals: - Debug(self, f": visual_wire_segments = {self.visual_wire_segments}", color=(255, 0, 255)) - Debug(self, f": visual_wire_points_selected = {self.visual_wire_points_selected}", color=(255, 0, 255)) - Debug(self, f": visual_wire_points_sliced = {self.visual_wire_points_sliced}", color=(255, 0, 255)) - Debug(self, f": visual_field_points = {self.visual_field_points}", color=(255, 0, 255)) - Debug(self, f": visual_field_arrow_lines = {self.visual_field_arrow_lines}", color=(255, 0, 255)) - Debug(self, f": visual_field_arrow_heads = {self.visual_field_arrow_heads}", color=(255, 0, 255)) + Debug(self, f": visual_wire_segments = {self.visual_wire_segments}") + Debug(self, f": visual_wire_points_selected = {self.visual_wire_points_selected}") + Debug(self, f": visual_wire_points_sliced = {self.visual_wire_points_sliced}") + Debug(self, f": visual_field_points = {self.visual_field_points}") + Debug(self, f": visual_field_arrow_lines = {self.visual_field_arrow_lines}") + Debug(self, f": visual_field_arrow_heads = {self.visual_field_arrow_heads}") self.foreground = None self.background = None @@ -134,7 +142,7 @@ def __init__(self, gui): bold=True, text="Performing initial just-in-time compilation;\n" "subsequent calculations will execute faster!\n", - color=(1, .55, 0), + color=(1, .55, 0), # Orange face=self.DefaultFontFace, font_size=self.DefaultFontSize, font_manager=self.font_manager @@ -150,16 +158,18 @@ def __init__(self, gui): self.freeze() - def update_color_scheme(self): + def update_color_scheme(self) -> None: """ Updates the color scheme. """ + Debug(self, ".update_color_scheme()") + self.foreground = self.White if self.gui.config.get_bool("dark_background") else self.Black self.background = self.Black if self.gui.config.get_bool("dark_background") else self.White self.bgcolor = self.background self.visual_perspective_info.color = np.append(self.foreground[:3], 0.6) - def set_visible(self, visual, is_visible: bool): + def set_visible(self, visual: Visual, is_visible: bool) -> None: """ Sets some visual's visibility. @@ -168,7 +178,7 @@ def set_visible(self, visual, is_visible: bool): """ visual.parent = self.view_main.scene if is_visible else None - def load_perspective(self, redraw: bool = True): + def load_perspective(self, redraw: bool = True) -> None: """ Loads perspective from configuration. @@ -186,7 +196,7 @@ def load_perspective(self, redraw: bool = True): self.on_perspective_changed() self.redraw() - def on_perspective_changed(self): + def on_perspective_changed(self) -> None: """ Handles a change of perspective. """ @@ -221,7 +231,7 @@ def on_perspective_changed(self): self.super_perspective_changed() self.redraw_perspective_info() - def redraw_perspective_info(self): + def redraw_perspective_info(self) -> None: """ Re-draws the perspective info text. """ @@ -240,11 +250,11 @@ def redraw_perspective_info(self): f"Elevation: {self.view_main.camera.elevation:+3.0f} ° " + \ f"Zoom: {zoom:4.0f}" - def redraw(self): + def redraw(self) -> None: """ Re-draws the entire scene. """ - Debug(self, ".redraw()", color=Theme.SuccessColor) + Debug(self, ".redraw()") self.redraw_start_time = time.monotonic() @@ -283,15 +293,11 @@ def redraw(self): self.redraw_field_labels(colors) redraw_time = time.monotonic() - self.redraw_start_time - Debug( - self, - f".redraw(): Finished (took {redraw_time:.2f} s)", - color=Theme.SuccessColor - ) + Debug(self, f".redraw(): Finished (took {redraw_time:.2f} s)", success=True) # ------------------------------------------------------------------------------------------------------------------ - def redraw_wire_segments(self): + def redraw_wire_segments(self) -> None: """ Re-draws wire segments. """ @@ -301,12 +307,7 @@ def redraw_wire_segments(self): if visible: if self.DebugVisuals: - Debug( - self, - ".redraw_wire_segments(): " - f"pos[{len(self.gui.model.wire.get_points_sliced())}]", - color=(255, 0, 255) - ) + Debug(self, ".redraw_wire_segments(): pos[{len(self.gui.model.wire.get_points_sliced())}]") self.visual_wire_segments.set_data( pos=self.gui.model.wire.get_points_sliced(), @@ -314,7 +315,7 @@ def redraw_wire_segments(self): color=self.foreground ) - def redraw_wire_points_sliced(self): + def redraw_wire_points_sliced(self) -> None: """ Re-draws sliced wire points. """ @@ -326,12 +327,7 @@ def redraw_wire_points_sliced(self): if visible: if self.DebugVisuals: - Debug( - self, - ".redraw_wire_points_sliced(): " - f"pos[{len(self.gui.model.wire.get_points_sliced())}]", - color=(255, 0, 255) - ) + Debug(self, ".redraw_wire_points_sliced(): pos[{len(self.gui.model.wire.get_points_sliced())}]") self.visual_wire_points_sliced.set_data( pos=self.gui.model.wire.get_points_sliced(), @@ -342,7 +338,7 @@ def redraw_wire_points_sliced(self): symbol="disc" ) - def redraw_wire_points_selected(self): + def redraw_wire_points_selected(self) -> None: """ Re-draws selected wire base points. """ @@ -364,12 +360,7 @@ def redraw_wire_points_selected(self): ]) if self.DebugVisuals: - Debug( - self, - ".redraw_wire_points_selected(): " - f"pos[{len(points_selected)}]", - color=(255, 0, 255) - ) + Debug(self, ".redraw_wire_points_selected(): pos[{len(points_selected)}]") self.visual_wire_points_selected.set_data( pos=points_selected, @@ -384,7 +375,7 @@ def redraw_wire_points_selected(self): # ------------------------------------------------------------------------------------------------------------------ - def redraw_field_arrows(self, colors): + def redraw_field_arrows(self, colors: np.ndarray) -> None: """ Re-draws field arrows. @@ -414,12 +405,7 @@ def redraw_field_arrows(self, colors): ) if self.DebugVisuals: - Debug( - self, - ".redraw_field_arrows(): arrow lines: " - f"pos[{len(line_pairs)}] " - f"color[{len(colors)}]", - color=(255, 0, 255)) + Debug(self, ".redraw_field_arrows(): arrow lines: pos[{len(line_pairs)}] color[{len(colors)}]") self.visual_field_arrow_lines.set_data( pos=line_pairs, @@ -428,13 +414,7 @@ def redraw_field_arrows(self, colors): ) if self.DebugVisuals: - Debug( - self, - ".redraw_field_arrows(): arrow heads: " - f"pos[{len(head_points)}] " - f"face_color[{len(colors)}]", - color=(255, 0, 255) - ) + Debug(self, ".redraw_field_arrows(): arrow heads: pos[{len(head_points)}] face_color[{len(colors)}]") self.visual_field_arrow_heads.set_data( pos=head_points, @@ -448,7 +428,7 @@ def redraw_field_arrows(self, colors): self.set_visible(self.visual_field_arrow_lines, visible) self.set_visible(self.visual_field_arrow_heads, visible) - def redraw_field_points(self, colors): + def redraw_field_points(self, colors: np.ndarray) -> None: """ Re-draws field points. @@ -466,9 +446,7 @@ def redraw_field_points(self, colors): Debug( self, ".redraw_field_points(): " - f"pos[{self.gui.model.sampling_volume.get_points_count()}] " - f"face_color[{len(colors)}]", - color=(255, 0, 255) + "pos[{self.gui.model.sampling_volume.get_points_count()}] face_color[{len(colors)}]" ) self.visual_field_points.set_data( @@ -484,14 +462,14 @@ def redraw_field_points(self, colors): # ------------------------------------------------------------------------------------------------------------------ - def create_field_labels(self): + def create_field_labels(self) -> None: """ Creates field labels. """ n = len(self.gui.model.sampling_volume.get_labeled_indices()) if self.DebugVisuals: - Debug(self, f".create_field_labels(): Creating {n} labels …", color=(255, 0, 255), force=self.DebugVisuals) + Debug(self, f".create_field_labels(): Creating {n} labels …") show_gauss = self.gui.config.get_bool("show_gauss") field_units, field_factor = self.gui.model.field.get_units(show_gauss=show_gauss) @@ -523,9 +501,9 @@ def create_field_labels(self): self.visual_field_labels.append(visual) if self.DebugVisuals: - Debug(self, f".create_field_labels(): Created {n} labels", color=(255, 0, 255), force=self.DebugVisuals) + Debug(self, f".create_field_labels(): Created {n} labels") - def delete_field_labels(self): + def delete_field_labels(self) -> None: """ Deletes the field labels. """ @@ -533,18 +511,13 @@ def delete_field_labels(self): visual.parent = None if self.DebugVisuals: - Debug( - self, - f".delete_field_labels(): Deleted {len(self.visual_field_labels)}", - color=(255, 0, 255), - force=self.DebugVisuals - ) + Debug(self, f".delete_field_labels(): Deleted {len(self.visual_field_labels)}") self.visual_field_labels = [] # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - def redraw_field_labels(self, colors): + def redraw_field_labels(self, colors) -> None: """ Re-draws field labels. @@ -563,7 +536,7 @@ def redraw_field_labels(self, colors): self.create_field_labels() if self.DebugVisuals: - Debug(self, f".redraw_field_labels(): Coloring {len(self.visual_field_labels)}", color=(255, 0, 255)) + Debug(self, f".redraw_field_labels(): Coloring {len(self.visual_field_labels)}") # Update label colors for i in range(len(self.visual_field_labels)): @@ -581,10 +554,12 @@ def redraw_field_labels(self, colors): # ------------------------------------------------------------------------------------------------------------------ - def save_image(self, filename: str): + def save_image(self, filename: str) -> None: """ Saves the currently displayed scene to PNG file. @param filename: Filename """ + Debug(self, f".save_image({filename})") + io.write_png(filename, self.render()) diff --git a/magneticalc/Wire.py b/magneticalc/Wire.py index 3c4ae82..5bb95f5 100644 --- a/magneticalc/Wire.py +++ b/magneticalc/Wire.py @@ -16,17 +16,25 @@ # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +from typing import Dict, Tuple, List, Callable import numpy as np from PyQt5.QtCore import QThread from magneticalc.Assert_Dialog import Assert_Dialog from magneticalc.Debug import Debug -from magneticalc.Theme import Theme class Wire: """ Wire class. """ - def __init__(self, points, stretch, rotational_symmetry, close_loop: bool, slicer_limit: float, dc: float): + def __init__( + self, + points: np.ndarray, + stretch: np.ndarray, + rotational_symmetry: Dict, + close_loop: bool, + slicer_limit: float, + dc: float + ) -> None: """ A 3D piecewise linear curve with some DC current associated with it. @@ -78,7 +86,7 @@ def __init__(self, points, stretch, rotational_symmetry, close_loop: bool, slice Assert_Dialog(len(self._points_base) >= 2, "Number of points must be >= 2") - def is_valid(self): + def is_valid(self) -> bool: """ Indicates valid data for display. @@ -88,18 +96,18 @@ def is_valid(self): self._points_sliced is not None and \ self._length is not None - def invalidate(self): + def invalidate(self) -> None: """ Resets data, hiding from display. """ - Debug(self, ".invalidate()", color=Theme.InvalidColor) + Debug(self, ".invalidate()") self._points_sliced = None self._length = None # ------------------------------------------------------------------------------------------------------------------ - def get_bounds(self): + def get_bounds(self) -> Tuple[List, List]: """ Returns this curve's bounding box. @@ -110,7 +118,7 @@ def get_bounds(self): bounds_max = [max(axes[0]), max(axes[1]), max(axes[2])] return bounds_min, bounds_max - def get_points_base(self): + def get_points_base(self) -> np.ndarray: """ Returns this wire's base points. @@ -118,7 +126,7 @@ def get_points_base(self): """ return self._points_base - def get_points_transformed(self): + def get_points_transformed(self) -> np.ndarray: """ Returns this wire's transformed points. @@ -126,7 +134,7 @@ def get_points_transformed(self): """ return self._points_transformed - def get_points_sliced(self): + def get_points_sliced(self) -> np.ndarray: """ Returns this wire's points after slicing. @@ -136,7 +144,7 @@ def get_points_sliced(self): return self._points_sliced - def get_elements(self): + def get_elements(self) -> np.ndarray: """ Returns this curve's elements, i.e. an ordered list of segment center points and directions. @@ -173,7 +181,7 @@ def get_length(self) -> float: # ------------------------------------------------------------------------------------------------------------------ - def _set_stretch(self, stretch): + def _set_stretch(self, stretch: np.ndarray) -> None: """ This transformation stretches (and/or mirrors) this curve by some factor in any direction. Use the factor +1 / -1 to retain / mirror the curve in that direction. @@ -182,7 +190,7 @@ def _set_stretch(self, stretch): @param stretch: XYZ stretch transform factors (3D point) """ - Debug(self, ".stretch()") + Debug(self, "._set_stretch()") axes = self.get_points_transformed().transpose() @@ -191,7 +199,7 @@ def _set_stretch(self, stretch): self._points_transformed = axes.transpose() - def _set_rotational_symmetry(self, parameters, close_loop: bool): + def _set_rotational_symmetry(self, parameters: Dict, close_loop: bool) -> None: """ This transformation replicates and rotates this curve `count` times about an `axis` with radius `radius`. @@ -224,11 +232,9 @@ def _set_rotational_symmetry(self, parameters, close_loop: bool): self._points_transformed = np.array(axes).transpose() - return self - # ------------------------------------------------------------------------------------------------------------------ - def recalculate(self, progress_callback) -> bool: + def recalculate(self, progress_callback: Callable) -> bool: """ Slices wire segments into smaller ones until segment lengths equal or undershoot slicer limit. @@ -257,7 +263,7 @@ def recalculate(self, progress_callback) -> bool: progress_callback(100 * (i + 1) / (len(self.get_points_transformed()) - 1)) if QThread.currentThread().isInterruptionRequested(): - Debug(self, ".recalculate(): Interruption requested, exiting now", color=Theme.PrimaryColor) + Debug(self, ".recalculate(): WARNING: Interruption requested, exiting now", warning=True) return False # Append the very last point since it is not appended by the interpolation above diff --git a/magneticalc/Wire_Presets.py b/magneticalc/Wire_Presets.py index 185e067..9dec903 100644 --- a/magneticalc/Wire_Presets.py +++ b/magneticalc/Wire_Presets.py @@ -16,6 +16,7 @@ # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +from typing import Optional, Dict import numpy as np @@ -185,10 +186,10 @@ class Wire_Presets: @staticmethod def get_phase_jumping_toroidal_loop( - n_points=1000, n_phase_jumps=32, - toroidal_radius=1, poloidal_radius=.5, - toroidal_freq=1, poloidal_freq=32 - ): + n_points: int, n_phase_jumps: int, + toroidal_radius: float, poloidal_radius: float, + toroidal_freq: float, poloidal_freq: float + ) -> np.ndarray: """ Generates a (phase-jumping) toroidal loop. @@ -199,7 +200,7 @@ def get_phase_jumping_toroidal_loop( @param toroidal_freq: Toroidal frequency @param poloidal_freq: Poloidal frequency """ - def rotate_xy(V, A): + def rotate_xy(V: np.ndarray, A: float) -> np.ndarray: """ Rotates a 3D vector some angle in the XY-plane. @@ -222,6 +223,7 @@ def rotate_xy(V, A): return np.array(wire_points) # Preset: A phase-jumping toroidal loop: 8 turns. + # noinspection PyUnresolvedReferences PhaseJumpingToroidalLoop8 = { "id": "Phase-jumping Toroidal Loop: 8 turns", "points": get_phase_jumping_toroidal_loop.__func__( @@ -231,6 +233,7 @@ def rotate_xy(V, A): ) } # Preset: A phase-jumping toroidal loop: 32 turns. + # noinspection PyUnresolvedReferences PhaseJumpingToroidalLoop16 = { "id": "Phase-jumping Toroidal Loop: 16 turns", "points": get_phase_jumping_toroidal_loop.__func__( @@ -240,6 +243,7 @@ def rotate_xy(V, A): ) } # Preset: A phase-jumping toroidal loop: 32 turns. + # noinspection PyUnresolvedReferences PhaseJumpingToroidalLoop32 = { "id": "Phase-jumping Toroidal Loop: 32 turns", "points": get_phase_jumping_toroidal_loop.__func__( @@ -250,6 +254,7 @@ def rotate_xy(V, A): } # Preset: A toroidal loop: 8 turns. + # noinspection PyUnresolvedReferences ToroidalLoop8 = { "id": "Toroidal Loop: 8 turns", "points": get_phase_jumping_toroidal_loop.__func__( @@ -260,6 +265,7 @@ def rotate_xy(V, A): } # Preset: A toroidal loop: 16 turns. + # noinspection PyUnresolvedReferences ToroidalLoop16 = { "id": "Toroidal Loop: 16 turns", "points": get_phase_jumping_toroidal_loop.__func__( @@ -270,6 +276,7 @@ def rotate_xy(V, A): } # Preset: A toroidal loop: 32 turns. + # noinspection PyUnresolvedReferences ToroidalLoop32 = { "id": "Toroidal Loop: 32 turns", "points": get_phase_jumping_toroidal_loop.__func__( @@ -304,7 +311,7 @@ def rotate_xy(V, A): # ------------------------------------------------------------------------------------------------------------------ @staticmethod - def get_by_id(_id_: str): + def get_by_id(_id_: str) -> Optional[Dict]: """ Selects a preset by name. diff --git a/magneticalc/Wire_Widget.py b/magneticalc/Wire_Widget.py index 4f1c4d3..c3335e2 100644 --- a/magneticalc/Wire_Widget.py +++ b/magneticalc/Wire_Widget.py @@ -16,7 +16,8 @@ # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -from typing import Optional, Dict, List +from __future__ import annotations +from typing import Optional, Dict, List, Union import numpy as np import qtawesome as qta from PyQt5.QtCore import Qt @@ -31,6 +32,11 @@ from magneticalc.Theme import Theme from magneticalc.Wire import Wire +# Note: Workaround for type hinting +# noinspection PyUnreachableCode +if False: + from magneticalc.GUI import GUI + class Wire_Widget(QGroupBox2): """ Wire_Widget class. """ @@ -62,25 +68,26 @@ class Wire_Widget(QGroupBox2): DcStep = 0.1 DcPrecision = 3 - def __init__(self, gui): + def __init__(self, gui: GUI) -> None: """ Populates the widget. @param gui: GUI """ - self.gui = gui - QGroupBox2.__init__(self, "Wire") + Debug(self, ": Init") + self.gui = gui # -------------------------------------------------------------------------------------------------------------- table_icon_label = QIconLabel("Points", "mdi.vector-square", final_stretch=False) table_shortcut_label = QLabel("⟨F2⟩, ⟨ESC⟩") - table_shortcut_label.setStyleSheet(f"font-size: 13px; color: {Theme.LightColor}") + table_shortcut_label.setStyleSheet(f"font-size: 13px; color: {Theme.LiteColor}") table_icon_label.addWidget(table_shortcut_label) table_icon_label.addStretch() table_add_button = QPushButton() table_add_button.setIcon(qta.icon("fa.plus")) + # noinspection PyUnresolvedReferences table_add_button.clicked.connect(self.on_table_row_added) table_icon_label.addWidget(table_add_button) table_units_label = QLabel("cm") @@ -103,9 +110,9 @@ def __init__(self, gui): table_total_layout = QHBoxLayout() table_total_label_left = QLabel("Total base points:") - table_total_label_left.setStyleSheet(f"color: {Theme.LightColor}; font-style: italic;") + table_total_label_left.setStyleSheet(f"color: {Theme.LiteColor}; font-style: italic;") self.table_total_label = QLabel("") - self.table_total_label.setStyleSheet(f"color: {Theme.PrimaryColor};") + self.table_total_label.setStyleSheet(f"color: {Theme.MainColor};") self.table_total_label.setAlignment(Qt.AlignRight | Qt.AlignVCenter) table_total_layout.addWidget(table_total_label_left, alignment=Qt.AlignVCenter) table_total_layout.addWidget(self.table_total_label, alignment=Qt.AlignVCenter) @@ -118,6 +125,7 @@ def __init__(self, gui): stretch_icon_label = QIconLabel("Stretch", "mdi.arrow-all") stretch_clear_button = QPushButton() stretch_clear_button.setIcon(qta.icon("fa.eraser")) + # noinspection PyUnresolvedReferences stretch_clear_button.clicked.connect(self.clear_stretch) stretch_icon_label.addWidget(stretch_clear_button) stretch_units_label = QLabel("cm") @@ -136,6 +144,7 @@ def __init__(self, gui): self.stretch_spinbox[i].setMaximum(self.StretchMax) self.stretch_spinbox[i].setSingleStep(self.StretchStep) self.stretch_spinbox[i].setDecimals(self.StretchPrecision) + # noinspection PyUnresolvedReferences self.stretch_spinbox[i].valueChanged.connect(self.set_stretch) stretch_label[i] = QLabel(["X", "Y", "Z"][i] + ":") stretch_label[i].setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Expanding) @@ -150,6 +159,7 @@ def __init__(self, gui): rotational_symmetry_icon_label = QIconLabel("Rotational Symmetry", "mdi.rotate-3d-variant") rotational_symmetry_clear_button = QPushButton() rotational_symmetry_clear_button.setIcon(qta.icon("fa.eraser")) + # noinspection PyUnresolvedReferences rotational_symmetry_clear_button.clicked.connect(self.clear_rotational_symmetry) rotational_symmetry_icon_label.addWidget(rotational_symmetry_clear_button) self.addLayout(rotational_symmetry_icon_label) @@ -173,6 +183,7 @@ def __init__(self, gui): self.rotational_symmetry_count_spinbox, alignment=Qt.AlignVCenter ) + # noinspection PyUnresolvedReferences self.rotational_symmetry_count_spinbox.valueChanged.connect(self.set_rotational_symmetry) rotational_symmetry_layout_right.addWidget(QLabel("")) @@ -195,6 +206,7 @@ def __init__(self, gui): rotational_symmetry_count_radius_label.setAlignment(Qt.AlignRight) rotational_symmetry_count_radius_label.setFixedWidth(self.UnitsLabelWidth) rotational_symmetry_layout_right.addWidget(rotational_symmetry_count_radius_label, alignment=Qt.AlignVCenter) + # noinspection PyUnresolvedReferences self.rotational_symmetry_radius_spinbox.valueChanged.connect(self.set_rotational_symmetry) # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -210,6 +222,7 @@ def __init__(self, gui): alignment=Qt.AlignVCenter ) rotational_symmetry_layout_right.addWidget(QLabel("")) + # noinspection PyUnresolvedReferences self.rotational_symmetry_axis_combobox.currentIndexChanged.connect(self.set_rotational_symmetry) # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -231,6 +244,7 @@ def __init__(self, gui): rotational_symmetry_offset_units_label.setAlignment(Qt.AlignRight) rotational_symmetry_offset_units_label.setFixedWidth(self.UnitsLabelWidth) rotational_symmetry_layout_right.addWidget(rotational_symmetry_offset_units_label, alignment=Qt.AlignVCenter) + # noinspection PyUnresolvedReferences self.rotational_symmetry_offset_spinbox.valueChanged.connect(self.set_rotational_symmetry) self.addLayout(rotational_symmetry_layout) @@ -240,6 +254,7 @@ def __init__(self, gui): self.addWidget(QHLine()) self.close_loop_checkbox = QCheckBox(" Close Loop") + # noinspection PyUnresolvedReferences self.close_loop_checkbox.toggled.connect( lambda: self.set_wire(close_loop=self.close_loop_checkbox.isChecked()) ) @@ -247,9 +262,9 @@ def __init__(self, gui): rotational_symmetry_total_layout = QHBoxLayout() rotational_symmetry_total_label_left = QLabel("Total transformed points:") - rotational_symmetry_total_label_left.setStyleSheet(f"color: {Theme.LightColor}; font-style: italic;") + rotational_symmetry_total_label_left.setStyleSheet(f"color: {Theme.LiteColor}; font-style: italic;") self.transformed_total_label = QLabel("") - self.transformed_total_label.setStyleSheet(f"color: {Theme.PrimaryColor};") + self.transformed_total_label.setStyleSheet(f"color: {Theme.MainColor};") self.transformed_total_label.setAlignment(Qt.AlignRight | Qt.AlignVCenter) rotational_symmetry_total_layout.addWidget( rotational_symmetry_total_label_left, @@ -260,6 +275,7 @@ def __init__(self, gui): replace_base_points_button = QPushButton(" Replace base points") replace_base_points_button.setIcon(qta.icon("mdi.content-copy")) + # noinspection PyUnresolvedReferences replace_base_points_button.clicked.connect( lambda: self.set_wire(points=self.gui.model.wire.get_points_transformed()) ) @@ -276,6 +292,7 @@ def __init__(self, gui): self.slicer_limit_spinbox.setMaximum(self.SlicerLimitMaximum) self.slicer_limit_spinbox.setDecimals(self.SlicerLimitPrecision) self.slicer_limit_spinbox.setSingleStep(self.SlicerLimitStep) + # noinspection PyUnresolvedReferences self.slicer_limit_spinbox.valueChanged.connect( lambda: self.set_wire(slicer_limit=self.slicer_limit_spinbox.value()) ) @@ -289,9 +306,9 @@ def __init__(self, gui): sliced_total_layout = QHBoxLayout() sliced_total_label_left = QLabel("Total sliced points:") - sliced_total_label_left.setStyleSheet(f"color: {Theme.LightColor}; font-style: italic;") + sliced_total_label_left.setStyleSheet(f"color: {Theme.LiteColor}; font-style: italic;") self.sliced_total_label = QLabel("") - self.sliced_total_label.setStyleSheet(f"color: {Theme.PrimaryColor};") + self.sliced_total_label.setStyleSheet(f"color: {Theme.MainColor};") self.sliced_total_label.setAlignment(Qt.AlignRight | Qt.AlignVCenter) sliced_total_layout.addWidget(sliced_total_label_left, alignment=Qt.AlignVCenter) sliced_total_layout.addWidget(self.sliced_total_label, alignment=Qt.AlignVCenter) @@ -308,6 +325,7 @@ def __init__(self, gui): self.dc_spinbox.setMaximum(self.DcMaximum) self.dc_spinbox.setSingleStep(self.DcStep) self.dc_spinbox.setDecimals(self.DcPrecision) + # noinspection PyUnresolvedReferences self.dc_spinbox.valueChanged.connect(lambda: self.set_wire(dc=self.dc_spinbox.value())) dc_layout = QHBoxLayout() dc_layout.addWidget(self.dc_spinbox, alignment=Qt.AlignVCenter) @@ -321,7 +339,7 @@ def __init__(self, gui): self.reinitialize() - def reinitialize(self): + def reinitialize(self) -> None: """ Re-initializes the widget. """ @@ -355,7 +373,7 @@ def reinitialize(self): def set_wire( self, - points: Optional[List] = None, + points: Optional[Union[List, np.ndarray]] = None, stretch: Optional[List] = None, rotational_symmetry: Optional[Dict] = None, close_loop: Optional[bool] = None, @@ -364,7 +382,7 @@ def set_wire( recalculate: bool = True, readjust_sampling_volume: bool = True, invalidate_self: bool = True - ): + ) -> None: """ Sets the wire. This will overwrite the currently set wire in the model. Any parameter may be left set to None in order to load its default value. @@ -384,6 +402,8 @@ def set_wire( if self.signalsBlocked(): return + Debug(self, ".set_wire()") + with ModelAccess(self.gui, recalculate): should_update_stretch_controls = stretch is not None @@ -429,19 +449,23 @@ def set_wire( # ------------------------------------------------------------------------------------------------------------------ - def set_stretch(self): + def set_stretch(self) -> None: """ Handles changes to stretch transform parameters. """ if self.signalsBlocked(): return + Debug(self, ".set_stretch()") + self.set_wire(stretch=[self.stretch_spinbox[i].value() for i in range(3)]) - def clear_stretch(self): + def clear_stretch(self) -> None: """ Clears the stretch values. """ + Debug(self, ".clear_stretch()") + stretch = [1.0, 1.0, 1.0] self.set_wire(stretch=stretch) self.update_stretch(stretch=stretch) @@ -452,6 +476,8 @@ def update_stretch(self, stretch: List) -> None: @param stretch: 3D point """ + Debug(self, ".update_stretch()") + self.blockSignals(True) for i in range(3): self.stretch_spinbox[i].setValue(stretch[i]) @@ -459,13 +485,15 @@ def update_stretch(self, stretch: List) -> None: # ------------------------------------------------------------------------------------------------------------------ - def set_rotational_symmetry(self): + def set_rotational_symmetry(self) -> None: """ Handles changes to rotational symmetry transform parameters. """ if self.signalsBlocked(): return + Debug(self, ".set_rotational_symmetry()") + self.set_wire( rotational_symmetry={ "count" : self.rotational_symmetry_count_spinbox.value(), @@ -475,10 +503,12 @@ def set_rotational_symmetry(self): } ) - def clear_rotational_symmetry(self): + def clear_rotational_symmetry(self) -> None: """ Clears the rotational symmetry values. """ + Debug(self, ".clear_rotational_symmetry()") + rotational_symmetry = { "count": 1, "radius": 0, @@ -488,12 +518,14 @@ def clear_rotational_symmetry(self): self.set_wire(rotational_symmetry=rotational_symmetry) self.update_rotational_symmetry(rotational_symmetry=rotational_symmetry) - def update_rotational_symmetry(self, rotational_symmetry: Dict): + def update_rotational_symmetry(self, rotational_symmetry: Dict) -> None: """ Updates the rotational symmetry controls. @param rotational_symmetry: Dictionary """ + Debug(self, ".update_rotational_symmetry()") + self.blockSignals(True) self.rotational_symmetry_count_spinbox.setValue(rotational_symmetry["count"]) self.rotational_symmetry_radius_spinbox.setValue(rotational_symmetry["radius"]) @@ -503,10 +535,12 @@ def update_rotational_symmetry(self, rotational_symmetry: Dict): # ------------------------------------------------------------------------------------------------------------------ - def update_table(self): + def update_table(self) -> None: """ Populates the table. """ + Debug(self, ".update_table()") + points = [[f"{round(col, 2):+0.02f}" for col in row] for row in self.gui.model.wire.get_points_base()] self.table.clear_rows() @@ -516,43 +550,47 @@ def update_table(self): self.table_total_label.setText(str(len(self.gui.model.wire.get_points_base()))) - def on_table_row_added(self): + def on_table_row_added(self) -> None: """ Gets called after a row has been added to the table. """ + Debug(self, ".on_table_row_added()") # Add a new base point (0, 0, 0) to the wire self.set_wire(points=list(self.gui.model.wire.get_points_base()) + [np.zeros(3)]) self.table.select_last_row() - def on_table_cell_edited(self, value, row, column): + def on_table_cell_edited(self, value: float, row: int, column: int) -> None: """ Gets called after a table cell has been edited. @param value: Cell value - @param row: Row - @param column: Column + @param row: Row index + @param column: Column index """ points = self.gui.model.wire.get_points_base() points[row][column] = value self.set_wire(points=points) - def on_table_row_deleted(self, index): + def on_table_row_deleted(self, index: int) -> None: """ Gets called after a row has been deleted from the table. @param index: Row index """ + Debug(self, ".on_table_row_deleted()") # Delete the wire base point at the given index self.set_wire(points=np.delete(self.gui.model.wire.get_points_base(), index, axis=0)) # ------------------------------------------------------------------------------------------------------------------ - def update_labels(self): + def update_labels(self) -> None: """ Updates the labels. """ + Debug(self, ".update_labels()") + if self.gui.model.wire.is_valid(): self.sliced_total_label.setText(str(len(self.gui.model.wire.get_points_sliced()))) else: diff --git a/magneticalc/__main__.py b/magneticalc/__main__.py index 5075ec1..47ab485 100644 --- a/magneticalc/__main__.py +++ b/magneticalc/__main__.py @@ -22,11 +22,12 @@ import sys from sty import ef from PyQt5.QtWidgets import QApplication +from magneticalc.Config import get_jit_enabled from magneticalc.GUI import GUI from magneticalc.Version import Version -def main(): +def main() -> None: """ MagnetiCalc main function. """ if sys.platform == "win32": @@ -37,6 +38,8 @@ def main(): print(Version.Copyright) print(Version.License) print() + print("JIT is " + ("enabled" if get_jit_enabled() else "disabled")) + print() app = QApplication(sys.argv)
    ModuleComparison_TypesComparison_Types module.
    ModuleConditionalDecoratorConditionalDecorator module.
    Module Config Config module.
    ModuleConfig_GroupConfig_Collection module.
    Module Constants Constants module.
    ModuleNorm_TypesNorm_Types module.
    Module OverridePadding_Dialog OverridePadding_Dialog module.