pypsbuilder 2.6.6__tar.gz → 2.6.8__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {pypsbuilder-2.6.6 → pypsbuilder-2.6.8}/.github/workflows/testing.yml +4 -1
- {pypsbuilder-2.6.6 → pypsbuilder-2.6.8}/.readthedocs.yaml +1 -0
- {pypsbuilder-2.6.6 → pypsbuilder-2.6.8}/CHANGELOG.md +17 -0
- {pypsbuilder-2.6.6 → pypsbuilder-2.6.8}/PKG-INFO +1 -1
- {pypsbuilder-2.6.6 → pypsbuilder-2.6.8}/docs/psbuilders-tutorial.rst +43 -9
- {pypsbuilder-2.6.6 → pypsbuilder-2.6.8}/examples/avgpelite/tc-avgpelite.txt +16 -17
- {pypsbuilder-2.6.6 → pypsbuilder-2.6.8}/pypsbuilder/__init__.py +1 -1
- {pypsbuilder-2.6.6 → pypsbuilder-2.6.8}/pypsbuilder/psbuilders.py +213 -28
- {pypsbuilder-2.6.6 → pypsbuilder-2.6.8}/pypsbuilder/tcapi.py +12 -5
- {pypsbuilder-2.6.6 → pypsbuilder-2.6.8}/pypsbuilder/tcinit.py +50 -18
- pypsbuilder-2.6.8/pypsbuilder/tests/test_psbuilders.py +432 -0
- {pypsbuilder-2.6.6 → pypsbuilder-2.6.8}/pypsbuilder/tests/test_tcapi.py +11 -9
- {pypsbuilder-2.6.6 → pypsbuilder-2.6.8}/pypsbuilder/tests/test_tcinit.py +87 -7
- {pypsbuilder-2.6.6 → pypsbuilder-2.6.8}/pypsbuilder/ui/ptbuilder.ui +12 -0
- {pypsbuilder-2.6.6 → pypsbuilder-2.6.8}/pypsbuilder/ui/pxbuilder.ui +12 -0
- {pypsbuilder-2.6.6 → pypsbuilder-2.6.8}/pypsbuilder/ui/txbuilder.ui +12 -0
- {pypsbuilder-2.6.6 → pypsbuilder-2.6.8}/pypsbuilder/ui_addinv.py +1 -1
- {pypsbuilder-2.6.6 → pypsbuilder-2.6.8}/pypsbuilder/ui_adduni.py +1 -1
- {pypsbuilder-2.6.6 → pypsbuilder-2.6.8}/pypsbuilder/ui_ptbuilder.py +8 -0
- {pypsbuilder-2.6.6 → pypsbuilder-2.6.8}/pypsbuilder/ui_pxbuilder.py +8 -0
- {pypsbuilder-2.6.6 → pypsbuilder-2.6.8}/pypsbuilder/ui_txbuilder.py +8 -0
- {pypsbuilder-2.6.6 → pypsbuilder-2.6.8}/pypsbuilder/ui_uniguess.py +1 -1
- pypsbuilder-2.6.6/pypsbuilder/tests/test_psbuilders.py +0 -200
- {pypsbuilder-2.6.6 → pypsbuilder-2.6.8}/.github/dependabot.yml +0 -0
- {pypsbuilder-2.6.6 → pypsbuilder-2.6.8}/.github/workflows/release.yml +0 -0
- {pypsbuilder-2.6.6 → pypsbuilder-2.6.8}/.github/workflows/testrelease.yml +0 -0
- {pypsbuilder-2.6.6 → pypsbuilder-2.6.8}/.gitignore +0 -0
- {pypsbuilder-2.6.6 → pypsbuilder-2.6.8}/.pre-commit-config.yaml +0 -0
- {pypsbuilder-2.6.6 → pypsbuilder-2.6.8}/.zenodo.json +0 -0
- {pypsbuilder-2.6.6 → pypsbuilder-2.6.8}/AUTHORS.md +0 -0
- {pypsbuilder-2.6.6 → pypsbuilder-2.6.8}/CONTRIBUTING.md +0 -0
- {pypsbuilder-2.6.6 → pypsbuilder-2.6.8}/LICENSE +0 -0
- {pypsbuilder-2.6.6 → pypsbuilder-2.6.8}/README.md +0 -0
- {pypsbuilder-2.6.6 → pypsbuilder-2.6.8}/codecov.yml +0 -0
- {pypsbuilder-2.6.6 → pypsbuilder-2.6.8}/docs/_static/theme_overrides.css +0 -0
- {pypsbuilder-2.6.6 → pypsbuilder-2.6.8}/docs/api/pypsbuilder.psclasses.Dogmin.rst +0 -0
- {pypsbuilder-2.6.6 → pypsbuilder-2.6.8}/docs/api/pypsbuilder.psclasses.InvPoint.rst +0 -0
- {pypsbuilder-2.6.6 → pypsbuilder-2.6.8}/docs/api/pypsbuilder.psclasses.PTsection.rst +0 -0
- {pypsbuilder-2.6.6 → pypsbuilder-2.6.8}/docs/api/pypsbuilder.psclasses.PXsection.rst +0 -0
- {pypsbuilder-2.6.6 → pypsbuilder-2.6.8}/docs/api/pypsbuilder.psclasses.TCResult.rst +0 -0
- {pypsbuilder-2.6.6 → pypsbuilder-2.6.8}/docs/api/pypsbuilder.psclasses.TCResultSet.rst +0 -0
- {pypsbuilder-2.6.6 → pypsbuilder-2.6.8}/docs/api/pypsbuilder.psclasses.TXsection.rst +0 -0
- {pypsbuilder-2.6.6 → pypsbuilder-2.6.8}/docs/api/pypsbuilder.psclasses.UniLine.rst +0 -0
- {pypsbuilder-2.6.6 → pypsbuilder-2.6.8}/docs/api/pypsbuilder.psexplorer.PTPS.rst +0 -0
- {pypsbuilder-2.6.6 → pypsbuilder-2.6.8}/docs/api/pypsbuilder.psexplorer.PXPS.rst +0 -0
- {pypsbuilder-2.6.6 → pypsbuilder-2.6.8}/docs/api/pypsbuilder.psexplorer.TXPS.rst +0 -0
- {pypsbuilder-2.6.6 → pypsbuilder-2.6.8}/docs/api/pypsbuilder.tcapi.TC34API.rst +0 -0
- {pypsbuilder-2.6.6 → pypsbuilder-2.6.8}/docs/api/pypsbuilder.tcapi.TC35API.rst +0 -0
- {pypsbuilder-2.6.6 → pypsbuilder-2.6.8}/docs/api.rst +0 -0
- {pypsbuilder-2.6.6 → pypsbuilder-2.6.8}/docs/authors.rst +0 -0
- {pypsbuilder-2.6.6 → pypsbuilder-2.6.8}/docs/command-line.rst +0 -0
- {pypsbuilder-2.6.6 → pypsbuilder-2.6.8}/docs/conf.py +0 -0
- {pypsbuilder-2.6.6 → pypsbuilder-2.6.8}/docs/images/create_environment.png +0 -0
- {pypsbuilder-2.6.6 → pypsbuilder-2.6.8}/docs/images/crossing.png +0 -0
- {pypsbuilder-2.6.6 → pypsbuilder-2.6.8}/docs/images/delta.png +0 -0
- {pypsbuilder-2.6.6 → pypsbuilder-2.6.8}/docs/images/install_locally.png +0 -0
- {pypsbuilder-2.6.6 → pypsbuilder-2.6.8}/docs/images/invsearch.png +0 -0
- {pypsbuilder-2.6.6 → pypsbuilder-2.6.8}/docs/images/isopleths_1.png +0 -0
- {pypsbuilder-2.6.6 → pypsbuilder-2.6.8}/docs/images/isopleths_2.png +0 -0
- {pypsbuilder-2.6.6 → pypsbuilder-2.6.8}/docs/images/modes.png +0 -0
- {pypsbuilder-2.6.6 → pypsbuilder-2.6.8}/docs/images/psbuilder_areas.png +0 -0
- {pypsbuilder-2.6.6 → pypsbuilder-2.6.8}/docs/images/psbuilder_dogmin.png +0 -0
- {pypsbuilder-2.6.6 → pypsbuilder-2.6.8}/docs/images/psbuilder_finished.png +0 -0
- {pypsbuilder-2.6.6 → pypsbuilder-2.6.8}/docs/images/psbuilder_highlight.png +0 -0
- {pypsbuilder-2.6.6 → pypsbuilder-2.6.8}/docs/images/psbuilder_init.png +0 -0
- {pypsbuilder-2.6.6 → pypsbuilder-2.6.8}/docs/images/psbuilder_inv.png +0 -0
- {pypsbuilder-2.6.6 → pypsbuilder-2.6.8}/docs/images/psbuilder_modes.png +0 -0
- {pypsbuilder-2.6.6 → pypsbuilder-2.6.8}/docs/images/psbuilder_uni.png +0 -0
- {pypsbuilder-2.6.6 → pypsbuilder-2.6.8}/docs/images/psiso_alm.png +0 -0
- {pypsbuilder-2.6.6 → pypsbuilder-2.6.8}/docs/images/psiso_labelkey.png +0 -0
- {pypsbuilder-2.6.6 → pypsbuilder-2.6.8}/docs/images/psiso_mode.png +0 -0
- {pypsbuilder-2.6.6 → pypsbuilder-2.6.8}/docs/images/psiso_other.png +0 -0
- {pypsbuilder-2.6.6 → pypsbuilder-2.6.8}/docs/images/psshow_out.png +0 -0
- {pypsbuilder-2.6.6 → pypsbuilder-2.6.8}/docs/images/ptpath.png +0 -0
- {pypsbuilder-2.6.6 → pypsbuilder-2.6.8}/docs/images/show_data.png +0 -0
- {pypsbuilder-2.6.6 → pypsbuilder-2.6.8}/docs/images/show_grid.png +0 -0
- {pypsbuilder-2.6.6 → pypsbuilder-2.6.8}/docs/images/show_label.png +0 -0
- {pypsbuilder-2.6.6 → pypsbuilder-2.6.8}/docs/images/show_out.png +0 -0
- {pypsbuilder-2.6.6 → pypsbuilder-2.6.8}/docs/images/show_plain.png +0 -0
- {pypsbuilder-2.6.6 → pypsbuilder-2.6.8}/docs/images/status.png +0 -0
- {pypsbuilder-2.6.6 → pypsbuilder-2.6.8}/docs/index.rst +0 -0
- {pypsbuilder-2.6.6 → pypsbuilder-2.6.8}/docs/psexplorer-tutorial.rst +0 -0
- {pypsbuilder-2.6.6 → pypsbuilder-2.6.8}/docs/readme.rst +0 -0
- {pypsbuilder-2.6.6 → pypsbuilder-2.6.8}/environment.yml +0 -0
- {pypsbuilder-2.6.6 → pypsbuilder-2.6.8}/examples/avgpelite/tc-ds62.txt +0 -0
- {pypsbuilder-2.6.6 → pypsbuilder-2.6.8}/examples/avgpelite/tc-mp50MnNCKFMASHTO.txt +0 -0
- {pypsbuilder-2.6.6 → pypsbuilder-2.6.8}/examples/avgpelite/tc-prefs.txt +0 -0
- {pypsbuilder-2.6.6 → pypsbuilder-2.6.8}/examples/avgpelite_34/tc-6axmn.txt +0 -0
- {pypsbuilder-2.6.6 → pypsbuilder-2.6.8}/examples/avgpelite_34/tc-avgpelite.txt +0 -0
- {pypsbuilder-2.6.6 → pypsbuilder-2.6.8}/examples/avgpelite_34/tc-ds62.txt +0 -0
- {pypsbuilder-2.6.6 → pypsbuilder-2.6.8}/examples/avgpelite_34/tc-prefs.txt +0 -0
- {pypsbuilder-2.6.6 → pypsbuilder-2.6.8}/examples/outputs/inv1-ic.txt +0 -0
- {pypsbuilder-2.6.6 → pypsbuilder-2.6.8}/examples/outputs/inv1-log.txt +0 -0
- {pypsbuilder-2.6.6 → pypsbuilder-2.6.8}/examples/outputs/inv2-ic.txt +0 -0
- {pypsbuilder-2.6.6 → pypsbuilder-2.6.8}/examples/outputs/inv2-log.txt +0 -0
- {pypsbuilder-2.6.6 → pypsbuilder-2.6.8}/examples/outputs/inv3-ic.txt +0 -0
- {pypsbuilder-2.6.6 → pypsbuilder-2.6.8}/examples/outputs/inv3-log.txt +0 -0
- {pypsbuilder-2.6.6 → pypsbuilder-2.6.8}/examples/outputs/uni1-ic.txt +0 -0
- {pypsbuilder-2.6.6 → pypsbuilder-2.6.8}/examples/outputs/uni1-log.txt +0 -0
- {pypsbuilder-2.6.6 → pypsbuilder-2.6.8}/examples/outputs/uni2-ic.txt +0 -0
- {pypsbuilder-2.6.6 → pypsbuilder-2.6.8}/examples/outputs/uni2-log.txt +0 -0
- {pypsbuilder-2.6.6 → pypsbuilder-2.6.8}/examples/outputs/uni3-ic.txt +0 -0
- {pypsbuilder-2.6.6 → pypsbuilder-2.6.8}/examples/outputs/uni3-log.txt +0 -0
- {pypsbuilder-2.6.6 → pypsbuilder-2.6.8}/notebooks/pypsbuilder.ipynb +0 -0
- {pypsbuilder-2.6.6 → pypsbuilder-2.6.8}/pyproject.toml +0 -0
- {pypsbuilder-2.6.6 → pypsbuilder-2.6.8}/pypsbuilder/images/ptbuilder.png +0 -0
- {pypsbuilder-2.6.6 → pypsbuilder-2.6.8}/pypsbuilder/images/pxbuilder.png +0 -0
- {pypsbuilder-2.6.6 → pypsbuilder-2.6.8}/pypsbuilder/images/pypsbuilder.png +0 -0
- {pypsbuilder-2.6.6 → pypsbuilder-2.6.8}/pypsbuilder/images/txbuilder.png +0 -0
- {pypsbuilder-2.6.6 → pypsbuilder-2.6.8}/pypsbuilder/psclasses.py +0 -0
- {pypsbuilder-2.6.6 → pypsbuilder-2.6.8}/pypsbuilder/psexplorer.py +0 -0
- {pypsbuilder-2.6.6 → pypsbuilder-2.6.8}/pypsbuilder/tests/__init__.py +0 -0
- {pypsbuilder-2.6.6 → pypsbuilder-2.6.8}/pypsbuilder/tests/test_pclasses.py +0 -0
- {pypsbuilder-2.6.6 → pypsbuilder-2.6.8}/pypsbuilder/tests/test_psclasses.py +0 -0
- {pypsbuilder-2.6.6 → pypsbuilder-2.6.8}/pypsbuilder/tests/test_psexplorer.py +0 -0
- {pypsbuilder-2.6.6 → pypsbuilder-2.6.8}/pypsbuilder/ui/addinv.ui +0 -0
- {pypsbuilder-2.6.6 → pypsbuilder-2.6.8}/pypsbuilder/ui/adduni.ui +0 -0
- {pypsbuilder-2.6.6 → pypsbuilder-2.6.8}/pypsbuilder/ui/compile_ui.sh +0 -0
- {pypsbuilder-2.6.6 → pypsbuilder-2.6.8}/pypsbuilder/ui/uniguess.ui +0 -0
|
@@ -9,9 +9,11 @@ on:
|
|
|
9
9
|
jobs:
|
|
10
10
|
build:
|
|
11
11
|
name: Package testing
|
|
12
|
-
runs-on:
|
|
12
|
+
runs-on: ${{ matrix.os }}
|
|
13
13
|
strategy:
|
|
14
|
+
fail-fast: false
|
|
14
15
|
matrix:
|
|
16
|
+
os: [ubuntu-latest, windows-latest, macos-latest]
|
|
15
17
|
python-version: ["3.12", "3.13", "3.14"]
|
|
16
18
|
|
|
17
19
|
env:
|
|
@@ -28,6 +30,7 @@ jobs:
|
|
|
28
30
|
enable-cache: true
|
|
29
31
|
|
|
30
32
|
- name: Install Qt runtime dependencies
|
|
33
|
+
if: runner.os == 'Linux'
|
|
31
34
|
run: |
|
|
32
35
|
sudo apt-get update
|
|
33
36
|
sudo apt-get install -y libegl1 libxkbcommon0
|
|
@@ -1,6 +1,23 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
All notable pypsbuilder changes.
|
|
3
3
|
|
|
4
|
+
## [2.6.8] - 2026-09-05
|
|
5
|
+
### Added
|
|
6
|
+
- `Export JSON` menu item added to ptbuilder/txbuilder/pxbuilder File menu, exporting invariant points and univariant lines in a schema readable back in by `Import from JSON`
|
|
7
|
+
### Fixed
|
|
8
|
+
- TC35API rejects `omit` scriptfile script as unrecognised (discontinued in THERMOCALC 3.51); use `with`/`inexcess` instead
|
|
9
|
+
- TC35API bombed-run detection matches THERMOCALC 3.51's actual `-- run bombed` output
|
|
10
|
+
- About, Modes and Full TC output dialogs no longer get hidden behind the main builder window; About dialog now also shows the builder's icon
|
|
11
|
+
- `Import from JSON` no longer requires an empty project; existing invariant points/univariant lines are left untouched and only genuinely new entries are calculated. It seeds THERMOCALC ptguesses from the nearest already-calculated invariant point before each calculation
|
|
12
|
+
- `tcinit`'s bundled TC 3.51 starting-guess template used inconsistent solution-model names (`L`, `pl`, `ksp` instead of `liq`, `pl4tr`, `k4tr`) for the same phases it names correctly elsewhere in the template
|
|
13
|
+
### Changed
|
|
14
|
+
- CI test matrix now runs on Linux, Windows and macOS (in addition to the existing Python version matrix)
|
|
15
|
+
|
|
16
|
+
## [2.6.7] - 2026-08-29
|
|
17
|
+
### Added
|
|
18
|
+
- `tcinit` now prompts for the P-T range (`[pmin, pmax, tmin, tmax]`), used to set the generated scriptfile's `diagramPT`/`calcP`/`calcT` lines
|
|
19
|
+
- `tcinit` creates the destination directory automatically when it doesn't exist yet but its parent does
|
|
20
|
+
|
|
4
21
|
## [2.6.6] - 2026-08-29
|
|
5
22
|
### Fixed
|
|
6
23
|
- project extra jupyter renamed to lab
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: pypsbuilder
|
|
3
|
-
Version: 2.6.
|
|
3
|
+
Version: 2.6.8
|
|
4
4
|
Summary: THERMOCALC front-end for constructing and analyzing PT pseudosections
|
|
5
5
|
Project-URL: Homepage, https://github.com/ondrolexa/pypsbuilder
|
|
6
6
|
Project-URL: Documentation, https://pypsbuilder.readthedocs.io
|
|
@@ -65,18 +65,23 @@ Using tcinit to setup working directory
|
|
|
65
65
|
---------------------------------------
|
|
66
66
|
|
|
67
67
|
For TC3.5 you can use the ``tcinit`` command to initialize a working
|
|
68
|
-
directory. Run it
|
|
68
|
+
directory. Run it and answer the prompts::
|
|
69
69
|
|
|
70
70
|
$ tcinit
|
|
71
71
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
(
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
72
|
+
You will be asked for a project directory (defaults to the current
|
|
73
|
+
directory; if it doesn't exist yet but its parent does, it is created for
|
|
74
|
+
you automatically), a project name (max 8 characters), the P-T range to use
|
|
75
|
+
(``[pmin, pmax, tmin, tmax]``, defaulting to ``[1.9, 10.1, 345, 805]`` and
|
|
76
|
+
written into the scriptfile's ``diagramPT``/``calcP``/``calcT`` lines), and
|
|
77
|
+
one of four bundled datasets/a-x files: ``metapelite``, ``metabasite``,
|
|
78
|
+
``igg25`` (igneous, White et al. 2025 update) or ``igw24`` (igneous, Weller
|
|
79
|
+
et al. 2024). It then downloads THERMOCALC 3.51 for your platform (Linux,
|
|
80
|
+
Windows or macOS). The chosen dataset, a-x file, starting guesses and
|
|
81
|
+
preferences file are written into the project directory, already tagged
|
|
82
|
+
with the ``%{PSBGUESS-...}``, ``%{PSBCALC-...}`` and ``%{PSBBULK-...}``
|
|
83
|
+
blocks described above, so the resulting scriptfile works with
|
|
84
|
+
``ptbuilder``/``txbuilder``/``pxbuilder`` out of the box.
|
|
80
85
|
|
|
81
86
|
|
|
82
87
|
New P-T pseudosection project
|
|
@@ -245,6 +250,35 @@ When you have already calculated invariant points and lines and you want to use
|
|
|
245
250
|
them in separate project, create new project, set axes limits properly and
|
|
246
251
|
use `File>Import > Import into range` to read it.
|
|
247
252
|
|
|
253
|
+
Import and export JSON
|
|
254
|
+
-----------------------
|
|
255
|
+
|
|
256
|
+
Besides the ``.ptb``/``.txb``/``.pxb`` project files, invariant points and
|
|
257
|
+
univariant lines can be exchanged as plain JSON, e.g. to share a
|
|
258
|
+
pseudosection's topology without the project file, or to seed a new project
|
|
259
|
+
from results calculated elsewhere.
|
|
260
|
+
|
|
261
|
+
``File>Export>Export JSON...`` writes the current project's invariant points
|
|
262
|
+
and univariant lines to a JSON file with top-level keys ``kind`` (``"PT"``,
|
|
263
|
+
``"TX"`` or ``"PX"``), ``P``/``T`` (the diagram's fixed P or T value for
|
|
264
|
+
T-X/P-X sections, otherwise its ``[min, max]`` range), and ``inv``/``uni``
|
|
265
|
+
lists. Each entry in ``inv``/``uni`` carries ``P``/``T``/``X`` (a
|
|
266
|
+
``[min, max]`` range, or ``null`` for the axis unused by this builder's
|
|
267
|
+
``kind``), ``phases`` and ``out`` (the zero-mode phase(s): two for an
|
|
268
|
+
invariant point, one for a univariant line).
|
|
269
|
+
|
|
270
|
+
``File>Import>Import from JSON...`` reads such a file back and calculates any
|
|
271
|
+
invariant point or univariant line not already present in the project
|
|
272
|
+
(existing ones are left untouched and reported as duplicates). Its P/T range
|
|
273
|
+
must fit inside the project's own diagram window, and phases referenced in
|
|
274
|
+
the file that aren't defined in this project prompt for a replacement name
|
|
275
|
+
(or are resolved from a ``phase_map`` when calling ``import_from_json()``
|
|
276
|
+
from a script). Each calculation is seeded from the nearest already
|
|
277
|
+
calculated invariant point, invariant points that fail on the first pass are
|
|
278
|
+
retried once more points are available as seeds, and univariant lines are
|
|
279
|
+
stepped along whichever axis they run along more, at a resolution capped
|
|
280
|
+
relative to the full diagram range.
|
|
281
|
+
|
|
248
282
|
T-X and P-X pseudosections
|
|
249
283
|
--------------------------
|
|
250
284
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
% ==================================================================
|
|
2
2
|
% Scriptfile for pypsbuilder calculation
|
|
3
|
-
%
|
|
3
|
+
%
|
|
4
4
|
% Use "%" for commenting (nothing is read between % and the line ending).
|
|
5
5
|
% No lines are read after the "*" character.
|
|
6
6
|
% DO NOT REMOVE pypsbuilder TAGS !!!
|
|
@@ -16,7 +16,6 @@ autoexit
|
|
|
16
16
|
|
|
17
17
|
inexcess q H2O
|
|
18
18
|
%tozero H2O
|
|
19
|
-
omit sp0 sp1 Ni NiO opx sp ta plc abh ilmm hemm ilm0 ksp0 mt0 mt1 heme
|
|
20
19
|
|
|
21
20
|
% =======================
|
|
22
21
|
% which conditions
|
|
@@ -61,7 +60,7 @@ samecoding plc pl % rename Cbar1 plagioclase as 'pl'
|
|
|
61
60
|
|
|
62
61
|
%{PSBGUESS-BEGIN}
|
|
63
62
|
% ----------------------------------------------------------
|
|
64
|
-
% at P = 5.5, T = 500, for: g pl mu bi chl ab ru q H2O
|
|
63
|
+
% at P = 5.5, T = 500, for: g pl mu bi chl ab ru q H2O
|
|
65
64
|
% ----------------------------------------------------------
|
|
66
65
|
ptguess 5.539 500.35
|
|
67
66
|
% ----------------------------------------------------------
|
|
@@ -98,7 +97,7 @@ xyzguess Q4(chl) 0.0941449 range -1.000 1.000
|
|
|
98
97
|
|
|
99
98
|
% --------------------------------------------------------
|
|
100
99
|
% Starting guesses in MnNCKFMASHTO (over-ridden by any above)
|
|
101
|
-
% for g liq pl ksp ep ma mu pa bi opx sa cd st chl ctd sp mt ilmm hemm ilm hem mt1
|
|
100
|
+
% for g liq pl ksp ep ma mu pa bi opx sa cd st chl ctd sp mt ilmm hemm ilm hem mt1
|
|
102
101
|
% --------------------------------------------------------
|
|
103
102
|
|
|
104
103
|
xyzguess x(g) 0.824169
|
|
@@ -121,9 +120,9 @@ xyzguess na(ksp) 0.227897
|
|
|
121
120
|
xyzguess ca(ksp) 0.0114380
|
|
122
121
|
|
|
123
122
|
xyzguess f(ep) 0.379418
|
|
124
|
-
xyzguess Q(ep) 0.346850 range 0.000 0.500
|
|
123
|
+
xyzguess Q(ep) 0.346850 range 0.000 0.500
|
|
125
124
|
|
|
126
|
-
xyzguess x(ma) 0.6
|
|
125
|
+
xyzguess x(ma) 0.6
|
|
127
126
|
xyzguess y(ma) 0.96
|
|
128
127
|
xyzguess f(ma) 0.001
|
|
129
128
|
xyzguess n(ma) 0.05
|
|
@@ -133,7 +132,7 @@ xyzguess x(mu) 0.501982
|
|
|
133
132
|
xyzguess y(mu) 0.839614
|
|
134
133
|
xyzguess f(mu) 0.0172093
|
|
135
134
|
xyzguess n(mu) 0.144000
|
|
136
|
-
xyzguess c(mu) 0.00179401
|
|
135
|
+
xyzguess c(mu) 0.00179401
|
|
137
136
|
|
|
138
137
|
xyzguess x(pa) 0.501982
|
|
139
138
|
xyzguess y(pa) 0.998030
|
|
@@ -153,7 +152,7 @@ xyzguess m(opx) 0.001
|
|
|
153
152
|
xyzguess y(opx) 0.128377 range 0.000 2.000
|
|
154
153
|
xyzguess f(opx) 0.01
|
|
155
154
|
xyzguess c(opx) 0.01
|
|
156
|
-
xyzguess Q(opx) 0.216433
|
|
155
|
+
xyzguess Q(opx) 0.216433
|
|
157
156
|
|
|
158
157
|
xyzguess x(sa) 0.1
|
|
159
158
|
xyzguess y(sa) 0.3
|
|
@@ -181,13 +180,13 @@ xyzguess x(ctd) 0.990857
|
|
|
181
180
|
xyzguess m(ctd) 0.001
|
|
182
181
|
xyzguess f(ctd) 0.01
|
|
183
182
|
|
|
184
|
-
xyzguess x(sp) 0.6
|
|
185
|
-
xyzguess y(sp) 0.95
|
|
186
|
-
xyzguess z(sp) 0.01
|
|
183
|
+
xyzguess x(sp) 0.6
|
|
184
|
+
xyzguess y(sp) 0.95
|
|
185
|
+
xyzguess z(sp) 0.01
|
|
187
186
|
|
|
188
|
-
xyzguess x(mt) 0.85
|
|
189
|
-
xyzguess y(mt) 0.05
|
|
190
|
-
xyzguess z(mt) 0.01
|
|
187
|
+
xyzguess x(mt) 0.85
|
|
188
|
+
xyzguess y(mt) 0.05
|
|
189
|
+
xyzguess z(mt) 0.01
|
|
191
190
|
|
|
192
191
|
xyzguess i(ilmm) 0.858568
|
|
193
192
|
xyzguess g(ilmm) 0.0294376
|
|
@@ -199,11 +198,11 @@ xyzguess g(hemm) 0.00296953
|
|
|
199
198
|
xyzguess m(hemm) 0.0305831
|
|
200
199
|
xyzguess Q(hemm) -0.0102634 range -0.300 0.300
|
|
201
200
|
|
|
202
|
-
xyzguess x(ilm) 0.80
|
|
201
|
+
xyzguess x(ilm) 0.80
|
|
203
202
|
xyzguess Q(ilm) 0.01 range -0.990 0.990
|
|
204
203
|
|
|
205
|
-
xyzguess x(hem) 0.20
|
|
206
|
-
xyzguess Q(hem) 0.8 range -0.99 0.99
|
|
204
|
+
xyzguess x(hem) 0.20
|
|
205
|
+
xyzguess Q(hem) 0.8 range -0.99 0.99
|
|
207
206
|
|
|
208
207
|
xyzguess x(mt1) 0.632160
|
|
209
208
|
xyzguess Q(mt1) 0.564334
|
|
@@ -81,6 +81,10 @@ app_icons = dict(
|
|
|
81
81
|
PXBuilder="images/pxbuilder.png",
|
|
82
82
|
)
|
|
83
83
|
|
|
84
|
+
# maps a section's x_var/y_var ("T"/"p"/"C") to the JSON entry key that
|
|
85
|
+
# carries that axis's [min, max] span ("T"/"P"/"X")
|
|
86
|
+
json_key_for_var = {"T": "T", "p": "P", "C": "X"}
|
|
87
|
+
|
|
84
88
|
|
|
85
89
|
class BuildersBase(QtWidgets.QMainWindow):
|
|
86
90
|
"""Main base class for pseudosection builders."""
|
|
@@ -96,7 +100,9 @@ class BuildersBase(QtWidgets.QMainWindow):
|
|
|
96
100
|
)
|
|
97
101
|
self.setWindowIcon(QtGui.QIcon(window_icon))
|
|
98
102
|
self.__changed = False
|
|
99
|
-
self.about_dialog = AboutDialog(
|
|
103
|
+
self.about_dialog = AboutDialog(
|
|
104
|
+
self.builder_name, __version__, __copyright__, window_icon, parent=self
|
|
105
|
+
)
|
|
100
106
|
self.unihigh = None
|
|
101
107
|
self.invhigh = None
|
|
102
108
|
self.outhigh = None
|
|
@@ -274,6 +280,7 @@ class BuildersBase(QtWidgets.QMainWindow):
|
|
|
274
280
|
self.actionAbout.triggered.connect(self.about_dialog.exec)
|
|
275
281
|
self.actionImport_project.triggered.connect(self.import_from_prj)
|
|
276
282
|
self.actionImport_json.triggered.connect(lambda: self.import_from_json())
|
|
283
|
+
self.actionExport_json.triggered.connect(lambda: self.export_to_json())
|
|
277
284
|
self.actionCleanup.triggered.connect(self.cleanup_storage)
|
|
278
285
|
self.actionFixphase.triggered.connect(self.fix_phasenames)
|
|
279
286
|
self.actionShow_areas.triggered.connect(self.check_prj_areas)
|
|
@@ -701,16 +708,70 @@ class BuildersBase(QtWidgets.QMainWindow):
|
|
|
701
708
|
entry["out"] = [mapping.get(p, p) for p in entry.get("out", [])]
|
|
702
709
|
return True
|
|
703
710
|
|
|
711
|
+
def _entry_xy(self, entry):
|
|
712
|
+
"""Midpoint (x, y) of a JSON inv/uni entry in diagram (ps.xrange/yrange) units."""
|
|
713
|
+
xv = entry.get(json_key_for_var[self.ps.x_var])
|
|
714
|
+
yv = entry.get(json_key_for_var[self.ps.y_var])
|
|
715
|
+
if xv is None or yv is None:
|
|
716
|
+
return None, None
|
|
717
|
+
return sum(xv) / 2, sum(yv) / 2
|
|
718
|
+
|
|
719
|
+
def _nearest_invpoint(self, x, y):
|
|
720
|
+
"""Closest existing InvPoint to (x, y), distance normalized by
|
|
721
|
+
ps.xrange/yrange, or None if there's nothing to compare against.
|
|
722
|
+
"""
|
|
723
|
+
if x is None or y is None or not self.ps.invpoints:
|
|
724
|
+
return None
|
|
725
|
+
xspan = self.ps.xrange[1] - self.ps.xrange[0]
|
|
726
|
+
yspan = self.ps.yrange[1] - self.ps.yrange[0]
|
|
727
|
+
if xspan <= 0 or yspan <= 0:
|
|
728
|
+
return None
|
|
729
|
+
return min(
|
|
730
|
+
self.ps.invpoints.values(),
|
|
731
|
+
key=lambda inv: ((inv._x - x) / xspan) ** 2 + ((inv._y - y) / yspan) ** 2,
|
|
732
|
+
)
|
|
733
|
+
|
|
734
|
+
def _seed_guess_from_nearest(self, entry):
|
|
735
|
+
"""Seed the scriptfile's ptguesses from the nearest already-calculated
|
|
736
|
+
invariant point to this JSON entry, mirroring invsel_guesses's manual
|
|
737
|
+
`update_scriptfile(guesses=inv.ptguess())` pattern.
|
|
738
|
+
"""
|
|
739
|
+
nearest = self._nearest_invpoint(*self._entry_xy(entry))
|
|
740
|
+
if nearest is not None:
|
|
741
|
+
self.tc.update_scriptfile(guesses=nearest.ptguess())
|
|
742
|
+
|
|
743
|
+
def _autoconnect_inv(self, inv, id_inv):
|
|
744
|
+
"""Connect any univariant line that now has both its endpoints
|
|
745
|
+
calculated, mirroring the manual autoconnect behavior.
|
|
746
|
+
"""
|
|
747
|
+
for uni in self.ps.unilines.values():
|
|
748
|
+
if uni.contains_inv(inv):
|
|
749
|
+
candidates = [inv]
|
|
750
|
+
for other_inv in self.ps.invpoints.values():
|
|
751
|
+
if other_inv.id != id_inv and uni.contains_inv(other_inv):
|
|
752
|
+
candidates.append(other_inv)
|
|
753
|
+
if len(candidates) == 2:
|
|
754
|
+
self.uni_connect(uni.id, candidates)
|
|
755
|
+
|
|
756
|
+
def _import_step_count(self, span, full_span):
|
|
757
|
+
"""Step count so the physical step used for a JSON-imported univariant
|
|
758
|
+
line is never finer than 1/200 of the full pseudosection range for
|
|
759
|
+
the axis being stepped (a floor on step size), capped at
|
|
760
|
+
spinSteps.value().
|
|
761
|
+
"""
|
|
762
|
+
if full_span <= 0 or span <= 0:
|
|
763
|
+
return self.spinSteps.value()
|
|
764
|
+
min_step = full_span / 200
|
|
765
|
+
max_steps = int(span / min_step)
|
|
766
|
+
return max(min(self.spinSteps.value(), max_steps), 1)
|
|
767
|
+
|
|
704
768
|
def import_from_json(self, jsonfile=None, phase_map=None):
|
|
705
|
-
if not
|
|
706
|
-
self.ready and len(self.ps.invpoints) == 0 and len(self.ps.unilines) == 0
|
|
707
|
-
):
|
|
769
|
+
if not self.ready:
|
|
708
770
|
qb = QtWidgets.QMessageBox
|
|
709
771
|
qb.critical(
|
|
710
772
|
self,
|
|
711
773
|
"Cannot import",
|
|
712
|
-
"Import from JSON requires an initialized
|
|
713
|
-
"(no invariant points or univariant lines yet).",
|
|
774
|
+
"Import from JSON requires an initialized project.",
|
|
714
775
|
qb.StandardButton.Abort,
|
|
715
776
|
)
|
|
716
777
|
return
|
|
@@ -747,10 +808,14 @@ class BuildersBase(QtWidgets.QMainWindow):
|
|
|
747
808
|
n_uni_ok = n_uni_fail = n_uni_dup = 0
|
|
748
809
|
QtWidgets.QApplication.setOverrideCursor(QtCore.Qt.CursorShape.WaitCursor)
|
|
749
810
|
try:
|
|
811
|
+
# Round 1: attempt every new invariant point once. Entries that
|
|
812
|
+
# fail are retried in round 2 below, once other points from this
|
|
813
|
+
# same import are available as nearby ptguess seeds.
|
|
750
814
|
n = len(data["inv"])
|
|
815
|
+
retry = []
|
|
751
816
|
for i, entry in enumerate(data["inv"]):
|
|
752
817
|
self.statusBar().showMessage(
|
|
753
|
-
"Importing invariant point {}/{}...".format(i + 1, n)
|
|
818
|
+
"Importing invariant point {}/{} (round 1)...".format(i + 1, n)
|
|
754
819
|
)
|
|
755
820
|
QtWidgets.QApplication.processEvents()
|
|
756
821
|
try:
|
|
@@ -766,6 +831,27 @@ class BuildersBase(QtWidgets.QMainWindow):
|
|
|
766
831
|
if not isnew:
|
|
767
832
|
n_inv_dup += 1
|
|
768
833
|
continue
|
|
834
|
+
self._seed_guess_from_nearest(entry)
|
|
835
|
+
inv = self._import_calc_inv(inv_tmp.phases, inv_tmp.out)
|
|
836
|
+
if inv is None:
|
|
837
|
+
retry.append((id_inv, inv_tmp, entry))
|
|
838
|
+
continue
|
|
839
|
+
self.invmodel.appendRow(id_inv, inv)
|
|
840
|
+
n_inv_ok += 1
|
|
841
|
+
if self.checkAutoconnectInv.isChecked():
|
|
842
|
+
self._autoconnect_inv(inv, id_inv)
|
|
843
|
+
self.plot()
|
|
844
|
+
|
|
845
|
+
# Round 2: retry points that failed in round 1, now that any
|
|
846
|
+
# points calculated in round 1 are available as nearby ptguess
|
|
847
|
+
# seeds too.
|
|
848
|
+
n = len(retry)
|
|
849
|
+
for i, (id_inv, inv_tmp, entry) in enumerate(retry):
|
|
850
|
+
self.statusBar().showMessage(
|
|
851
|
+
"Importing invariant point {}/{} (round 2)...".format(i + 1, n)
|
|
852
|
+
)
|
|
853
|
+
QtWidgets.QApplication.processEvents()
|
|
854
|
+
self._seed_guess_from_nearest(entry)
|
|
769
855
|
inv = self._import_calc_inv(inv_tmp.phases, inv_tmp.out)
|
|
770
856
|
if inv is None:
|
|
771
857
|
n_inv_fail += 1
|
|
@@ -773,16 +859,8 @@ class BuildersBase(QtWidgets.QMainWindow):
|
|
|
773
859
|
self.invmodel.appendRow(id_inv, inv)
|
|
774
860
|
n_inv_ok += 1
|
|
775
861
|
if self.checkAutoconnectInv.isChecked():
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
candidates = [inv]
|
|
779
|
-
for other_inv in self.ps.invpoints.values():
|
|
780
|
-
if other_inv.id != id_inv and uni.contains_inv(
|
|
781
|
-
other_inv
|
|
782
|
-
):
|
|
783
|
-
candidates.append(other_inv)
|
|
784
|
-
if len(candidates) == 2:
|
|
785
|
-
self.uni_connect(uni.id, candidates)
|
|
862
|
+
self._autoconnect_inv(inv, id_inv)
|
|
863
|
+
self.plot()
|
|
786
864
|
|
|
787
865
|
n = len(data["uni"])
|
|
788
866
|
for j, entry in enumerate(data["uni"]):
|
|
@@ -803,6 +881,7 @@ class BuildersBase(QtWidgets.QMainWindow):
|
|
|
803
881
|
if not isnew:
|
|
804
882
|
n_uni_dup += 1
|
|
805
883
|
continue
|
|
884
|
+
self._seed_guess_from_nearest(entry)
|
|
806
885
|
uni = self._import_calc_uni(uni_tmp.phases, uni_tmp.out, entry)
|
|
807
886
|
if uni is None:
|
|
808
887
|
n_uni_fail += 1
|
|
@@ -814,13 +893,13 @@ class BuildersBase(QtWidgets.QMainWindow):
|
|
|
814
893
|
n_uni_ok += 1
|
|
815
894
|
if self.checkAutoconnectUni.isChecked() and len(candidates) == 2:
|
|
816
895
|
self.uni_connect(id_uni, candidates)
|
|
896
|
+
self.plot()
|
|
817
897
|
finally:
|
|
818
898
|
QtWidgets.QApplication.restoreOverrideCursor()
|
|
819
899
|
|
|
820
900
|
self.changed = True
|
|
821
901
|
self.invview.resizeColumnsToContents()
|
|
822
902
|
self.uniview.resizeColumnsToContents()
|
|
823
|
-
self.plot()
|
|
824
903
|
summary = (
|
|
825
904
|
"Imported {}/{} invariant points and {}/{} univariant lines from JSON."
|
|
826
905
|
).format(n_inv_ok, len(data["inv"]), n_uni_ok, len(data["uni"]))
|
|
@@ -834,6 +913,73 @@ class BuildersBase(QtWidgets.QMainWindow):
|
|
|
834
913
|
).format(n_inv_dup, n_uni_dup)
|
|
835
914
|
self.statusBar().showMessage(summary)
|
|
836
915
|
|
|
916
|
+
def _build_export_json(self):
|
|
917
|
+
"""Build the JSON-serializable dict of current invariant points and
|
|
918
|
+
univariant lines. Kept free of Qt/file I/O so it can be tested
|
|
919
|
+
directly against a duck-typed stand-in for self.
|
|
920
|
+
"""
|
|
921
|
+
kind_map = {"PTBuilder": "PT", "TXBuilder": "TX", "PXBuilder": "PX"}
|
|
922
|
+
kind = kind_map[self.builder_name]
|
|
923
|
+
|
|
924
|
+
def axes(x0, x1, y0, y1):
|
|
925
|
+
if kind == "PT":
|
|
926
|
+
return {"P": [y0, y1], "T": [x0, x1], "X": None}
|
|
927
|
+
elif kind == "TX":
|
|
928
|
+
return {"P": None, "T": [x0, x1], "X": [y0, y1]}
|
|
929
|
+
else: # PX
|
|
930
|
+
return {"P": [y0, y1], "T": None, "X": [x0, x1]}
|
|
931
|
+
|
|
932
|
+
if kind == "TX":
|
|
933
|
+
P = float(sum(self.tc.prange) / 2)
|
|
934
|
+
T = [float(v) for v in self.ps.xrange]
|
|
935
|
+
elif kind == "PX":
|
|
936
|
+
P = [float(v) for v in self.ps.yrange]
|
|
937
|
+
T = float(sum(self.tc.trange) / 2)
|
|
938
|
+
else:
|
|
939
|
+
P = [float(v) for v in self.ps.yrange]
|
|
940
|
+
T = [float(v) for v in self.ps.xrange]
|
|
941
|
+
|
|
942
|
+
inv_list = []
|
|
943
|
+
for inv in self.ps.invpoints.values():
|
|
944
|
+
entry = axes(inv._x, inv._x, inv._y, inv._y)
|
|
945
|
+
entry["phases"] = sorted(inv.phases)
|
|
946
|
+
entry["out"] = sorted(inv.out)
|
|
947
|
+
inv_list.append(entry)
|
|
948
|
+
|
|
949
|
+
uni_list = []
|
|
950
|
+
for uni in self.ps.unilines.values():
|
|
951
|
+
entry = axes(
|
|
952
|
+
float(uni.x.min()),
|
|
953
|
+
float(uni.x.max()),
|
|
954
|
+
float(uni.y.min()),
|
|
955
|
+
float(uni.y.max()),
|
|
956
|
+
)
|
|
957
|
+
entry["phases"] = sorted(uni.phases)
|
|
958
|
+
entry["out"] = sorted(uni.out)
|
|
959
|
+
uni_list.append(entry)
|
|
960
|
+
|
|
961
|
+
return {"kind": kind, "P": P, "T": T, "inv": inv_list, "uni": uni_list}
|
|
962
|
+
|
|
963
|
+
def export_to_json(self):
|
|
964
|
+
if not self.ready:
|
|
965
|
+
self.statusBar().showMessage("Project is not yet initialized.")
|
|
966
|
+
return
|
|
967
|
+
filename = QtWidgets.QFileDialog.getSaveFileName(
|
|
968
|
+
self, "Export to JSON", str(self.tc.workdir), "JSON file (*.json)"
|
|
969
|
+
)[0]
|
|
970
|
+
if not filename:
|
|
971
|
+
return
|
|
972
|
+
if not filename.lower().endswith(".json"):
|
|
973
|
+
filename = filename + ".json"
|
|
974
|
+
data = self._build_export_json()
|
|
975
|
+
with open(filename, "w", encoding="utf-8") as f:
|
|
976
|
+
json.dump(data, f, indent=2)
|
|
977
|
+
self.statusBar().showMessage(
|
|
978
|
+
"Exported {} invariant points and {} univariant lines to {}".format(
|
|
979
|
+
len(data["inv"]), len(data["uni"]), filename
|
|
980
|
+
)
|
|
981
|
+
)
|
|
982
|
+
|
|
837
983
|
def cleanup_storage(self):
|
|
838
984
|
if self.ready:
|
|
839
985
|
qb = QtWidgets.QMessageBox
|
|
@@ -1057,10 +1203,12 @@ class BuildersBase(QtWidgets.QMainWindow):
|
|
|
1057
1203
|
def show_output(self, int):
|
|
1058
1204
|
if self.ready:
|
|
1059
1205
|
if int == 0:
|
|
1060
|
-
dia = OutputDialog("Modes", self.textOutput.toPlainText())
|
|
1206
|
+
dia = OutputDialog("Modes", self.textOutput.toPlainText(), parent=self)
|
|
1061
1207
|
dia.exec()
|
|
1062
1208
|
if int == 1:
|
|
1063
|
-
dia = OutputDialog(
|
|
1209
|
+
dia = OutputDialog(
|
|
1210
|
+
"TC output", self.textFullOutput.toPlainText(), parent=self
|
|
1211
|
+
)
|
|
1064
1212
|
dia.exec()
|
|
1065
1213
|
|
|
1066
1214
|
def toolbar_mode_name(self):
|
|
@@ -3126,12 +3274,22 @@ class PTBuilder(BuildersBase, Ui_PTBuilder):
|
|
|
3126
3274
|
results=res,
|
|
3127
3275
|
)
|
|
3128
3276
|
|
|
3277
|
+
def _uni_calc_strategy(self, p0, p1, t0, t1):
|
|
3278
|
+
""" "calc_p" (steps T, calctatp no) or "calc_t" (steps P, calctatp
|
|
3279
|
+
yes) for a JSON-imported univariant line spanning [p0, p1] x
|
|
3280
|
+
[t0, t1]: step through whichever axis spans proportionally more of
|
|
3281
|
+
the full pseudosection range - i.e. the axis the line runs along
|
|
3282
|
+
more, as plotted - and solve for the other.
|
|
3283
|
+
"""
|
|
3284
|
+
ratio_P = (p1 - p0) / (self.tc.prange[1] - self.tc.prange[0])
|
|
3285
|
+
ratio_T = (t1 - t0) / (self.tc.trange[1] - self.tc.trange[0])
|
|
3286
|
+
return "calc_p" if ratio_P < ratio_T else "calc_t"
|
|
3287
|
+
|
|
3129
3288
|
def _import_calc_uni(self, phases, out, entry):
|
|
3130
3289
|
try:
|
|
3131
|
-
p0, p1 = entry["P"]
|
|
3132
|
-
t0, t1 = entry["T"]
|
|
3133
|
-
|
|
3134
|
-
ratio_T = (t1 - t0) / (self.tc.trange[1] - self.tc.trange[0])
|
|
3290
|
+
p0, p1 = sorted(entry["P"])
|
|
3291
|
+
t0, t1 = sorted(entry["T"])
|
|
3292
|
+
strategy = self._uni_calc_strategy(p0, p1, t0, t1)
|
|
3135
3293
|
except (KeyError, TypeError, ValueError, ZeroDivisionError):
|
|
3136
3294
|
return None
|
|
3137
3295
|
# extend by 10% of the JSON line's own P/T span to minimize
|
|
@@ -3140,13 +3298,19 @@ class PTBuilder(BuildersBase, Ui_PTBuilder):
|
|
|
3140
3298
|
text = 0.1 * (t1 - t0)
|
|
3141
3299
|
prange = (max(p0 - pext, self.tc.prange[0]), min(p1 + pext, self.tc.prange[1]))
|
|
3142
3300
|
trange = (max(t0 - text, self.tc.trange[0]), min(t1 + text, self.tc.trange[1]))
|
|
3143
|
-
calc = self.tc
|
|
3301
|
+
calc = getattr(self.tc, strategy)
|
|
3302
|
+
if strategy == "calc_p":
|
|
3303
|
+
span = trange[1] - trange[0]
|
|
3304
|
+
full_span = self.tc.trange[1] - self.tc.trange[0]
|
|
3305
|
+
else:
|
|
3306
|
+
span = prange[1] - prange[0]
|
|
3307
|
+
full_span = self.tc.prange[1] - self.tc.prange[0]
|
|
3144
3308
|
tcout, ans = calc(
|
|
3145
3309
|
phases,
|
|
3146
3310
|
out,
|
|
3147
3311
|
prange=prange,
|
|
3148
3312
|
trange=trange,
|
|
3149
|
-
steps=self.
|
|
3313
|
+
steps=self._import_step_count(span, full_span),
|
|
3150
3314
|
)
|
|
3151
3315
|
status, res, output = self.tc.parse_logfile()
|
|
3152
3316
|
if status in ("bombed", "nir") or len(res) < 2:
|
|
@@ -5647,12 +5811,28 @@ class UniGuess(QtWidgets.QDialog, Ui_UniGuess):
|
|
|
5647
5811
|
class AboutDialog(QtWidgets.QDialog):
|
|
5648
5812
|
"""About dialog"""
|
|
5649
5813
|
|
|
5650
|
-
def __init__(self, builder, version, copyright, parent=None):
|
|
5814
|
+
def __init__(self, builder, version, copyright, icon=None, parent=None):
|
|
5651
5815
|
"""Display a dialog that shows application information."""
|
|
5652
5816
|
super(AboutDialog, self).__init__(parent)
|
|
5653
5817
|
|
|
5654
5818
|
self.setWindowTitle("About")
|
|
5655
|
-
self.resize(
|
|
5819
|
+
self.resize(320, 220)
|
|
5820
|
+
# keep the dialog above the main window (and everything else)
|
|
5821
|
+
# instead of a plain modal QDialog, which some window managers can
|
|
5822
|
+
# still push behind the parent window
|
|
5823
|
+
self.setWindowFlags(
|
|
5824
|
+
self.windowFlags() | QtCore.Qt.WindowType.WindowStaysOnTopHint
|
|
5825
|
+
)
|
|
5826
|
+
|
|
5827
|
+
if icon is not None:
|
|
5828
|
+
self.setWindowIcon(QtGui.QIcon(icon))
|
|
5829
|
+
logo = QtWidgets.QLabel()
|
|
5830
|
+
logo.setPixmap(
|
|
5831
|
+
QtGui.QIcon(icon).pixmap(
|
|
5832
|
+
64, 64, QtGui.QIcon.Mode.Normal, QtGui.QIcon.State.On
|
|
5833
|
+
)
|
|
5834
|
+
)
|
|
5835
|
+
logo.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter)
|
|
5656
5836
|
|
|
5657
5837
|
title = QtWidgets.QLabel("{} {}".format(builder, version))
|
|
5658
5838
|
title.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter)
|
|
@@ -5682,6 +5862,8 @@ class AboutDialog(QtWidgets.QDialog):
|
|
|
5682
5862
|
self.layout = QtWidgets.QVBoxLayout()
|
|
5683
5863
|
self.layout.setAlignment(QtCore.Qt.AlignmentFlag.AlignVCenter)
|
|
5684
5864
|
|
|
5865
|
+
if icon is not None:
|
|
5866
|
+
self.layout.addWidget(logo)
|
|
5685
5867
|
self.layout.addWidget(title)
|
|
5686
5868
|
self.layout.addWidget(suptitle)
|
|
5687
5869
|
self.layout.addWidget(author)
|
|
@@ -5700,6 +5882,9 @@ class OutputDialog(QtWidgets.QDialog):
|
|
|
5700
5882
|
|
|
5701
5883
|
self.setWindowTitle(title)
|
|
5702
5884
|
self.resize(800, 600)
|
|
5885
|
+
self.setWindowFlags(
|
|
5886
|
+
self.windowFlags() | QtCore.Qt.WindowType.WindowStaysOnTopHint
|
|
5887
|
+
)
|
|
5703
5888
|
|
|
5704
5889
|
self.plainText = QtWidgets.QPlainTextEdit(self)
|
|
5705
5890
|
self.plainText.setLineWrapMode(QtWidgets.QPlainTextEdit.LineWrapMode.NoWrap)
|
|
@@ -507,9 +507,10 @@ class TC35API(TCAPI):
|
|
|
507
507
|
# omit
|
|
508
508
|
errinfo = "Wrong omit in scriptfile."
|
|
509
509
|
if "omit" in scripts:
|
|
510
|
-
|
|
510
|
+
raise ScriptfileError("omit, is unrecognised (or discontinued).")
|
|
511
511
|
else:
|
|
512
512
|
self.omit = set()
|
|
513
|
+
errinfo = "Error in scriptfile."
|
|
513
514
|
# autoexit
|
|
514
515
|
if "autoexit" not in scripts:
|
|
515
516
|
raise ScriptfileError(
|
|
@@ -541,15 +542,21 @@ class TC35API(TCAPI):
|
|
|
541
542
|
"Dogmin script should be removed from scriptfile."
|
|
542
543
|
)
|
|
543
544
|
# union ax phases and samecoding and diff omit
|
|
544
|
-
if "
|
|
545
|
-
raise TCError(self.tcout.split("BOMBED")[1].split(os.linesep)[0])
|
|
546
|
-
else:
|
|
545
|
+
if "reading ax:" in self.tcout:
|
|
547
546
|
ax_phases = set(
|
|
548
547
|
self.tcout.split("reading ax:")[1]
|
|
549
548
|
.split(2 * os.linesep)[0]
|
|
550
549
|
.split()
|
|
551
550
|
)
|
|
552
551
|
self.phases = ax_phases.union(*self.samecoding) - self.omit
|
|
552
|
+
else:
|
|
553
|
+
if "-- run bombed" in self.tcout:
|
|
554
|
+
raise TCError(
|
|
555
|
+
"-- run bombed"
|
|
556
|
+
+ self.tcout.split("-- run bombed")[1].split(os.linesep)[0]
|
|
557
|
+
)
|
|
558
|
+
else:
|
|
559
|
+
raise TCError("Unspecified error")
|
|
553
560
|
# OK
|
|
554
561
|
self.status = "Initial check done."
|
|
555
562
|
self.OK = True
|
|
@@ -573,7 +580,7 @@ class TC35API(TCAPI):
|
|
|
573
580
|
self.OK = False
|
|
574
581
|
|
|
575
582
|
def parse_logfile(self, **kwargs):
|
|
576
|
-
"""Parser for THERMOCALC 3.
|
|
583
|
+
"""Parser for THERMOCALC 3.51 output.
|
|
577
584
|
|
|
578
585
|
It parses the outputs of THERMOCALC after calculation.
|
|
579
586
|
|