elasticipy 4.2.0__py3-none-any.whl → 6.0.0__py3-none-any.whl

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.
Files changed (36) hide show
  1. {Elasticipy → elasticipy}/FourthOrderTensor.py +4 -4
  2. elasticipy/StressStrainTensors.py +16 -0
  3. {Elasticipy → elasticipy}/ThermalExpansion.py +3 -3
  4. elasticipy/gui/__init__.py +3 -0
  5. elasticipy/gui/about.py +49 -0
  6. {Elasticipy → elasticipy/gui}/gui.py +218 -42
  7. elasticipy/gui/rotate_window.py +79 -0
  8. {Elasticipy → elasticipy}/interfaces/FEPX.py +5 -5
  9. {Elasticipy → elasticipy}/interfaces/PRISMS.py +2 -2
  10. {Elasticipy → elasticipy}/plasticity.py +180 -35
  11. elasticipy/resources/favicon.png +0 -0
  12. elasticipy/resources/logo_text.svg +126 -0
  13. {Elasticipy → elasticipy}/spherical_function.py +44 -5
  14. elasticipy/tensors/__init__.py +0 -0
  15. {Elasticipy → elasticipy}/tensors/elasticity.py +678 -152
  16. elasticipy/tensors/fourth_order.py +1385 -0
  17. elasticipy/tensors/mapping.py +92 -0
  18. {Elasticipy → elasticipy}/tensors/second_order.py +56 -14
  19. elasticipy/tensors/stress_strain.py +360 -0
  20. {Elasticipy → elasticipy}/tensors/thermal_expansion.py +8 -3
  21. {elasticipy-4.2.0.dist-info → elasticipy-6.0.0.dist-info}/METADATA +41 -22
  22. elasticipy-6.0.0.dist-info/RECORD +30 -0
  23. elasticipy-6.0.0.dist-info/entry_points.txt +2 -0
  24. elasticipy-6.0.0.dist-info/top_level.txt +1 -0
  25. Elasticipy/StressStrainTensors.py +0 -16
  26. Elasticipy/tensors/fourth_order.py +0 -662
  27. Elasticipy/tensors/mapping.py +0 -44
  28. Elasticipy/tensors/stress_strain.py +0 -154
  29. elasticipy-4.2.0.dist-info/RECORD +0 -23
  30. elasticipy-4.2.0.dist-info/top_level.txt +0 -1
  31. {Elasticipy → elasticipy}/__init__.py +0 -0
  32. {Elasticipy → elasticipy}/crystal_symmetries.py +0 -0
  33. {Elasticipy/tensors → elasticipy/interfaces}/__init__.py +0 -0
  34. {Elasticipy → elasticipy}/polefigure.py +0 -0
  35. {elasticipy-4.2.0.dist-info → elasticipy-6.0.0.dist-info}/WHEEL +0 -0
  36. {elasticipy-4.2.0.dist-info → elasticipy-6.0.0.dist-info}/licenses/LICENSE +0 -0
@@ -1,10 +1,10 @@
1
1
  import warnings
2
- from Elasticipy.tensors.elasticity import StiffnessTensor as NewStiffnessTensor
3
- from Elasticipy.tensors.elasticity import ComplianceTensor as NewComplianceTensor
2
+ from elasticipy.tensors.elasticity import StiffnessTensor as NewStiffnessTensor
3
+ from elasticipy.tensors.elasticity import ComplianceTensor as NewComplianceTensor
4
4
 
5
5
  warnings.warn(
6
- "The module 'Elasticipy.FourthOrderTensor' is deprecated and will be removed in a future release. "
7
- "Please use 'Elasticipy.tensors.elasticity' instead.",
6
+ "The module 'elasticipy.FourthOrderTensor' is deprecated and will be removed in a future release. "
7
+ "Please use 'elasticipy.tensors.elasticity' instead.",
8
8
  DeprecationWarning,
9
9
  stacklevel=2
10
10
  )
@@ -0,0 +1,16 @@
1
+ import warnings
2
+ from elasticipy.tensors.stress_strain import StressTensor as NewStressTensor
3
+ from elasticipy.tensors.stress_strain import StrainTensor as NewStrainTensor
4
+
5
+ warnings.warn(
6
+ "The module 'elasticipy.StressStrainTensors' is deprecated and will be removed in a future release. "
7
+ "Please use 'elasticipy.tensors.stress_strain' instead.",
8
+ DeprecationWarning,
9
+ stacklevel=2
10
+ )
11
+
12
+ class StressTensor(NewStressTensor):
13
+ pass
14
+
15
+ class StrainTensor(NewStrainTensor):
16
+ pass
@@ -1,9 +1,9 @@
1
1
  import warnings
2
- from Elasticipy.tensors.thermal_expansion import ThermalExpansionTensor as NewThermalExpansionTensor
2
+ from elasticipy.tensors.thermal_expansion import ThermalExpansionTensor as NewThermalExpansionTensor
3
3
 
4
4
  warnings.warn(
5
- "The module 'Elasticipy.ThermalExpansion' is deprecated and will be removed in a future release. "
6
- "Please use 'Elasticipy.tensors.thermal_expansion' instead.",
5
+ "The module 'elasticipy.ThermalExpansion' is deprecated and will be removed in a future release. "
6
+ "Please use 'elasticipy.tensors.thermal_expansion' instead.",
7
7
  DeprecationWarning,
8
8
  stacklevel=2
9
9
  )
@@ -0,0 +1,3 @@
1
+ from .gui import crystal_elastic_plotter
2
+
3
+ __all__ = ["crystal_elastic_plotter"]
@@ -0,0 +1,49 @@
1
+ from qtpy.QtWidgets import QVBoxLayout, QLabel, QPushButton
2
+ from qtpy.QtGui import QPixmap
3
+ from qtpy.QtCore import Qt
4
+
5
+ def about(dialog, logo_path):
6
+ dialog.setWindowTitle("About elasticipy")
7
+ dialog.setFixedWidth(400)
8
+
9
+ layout = QVBoxLayout(dialog)
10
+
11
+ if logo_path.exists():
12
+ logo = QLabel()
13
+ pixmap = QPixmap(str(logo_path))
14
+ pixmap = pixmap.scaledToWidth(250, Qt.SmoothTransformation)
15
+ logo.setPixmap(pixmap)
16
+ logo.setAlignment(Qt.AlignCenter)
17
+ layout.addWidget(logo)
18
+
19
+ # --- Text ---
20
+ text = QLabel(
21
+ "A Python library for elasticity tensors computations<br><br>"
22
+ "© 2024–2025 Dorian Depriester, MIT Licence"
23
+ )
24
+ text.setAlignment(Qt.AlignCenter)
25
+ layout.addWidget(text)
26
+
27
+ # --- Link ---
28
+ link = QLabel(
29
+ '<a href="https://elasticipy.readthedocs.io/">'
30
+ 'https://elasticipy.readthedocs.io/</a>'
31
+ )
32
+ link.setAlignment(Qt.AlignCenter)
33
+ link.setOpenExternalLinks(True)
34
+ layout.addWidget(link)
35
+
36
+ # --- Bug report ---
37
+ link = QLabel(
38
+ '<a href="https://github.com/DorianDepriester/Elasticipy/issues">'
39
+ 'Report a bug</a>'
40
+ )
41
+ link.setAlignment(Qt.AlignCenter)
42
+ link.setOpenExternalLinks(True)
43
+ layout.addWidget(link)
44
+
45
+ # --- Close button ---
46
+ close_btn = QPushButton("Close")
47
+ close_btn.clicked.connect(dialog.close)
48
+ layout.addWidget(close_btn)
49
+ return dialog
@@ -1,24 +1,35 @@
1
1
  import sys
2
-
3
2
  import numpy as np
4
3
  from qtpy.QtWidgets import (
5
- QApplication, QMainWindow, QComboBox, QGridLayout, QLabel,
6
- QLineEdit, QPushButton, QVBoxLayout, QHBoxLayout, QWidget, QFrame, QMessageBox
4
+ QApplication, QMainWindow, QComboBox, QGridLayout, QLineEdit, QWidget, QFrame, QMessageBox
7
5
  )
6
+ from qtpy.QtGui import QIcon
8
7
  from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
9
8
  from matplotlib.figure import Figure
10
9
 
11
- from Elasticipy.crystal_symmetries import SYMMETRIES
12
- from Elasticipy.tensors.elasticity import StiffnessTensor
10
+ from elasticipy.crystal_symmetries import SYMMETRIES
11
+ from elasticipy.gui.rotate_window import EulerBungeDialog
12
+ from elasticipy.gui.about import about
13
+ from elasticipy.tensors.elasticity import StiffnessTensor
14
+ from pathlib import Path
15
+
16
+ from scipy.spatial.transform import Rotation
13
17
 
14
18
  WHICH_OPTIONS = {'Mean': 'mean', 'Max': 'max', 'Min': 'min', 'Std. dev.': 'std'}
15
19
 
20
+ # --- Logo ---
21
+ here = Path(__file__).resolve().parent
22
+ LOGO_PATH = here / ".." / "resources" / "logo_text.svg"
23
+ ICON_PATH = here / ".." / "resources" / "favicon.png"
24
+
16
25
  class ElasticityGUI(QMainWindow):
17
26
  def __init__(self):
18
27
  super().__init__()
28
+ self.C_stiff = None
19
29
  self.coefficient_fields = {}
20
- self.setWindowTitle("Elasticipy - GUI")
30
+ self.setWindowTitle("elasticipy - GUI")
21
31
  self.initUI()
32
+ self.C_invar= np.zeros(7)
22
33
 
23
34
  def selected_symmetry(self):
24
35
  symmetry_name = self.symmetry_selector.currentText()
@@ -53,6 +64,7 @@ class ElasticityGUI(QMainWindow):
53
64
 
54
65
  # Space Group selection
55
66
  self.point_group_selector = QComboBox()
67
+ self.point_group_selector.setMinimumWidth(140)
56
68
  self.point_group_selector.addItems(['', ''])
57
69
  self.point_group_selector.currentIndexChanged.connect(self.update_fields)
58
70
  selectors_layout.addWidget(QLabel("Point group:"))
@@ -65,6 +77,14 @@ class ElasticityGUI(QMainWindow):
65
77
  selectors_layout.addWidget(QLabel("Diad convention:"))
66
78
  selectors_layout.addWidget(self.diag_selector)
67
79
 
80
+ # About button
81
+ self.about_button = QPushButton("About")
82
+ self.about_button.setFixedHeight(24)
83
+ self.about_button.setMaximumWidth(60)
84
+ self.about_button.clicked.connect(self.show_about)
85
+ selectors_layout.addStretch()
86
+ selectors_layout.addWidget(self.about_button)
87
+
68
88
  # Add horizontal separator
69
89
  separator = QFrame()
70
90
  separator.setFrameShape(QFrame.HLine)
@@ -125,12 +145,96 @@ class ElasticityGUI(QMainWindow):
125
145
 
126
146
  # Plot button
127
147
  self.calculate_button = QPushButton("Plot")
148
+ self.calculate_button.setEnabled(False)
128
149
  self.calculate_button.clicked.connect(self.calculate_and_plot)
129
150
  left_panel_layout.addWidget(self.calculate_button)
130
151
 
152
+ self.euler_button = QPushButton("Apply rotation")
153
+ self.euler_button.setEnabled(False)
154
+ self.euler_button.setToolTip("Rotate stiffness tensor (Bunge ZXZ)")
155
+ self.euler_button.clicked.connect(self.open_euler_dialog)
156
+ left_panel_layout.addWidget(self.euler_button)
157
+
158
+ # Add horizontal separator
159
+ separator = QFrame()
160
+ separator.setFrameShape(QFrame.HLine)
161
+ separator.setFrameShadow(QFrame.Sunken)
162
+ left_panel_layout.addWidget(separator)
163
+
164
+ ############################################
165
+ # Numeric results
166
+ ############################################
167
+ self.result_labels = {}
168
+ RESULT_GROUPS = {
169
+ "Young modulus": [
170
+ ("E_mean", "Mean"),
171
+ ("E_voigt", "Voigt"),
172
+ ("E_reuss", "Reuss"),
173
+ ("E_hill", "Hill"),
174
+ ],
175
+ "Shear modulus": [
176
+ ("G_mean", "Mean"),
177
+ ("G_voigt", "Voigt"),
178
+ ("G_reuss", "Reuss"),
179
+ ("G_hill", "Hill"),
180
+ ],
181
+ "Poisson ratio": [
182
+ ("nu_mean", "Mean"),
183
+ ("nu_voigt", "Voigt"),
184
+ ("nu_reuss", "Reuss"),
185
+ ("nu_hill", "Hill"),
186
+ ],
187
+ "Linear compressibility (x1000)": [
188
+ ("Beta_mean", "Mean"),
189
+ ("Beta_voigt", "Voigt"),
190
+ ("Beta_reuss", "Reuss"),
191
+ ("Beta_hill", "Hill"),
192
+ ],
193
+ "Other": [
194
+ ("K", "Bulk modulus"),
195
+ ("Z", "Zener ratio"),
196
+ ("A", "Univ. anisotropy factor"),
197
+ ]
198
+ }
199
+
200
+ ############################################
201
+ # Numeric results (grouped)
202
+ ############################################
203
+ self.result_labels = {}
204
+ for group_name, items in RESULT_GROUPS.items():
205
+
206
+ # Group title
207
+ group_label = QLabel(group_name + ":")
208
+ group_label.setStyleSheet("font-weight: bold; margin-top: 6px;")
209
+ left_panel_layout.addWidget(group_label)
210
+
211
+ # Indented layout
212
+ indent_layout = QVBoxLayout()
213
+ indent_layout.setContentsMargins(15, 0, 0, 0)
214
+
215
+ for key, label_text in items:
216
+ row = QHBoxLayout()
217
+
218
+ label_name = QLabel(f"{label_text}:")
219
+ label_value = QLabel("—")
220
+ label_value.setMinimumWidth(100)
221
+ label_value.setStyleSheet("font-family: Consolas, Courier;")
222
+
223
+ self.result_labels[key] = label_value
224
+
225
+ row.addWidget(label_name)
226
+ row.addStretch()
227
+ row.addWidget(label_value)
228
+
229
+ indent_layout.addLayout(row)
230
+
231
+ left_panel_layout.addLayout(indent_layout)
232
+
131
233
  # Fill space
132
234
  left_panel_layout.addStretch()
133
- bottom_layout.addLayout(left_panel_layout)
235
+
236
+
237
+ bottom_layout.addLayout(left_panel_layout,1)
134
238
 
135
239
  ############################################
136
240
  # Plotting area
@@ -143,7 +247,7 @@ class ElasticityGUI(QMainWindow):
143
247
 
144
248
  self.figure = Figure()
145
249
  self.canvas = FigureCanvas(self.figure)
146
- bottom_layout.addWidget(self.canvas)
250
+ bottom_layout.addWidget(self.canvas,4)
147
251
 
148
252
  #######################################################################################
149
253
  # Main widget
@@ -160,6 +264,7 @@ class ElasticityGUI(QMainWindow):
160
264
  self.plotting_selector.setCurrentText('Young modulus')
161
265
  self.which_selector.setEnabled(False)
162
266
 
267
+
163
268
  def update_fields(self):
164
269
  # Deactivate unused fields
165
270
  active_fields = self.selected_symmetry().required
@@ -193,42 +298,48 @@ class ElasticityGUI(QMainWindow):
193
298
  self.which_selector.setEnabled(True)
194
299
 
195
300
  def calculate_and_plot(self):
196
- """Collect entries and compute the stiffness tensor"""
197
- coefficients = np.zeros((6, 6))
198
- for (i, j), field in self.coefficient_fields.items():
301
+ stiff = self.C_stiff
302
+ self.figure.clear()
303
+ requested_value = self.plotting_selector.currentText()
304
+ if requested_value == "Young modulus":
305
+ value = stiff.Young_modulus
306
+ plot_kwargs = {}
307
+ elif requested_value == 'Linear compressibility':
308
+ value = stiff.linear_compressibility
309
+ plot_kwargs = {}
310
+ else:
311
+ if requested_value == 'Shear modulus':
312
+ value = stiff.shear_modulus
313
+ else:
314
+ value = stiff.Poisson_ratio
315
+ plot_kwargs = {'which': WHICH_OPTIONS[self.which_selector.currentText()]}
316
+ if self.plot_style_selector.currentIndex() == 0:
317
+ value.plot3D(fig=self.figure, **plot_kwargs)
318
+ elif self.plot_style_selector.currentIndex() == 1:
319
+ value.plot_xyz_sections(fig=self.figure)
320
+ else:
321
+ value.plot_as_pole_figure(fig=self.figure, **plot_kwargs)
322
+ self.canvas.draw()
323
+ invariants = np.array(stiff.linear_invariants() + stiff.quadratic_invariants())
324
+ if not np.all(np.isclose(invariants, self.C_invar)):
325
+ self.C_invar = invariants
326
+ self.result_labels["E_mean"].setText(f"{stiff.Young_modulus.mean():.3f}")
327
+ self.result_labels["G_mean"].setText(f"{stiff.shear_modulus.mean():.3f}")
328
+ self.result_labels["nu_mean"].setText(f"{stiff.Poisson_ratio.mean():.3f}")
329
+ self.result_labels["Beta_mean"].setText(f"{stiff.linear_compressibility.mean()*1000:.3f}")
330
+ for method in ['voigt', 'reuss', 'hill']:
331
+ C = stiff.average(method=method)
332
+ self.result_labels[f"E_{method}"].setText(f"{C.Young_modulus.eval([1,0,0]):.3f}")
333
+ self.result_labels[f"G_{method}"].setText(f"{C.shear_modulus.eval([1, 0, 0],[0,1,0]):.3f}")
334
+ self.result_labels[f"nu_{method}"].setText(f"{C.Poisson_ratio.eval([1, 0, 0], [0, 1, 0]):.3f}")
335
+ self.result_labels[f"Beta_{method}"].setText(f"{C.linear_compressibility.eval([1, 0, 0])*1000:.3f}")
336
+ self.result_labels["K"].setText(f"{stiff.bulk_modulus:.3f}")
199
337
  try:
200
- coefficients[i, j] = float(field.text())
338
+ Z = stiff.Zener_ratio()
339
+ self.result_labels["Z"].setText(f"{stiff.Zener_ratio():.3f}")
201
340
  except ValueError:
202
- coefficients[i, j] = 0
203
- C = np.array(coefficients)
204
- Csym = C + np.tril(C.T, -1) # Rebuild the lower triangular part
205
-
206
- try:
207
- stiff = StiffnessTensor(Csym)
208
- self.figure.clear()
209
- requested_value = self.plotting_selector.currentText()
210
- if requested_value == "Young modulus":
211
- value = stiff.Young_modulus
212
- plot_kwargs = {}
213
- elif requested_value == 'Linear compressibility':
214
- value = stiff.linear_compressibility
215
- plot_kwargs = {}
216
- else:
217
- if requested_value == 'Shear modulus':
218
- value = stiff.shear_modulus
219
- else:
220
- value = stiff.Poisson_ratio
221
- plot_kwargs = {'which': WHICH_OPTIONS[self.which_selector.currentText()]}
222
- if self.plot_style_selector.currentIndex() == 0:
223
- value.plot3D(fig=self.figure, **plot_kwargs)
224
- elif self.plot_style_selector.currentIndex() == 1:
225
- value.plot_xyz_sections(fig=self.figure)
226
- else:
227
- value.plot_as_pole_figure(fig=self.figure, **plot_kwargs)
228
- self.canvas.draw()
229
-
230
- except ValueError as inst:
231
- QMessageBox.critical(self, "Singular stiffness", inst.__str__(), QMessageBox.Ok)
341
+ self.result_labels["Z"].setText("—")
342
+ self.result_labels["A"].setText(f"{stiff.universal_anisotropy:.3f}")
232
343
 
233
344
 
234
345
  def update_dependent_fields(self):
@@ -255,9 +366,74 @@ class ElasticityGUI(QMainWindow):
255
366
  self.coefficient_fields[index].setText(f"{0.5*(C11-C12)}")
256
367
  except ValueError:
257
368
  pass
369
+ coefficients = np.zeros((6, 6))
370
+ for (i, j), field in self.coefficient_fields.items():
371
+ try:
372
+ coefficients[i, j] = float(field.text())
373
+ except ValueError:
374
+ coefficients[i, j] = 0
375
+ Csym = coefficients + np.tril(coefficients.T, -1) # Rebuild the lower triangular part
376
+ try:
377
+ self.C_stiff = StiffnessTensor(Csym)
378
+ self.calculate_button.setEnabled(True)
379
+ self.euler_button.setToolTip("Plot directional dependence")
380
+ self.euler_button.setEnabled(True)
381
+ self.euler_button.setToolTip("Rotate stiffness tensor (Bunge ZXZ)")
382
+ except ValueError:
383
+ self.calculate_button.setEnabled(False)
384
+ error_msg = "The stiffness tensor is not definite positive!"
385
+ self.calculate_button.setToolTip(error_msg)
386
+ self.euler_button.setEnabled(False)
387
+ self.euler_button.setToolTip(error_msg)
388
+
389
+ def show_about(self):
390
+ dialog = QDialog(self)
391
+ dialog = about(dialog, LOGO_PATH)
392
+ dialog.exec_()
393
+
394
+ def open_euler_dialog(self):
395
+ if not hasattr(self, "euler_dialog"):
396
+ self.current_config = {'sym': self.symmetry_selector.currentText(),
397
+ 'pg': self.point_group_selector.currentText(),
398
+ 'diag': self.diag_selector.currentText()}
399
+ self.euler_dialog = EulerBungeDialog(self, C=self.C_stiff.matrix())
400
+ self.euler_dialog.anglesChanged.connect(self.update_from_euler)
401
+ self.euler_dialog.show()
402
+
403
+ def update_from_euler(self, phi1, Phi, phi2):
404
+ C0 = StiffnessTensor(self.euler_dialog.C)
405
+ rot = Rotation.from_euler(seq='ZXZ', angles=[phi1, Phi, phi2], degrees=True)
406
+ if np.any(np.array([phi1, Phi, phi2])) != 0.:
407
+ self.symmetry_selector.setCurrentText('Triclinic')
408
+ C_new = C0.rotate(rot).matrix()
409
+ for (i, j), field in self.coefficient_fields.items():
410
+ self.coefficient_fields[(i,j)].setText(f"{C_new[i,j]}")
411
+ else:
412
+ for (i, j), field in self.coefficient_fields.items():
413
+ self.coefficient_fields[(i,j)].setText(f"{self.euler_dialog.C[i,j]}")
414
+ self.symmetry_selector.setCurrentText(self.current_config['sym'])
415
+ self.point_group_selector.setCurrentText(self.current_config['pg'])
416
+ self.diag_selector.setCurrentText(self.current_config['diag'])
417
+ if self.euler_dialog.live_button.isChecked():
418
+ self.calculate_and_plot()
258
419
 
259
420
  def crystal_elastic_plotter():
260
421
  app = QApplication(sys.argv)
422
+ try:
423
+ icon = QIcon(str(ICON_PATH))
424
+ except Exception:
425
+ icon = QIcon()
426
+ app.setWindowIcon(icon)
261
427
  window = ElasticityGUI()
428
+ window.setWindowIcon(icon)
262
429
  window.show()
263
430
  sys.exit(app.exec_())
431
+
432
+
433
+ from qtpy.QtWidgets import (
434
+ QDialog, QVBoxLayout, QHBoxLayout,
435
+ QLabel, QPushButton
436
+ )
437
+
438
+ if __name__ == "__main__":
439
+ crystal_elastic_plotter()
@@ -0,0 +1,79 @@
1
+ import numpy as np
2
+ from PyQt5.QtCore import Qt
3
+ from PyQt5.QtWidgets import QDialog, QVBoxLayout, QHBoxLayout, QLabel, QSlider, QDoubleSpinBox, QPushButton, QCheckBox
4
+ from qtpy.QtCore import Qt, Signal
5
+
6
+
7
+ class EulerBungeDialog(QDialog):
8
+ anglesChanged = Signal(float, float, float)
9
+
10
+ def __init__(self, parent=None, C=np.zeros((6, 6))):
11
+ super().__init__(parent)
12
+ self.setWindowTitle("Euler angles (Bunge ZXZ)")
13
+ self._build_ui()
14
+ self.reset()
15
+ self.C = C
16
+
17
+ def _build_ui(self):
18
+ self.layout = QVBoxLayout(self)
19
+
20
+ self.sliders = []
21
+ self.spins = []
22
+
23
+ labels = ["φ₁ (deg)", "Φ (deg)", "φ₂ (deg)"]
24
+ ranges = [(0, 360), (0, 180), (0, 360)]
25
+
26
+ for label, (vmin, vmax) in zip(labels, ranges):
27
+ row = QHBoxLayout()
28
+
29
+ row.addWidget(QLabel(label))
30
+
31
+ slider = QSlider(Qt.Horizontal)
32
+ slider.setRange(vmin * 10, vmax * 10)
33
+ slider.setSingleStep(1)
34
+
35
+ spin = QDoubleSpinBox()
36
+ spin.setRange(vmin, vmax)
37
+ spin.setDecimals(1)
38
+ spin.setSingleStep(0.1)
39
+
40
+ slider.valueChanged.connect(
41
+ lambda v, s=spin: s.setValue(v / 10)
42
+ )
43
+ spin.valueChanged.connect(
44
+ lambda v, s=slider: s.setValue(int(v * 10))
45
+ )
46
+ spin.valueChanged.connect(self._emit_angles)
47
+
48
+ row.addWidget(slider, stretch=1)
49
+ row.addWidget(spin)
50
+
51
+ self.sliders.append(slider)
52
+ self.spins.append(spin)
53
+
54
+ self.layout.addLayout(row)
55
+
56
+ # Live update
57
+ self.live_button = QCheckBox("Live-update plotting")
58
+ self.layout.addWidget(self.live_button)
59
+
60
+ # Reset button
61
+ reset_button = QPushButton("Reset orientation")
62
+ reset_button.clicked.connect(self.reset)
63
+ self.layout.addWidget(reset_button)
64
+
65
+ def reset(self):
66
+ self._set_angles(0.0, 0.0, 0.0)
67
+ for slider in self.sliders:
68
+ slider.setValue(0)
69
+
70
+ def _set_angles(self, phi1, Phi, phi2):
71
+ for spin, val in zip(self.spins, (phi1, Phi, phi2)):
72
+ spin.blockSignals(True)
73
+ spin.setValue(val)
74
+ spin.blockSignals(False)
75
+ self._emit_angles()
76
+
77
+ def _emit_angles(self):
78
+ angles = [spin.value() for spin in self.spins]
79
+ self.anglesChanged.emit(*angles)
@@ -1,6 +1,6 @@
1
- from Elasticipy.tensors.second_order import SymmetricSecondOrderTensor, SecondOrderTensor, \
1
+ from elasticipy.tensors.second_order import SymmetricSecondOrderTensor, SecondOrderTensor, \
2
2
  SkewSymmetricSecondOrderTensor
3
- from Elasticipy.tensors.stress_strain import StressTensor, StrainTensor
3
+ from elasticipy.tensors.stress_strain import StressTensor, StrainTensor
4
4
  import pandas as pd
5
5
  import numpy as np
6
6
  import os
@@ -90,14 +90,14 @@ def from_results_folder(folder, dtype=None):
90
90
  - SecondOrderTensor
91
91
  - SymmetricSecondOrderTensor
92
92
  - SkewSymmetricSecondOrderTensor
93
- - stressTensor
94
- - strainTensor
93
+ - StressTensor
94
+ - StrainTensor
95
95
 
96
96
  Returns
97
97
  -------
98
98
  SecondOrderTensor or numpy.ndarray
99
99
  Array of second-order tensors built from the read data. The array will be of shape (m, n), where m is the number
100
- of time increment n is the number of elements in the mesh.
100
+ of time increment n is the number of elements in the mesh.
101
101
  """
102
102
  dir_path = Path(folder)
103
103
  folder_name = dir_path.name
@@ -1,5 +1,5 @@
1
- from Elasticipy.tensors.second_order import SecondOrderTensor, SymmetricSecondOrderTensor
2
- from Elasticipy.tensors.stress_strain import StressTensor
1
+ from elasticipy.tensors.second_order import SecondOrderTensor, SymmetricSecondOrderTensor
2
+ from elasticipy.tensors.stress_strain import StressTensor
3
3
  import pandas as pd
4
4
  import numpy as np
5
5