wolfhece 2.1.98__py3-none-any.whl → 2.1.100__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.
@@ -0,0 +1,177 @@
1
+
2
+ from pathlib import Path
3
+ import numpy as np
4
+ from shapely.geometry import Polygon, Point, LineString
5
+ from shapely import prepare, is_prepared, destroy_prepared
6
+
7
+ import wx
8
+ import logging
9
+ from tqdm import tqdm
10
+
11
+ from .PyTranslate import _
12
+ from .PyVertexvectors import Zones, zone, vector, wolfvertex
13
+ from .matplotlib_fig import Matplotlib_Figure as mpl_plot, Matplotlib_ax_properties as mpl_ax, Matplolib_line_properties as mpl_line, Matplotlib_figure_properties as mpl_fig
14
+ from .matplotlib_fig import PRESET_LAYOUTS
15
+ from .wolf_array import WolfArray
16
+ from .wolfresults_2D import Wolfresults_2D
17
+ from .Results2DGPU import wolfres2DGPU
18
+
19
+ class Compare_vectors():
20
+ """ Compare multiple vectors """
21
+
22
+ def __init__(self) -> None:
23
+
24
+ self.fig:mpl_plot = None
25
+
26
+ self._reference:vector = None
27
+ self._reference_ls:LineString = None
28
+ self._ref_s:np.ndarray = None
29
+ self._ref_obj:dict[str, WolfArray | wolfres2DGPU | Wolfresults_2D] = {}
30
+ self._ref_values:zone = None
31
+
32
+ self._to_compare:dict[vector, list[WolfArray | wolfres2DGPU | Wolfresults_2D]] = {}
33
+ self._compare_values:dict[vector, zone] = {}
34
+
35
+ @property
36
+ def layout(self):
37
+ """ Layout of the figure """
38
+ return self.fig.layout
39
+
40
+ @layout.setter
41
+ def layout(self, value:dict | tuple | list | str):
42
+ """ Set layout of the figure """
43
+ self.fig = mpl_plot(value)
44
+ self.fig.Show()
45
+
46
+ @property
47
+ def reference(self):
48
+ """ Reference vector """
49
+ return self._reference
50
+
51
+ @reference.setter
52
+ def reference(self, value:vector):
53
+ """ Set reference vector """
54
+ if not isinstance(value, vector):
55
+ logging.error(_('Reference must be a vector'))
56
+ return
57
+
58
+ self._reference = value
59
+ self._reference_ls = value.asshapely_ls()
60
+ prepare(self._reference_ls)
61
+ self._ref_s = self._reference.get_s2d()
62
+
63
+ def __del__(self):
64
+ """ Destructor """
65
+
66
+ if self._reference_ls is not None:
67
+ if is_prepared(self._reference_ls):
68
+ destroy_prepared(self._reference_ls)
69
+
70
+ def add_ref_values(self, values:WolfArray | wolfres2DGPU | Wolfresults_2D):
71
+ """ Add values to the reference vector """
72
+
73
+ self._ref_obj[values.idx] = values
74
+
75
+ def del_ref_values(self, which:int | str):
76
+ """ Pop values from the reference vector """
77
+
78
+ if isinstance(which, str):
79
+ if which in self._ref_obj:
80
+ self._ref_obj.pop(which)
81
+ elif isinstance(which, int):
82
+ if which < len(self._ref_obj):
83
+ self._ref_obj.pop(list(self._ref_obj.keys())[which])
84
+
85
+ def reset_ref_values(self):
86
+ """ Reset reference values """
87
+
88
+ self._ref_obj = {}
89
+
90
+ def get_ref_values(self):
91
+ """ Retrieve reference values """
92
+
93
+ self._ref_values = self.reference.get_values_linked(self._ref_obj)
94
+
95
+ def add_compare(self, support:vector, values:list[WolfArray | wolfres2DGPU | Wolfresults_2D] = None):
96
+ """ Add values to compare """
97
+
98
+ if not isinstance(support, vector):
99
+ logging.error(_('Support must be a vector'))
100
+ return
101
+
102
+ if values is not None:
103
+ if not isinstance(values, list):
104
+ values = [values]
105
+
106
+ if isinstance(values, list):
107
+ if not all(isinstance(x, WolfArray | wolfres2DGPU | Wolfresults_2D) for x in values):
108
+ logging.error(_('Values must be a list of WolfArray, Wolfresults_2D or Wolfres2DGPU'))
109
+ return
110
+
111
+ if support in self._to_compare:
112
+ self._to_compare[support] += values
113
+ else:
114
+ self._to_compare[support] = values
115
+
116
+ def reset_compare(self):
117
+ """ Reset comparison values """
118
+
119
+ self._to_compare = {}
120
+
121
+ def del_compare(self, which:int | str):
122
+ """ Pop values from the comparison vector """
123
+
124
+ if isinstance(which, str):
125
+ if which in self._to_compare:
126
+ self._to_compare.pop(which)
127
+ elif isinstance(which, int):
128
+ if which < len(self._to_compare):
129
+ self._to_compare.pop(list(self._to_compare.keys())[which])
130
+
131
+ def get_compare_values(self):
132
+ """ Retrieve comparison values """
133
+
134
+ for curvect in self._to_compare:
135
+ self._compare_values[curvect] = curvect.get_values_linked({cur.idx: cur for cur in self._to_compare[curvect]})
136
+
137
+ def plot_ref(self, axis:int = 0):
138
+ """ Plot reference vector """
139
+
140
+ if self.fig is None:
141
+ logging.error(_('No figure layout defined'))
142
+ return
143
+
144
+ for curvect in self._ref_values.myvectors:
145
+ xyz = curvect.asnparray3d()
146
+ x = [self._reference_ls.project(Point(x,y)) for x,y in xyz[:,0:2]]
147
+ y = xyz[:,2]
148
+
149
+ self.fig.plot(x=x, y=y, ax=axis, label=curvect.myname)
150
+
151
+ def plot_compare(self, axis:int = 0):
152
+ """ Plot comparison vectors along reference vector.
153
+
154
+ We must project comparison vectors on the reference vector and plot them.
155
+ """
156
+
157
+ if self.fig is None:
158
+ logging.error(_('No figure layout defined'))
159
+ return
160
+
161
+ for curvect in self._compare_values:
162
+ for curval in self._compare_values[curvect].myvectors:
163
+ xyz = curval.asnparray3d()
164
+ x = [self._reference_ls.project(Point(x,y)) for x,y in xyz[:,0:2]]
165
+ y = xyz[:,2]
166
+
167
+ self.fig.plot(x=x, y=y, ax=axis, label=curval.myname)
168
+
169
+ def set_x_bounds(self, smin:float, smax:float, axis:int = 0):
170
+ """ Set x bounds for the figure """
171
+
172
+ self.fig.set_x_bounds(smin, smax, axis)
173
+
174
+ def set_y_bounds(self, ymin:float, ymax:float, axis:int = 0):
175
+ """ Set y bounds for the figure """
176
+
177
+ self.fig.set_y_bounds(ymin, ymax, axis)
wolfhece/apps/version.py CHANGED
@@ -5,7 +5,7 @@ class WolfVersion():
5
5
 
6
6
  self.major = 2
7
7
  self.minor = 1
8
- self.patch = 98
8
+ self.patch = 100
9
9
 
10
10
  def __str__(self):
11
11
 
@@ -10,13 +10,15 @@ copying or distribution of this file, via any medium, is strictly prohibited.
10
10
 
11
11
  import numpy as np
12
12
  from math import pi
13
- from scipy.optimize import fsolve, newton, root, root_scalar
13
+ from scipy.optimize import newton, root, root_scalar, fsolve
14
14
  import matplotlib.pyplot as plt
15
- from jax import grad, jit, numpy as jnp
15
+ # from jax import grad, jit, numpy as jnp, Array
16
+ from numba import jit
17
+ from jax.scipy.optimize import minimize
16
18
  import timeit
17
19
 
18
20
  @jit
19
- def _colebrook_white(f, k, diameter, reynolds):
21
+ def _colebrook_white(f:float, k:float, diameter:float, reynolds:float) -> float:
20
22
  """
21
23
  Colebrook-White equation for friction factor
22
24
 
@@ -25,14 +27,17 @@ def _colebrook_white(f, k, diameter, reynolds):
25
27
  @param diameter: float, diameter of the pipe [m]
26
28
  @param reynolds: float, Reynolds number [-]
27
29
  """
28
- return 1. / jnp.sqrt(f) + 2. * jnp.log10(k / (3.7 * diameter) + 2.51 / (reynolds * jnp.sqrt(f)))
30
+ ret = 1. / np.sqrt(f) + 2. * np.log10(k / (3.7 * diameter) + 2.51 / (reynolds * np.sqrt(f)))
31
+ return ret
29
32
 
30
- """ Gradient of the Colebrook-White equation """
31
- grad_colebrook_white = jit(grad(_colebrook_white))
32
- """ Second derivative of the Colebrook-White equation """
33
- grad2_colebrook_white = jit(grad(grad(_colebrook_white)))
33
+ @jit
34
+ def _grad_colebrook_white(f, k, diameter, reynolds):
35
+
36
+ term1 = -0.5 * f**(-1.5)
37
+ term2 = 2. * (2.51 / (reynolds * np.sqrt(f))) * (-0.5 * f**(-1.5)) / (k / (3.7 * diameter) + 2.51 / (reynolds * np.sqrt(f)))
38
+ return term1 + term2
34
39
 
35
- def f_colebrook_white(f, k, diameter, reynolds):
40
+ def f_colebrook_white(f:float, k:float, diameter:float, reynolds:float) -> float:
36
41
  """
37
42
  Solve the Colebrook-White equation using Newton's method
38
43
 
@@ -41,11 +46,12 @@ def f_colebrook_white(f, k, diameter, reynolds):
41
46
  @param diameter: float, diameter of the pipe [m]
42
47
  @param reynolds: float, Reynolds number [-]
43
48
  """
44
- f_sol = newton(_colebrook_white, f, grad_colebrook_white, args=(k, diameter, reynolds), rtol=1e-6)
45
- return f_sol.item()
46
49
 
50
+ f_sol = fsolve(_colebrook_white, f, args=(k, diameter, reynolds), xtol=1e-14, fprime=_grad_colebrook_white)
51
+ return f_sol[0]
47
52
 
48
53
  # Test multiple solvers
54
+
49
55
  def test_colebrook_fsolve():
50
56
  """ Test the Colebrook-White equation using Scipy fsolve """
51
57
 
@@ -58,7 +64,7 @@ def test_colebrook_fsolve():
58
64
  reynolds = velocity * diam / viscosity
59
65
 
60
66
  f_guess = 0.02 # Initial guess for the friction factor
61
- f_sol = fsolve(_colebrook_white, f_guess, args=(k, diam, reynolds), xtol=1e-14)
67
+ f_sol = fsolve(_colebrook_white, f_guess, args=(k, diam, reynolds), xtol=1e-6)
62
68
  return f_sol[0]
63
69
 
64
70
  def test_colebrook_root_scalar():
@@ -73,7 +79,7 @@ def test_colebrook_root_scalar():
73
79
  reynolds = velocity * diam / viscosity
74
80
 
75
81
  f_guess = 0.02 # Initial guess for the friction factor
76
- f_sol = root_scalar(_colebrook_white, method='brentq', bracket=[0.,10.], x0 = f_guess, args=(k, diam, reynolds)) #, fprime = grad_colebrook_white, fprime2 = grad2_colebrook_white, xtol=1e-6)
82
+ f_sol = root_scalar(_colebrook_white, method='brentq', bracket=[1e-10,10.], x0 = f_guess, args=(k, diam, reynolds)) #, fprime = grad_colebrook_white, fprime2 = grad2_colebrook_white, xtol=1e-6)
77
83
  return f_sol.root
78
84
 
79
85
  def test_colebrook_newton():
@@ -89,22 +95,69 @@ def test_colebrook_newton():
89
95
 
90
96
  f_guess = 0.02 # Initial guess for the friction factor
91
97
 
92
- f_sol = newton(_colebrook_white, f_guess, grad_colebrook_white, args=(k, diam, reynolds), rtol=1e-6)
98
+ f_sol = newton(_colebrook_white, f_guess, _grad_colebrook_white, args=(k, diam, reynolds), rtol=1e-6)
93
99
  return f_sol.item()
94
100
 
101
+ @jit
102
+ def dichotomy(f, a:float, b:float, args, tol=1e-10, max_iter=1000):
103
+ def cond_fun(val):
104
+ a, b, i = val
105
+ return (b - a) > tol
106
+
107
+ def body_fun(val):
108
+ a, b, i = val
109
+ c = (a + b) / 2.
110
+ k, diameter, reynolds = args
111
+ fa = f(a, k, diameter, reynolds)
112
+ fc = f(c, k, diameter, reynolds)
113
+ if fc == 0:
114
+ return (c, c, i + 1)
115
+ else:
116
+ if fa * fc < 0:
117
+ return (a, c, i + 1)
118
+ else:
119
+ return (c, b, i + 1)
120
+
121
+ i=0
122
+ while cond_fun((a, b, i)) and i < max_iter:
123
+ a, b, i = body_fun((a, b, 0))
124
+
125
+ return (a + b) / 2
126
+
127
+ def test_colebrook_dichotomy():
128
+ """ Test the Colebrook-White equation using Scipy root_scalar """
129
+
130
+ k= 1.e-4
131
+ diam = .5
132
+ viscosity = 1.e-6
133
+ area = pi * (diam/2.)**2.
134
+ discharge = 1.
135
+ velocity = discharge / area
136
+ reynolds = velocity * diam / viscosity
137
+
138
+ f_guess = 0.02 # Initial guess for the friction factor
139
+ f_sol = dichotomy(_colebrook_white, 1e-10, 10., (k, diam, reynolds))
140
+ return f_sol
141
+
95
142
 
96
143
  if __name__ == '__main__':
97
144
 
98
- trootscalar = timeit.timeit(test_colebrook_root_scalar, number = 1000)
99
- tfsolve = timeit.timeit(test_colebrook_fsolve, number = 1000)
100
- tnewton = timeit.timeit(test_colebrook_newton, number = 1000)
101
145
 
102
- trootscalar = test_colebrook_root_scalar()
103
- tfsolve = test_colebrook_fsolve()
104
- tnewton = test_colebrook_newton()
146
+ sol_newton_ref = f_colebrook_white(.02, 1.e-4, .5, 1/(pi*(.5/2.)**2.)*.5/1.e-6)
147
+
148
+ sol_rootscalar = test_colebrook_root_scalar()
149
+ sol_fsolve = test_colebrook_fsolve()
150
+ sol_newton = test_colebrook_newton()
151
+ sol_dicho = test_colebrook_dichotomy()
105
152
 
106
- sol_newton = f_colebrook_white(.02, 1.e-4, .5, 1/(pi*(.5/2.)**2.)*.5/1.e-6)
153
+ tfsolve = timeit.timeit(test_colebrook_fsolve, number = 10000)
154
+ tnewton = timeit.timeit(test_colebrook_newton, number = 10000)
155
+ trootscalar = timeit.timeit(test_colebrook_root_scalar, number = 10000)
156
+ tdichotomy = timeit.timeit(test_colebrook_dichotomy, number = 10000)
107
157
 
108
- assert sol_newton == tnewton
158
+ assert abs(sol_newton_ref - sol_newton) < 1e-8
159
+ assert abs(sol_newton_ref - sol_fsolve) < 1e-8
160
+ assert abs(sol_newton_ref - sol_rootscalar) < 1e-8
161
+ assert abs(sol_newton_ref - sol_dicho) < 1e-8
109
162
 
110
163
  pass
@@ -0,0 +1,143 @@
1
+ """
2
+ Author: HECE - University of Liege, Pierre Archambeau
3
+ Date: 2024
4
+
5
+ Copyright (c) 2024 University of Liege. All rights reserved.
6
+
7
+ This script and its content are protected by copyright law. Unauthorized
8
+ copying or distribution of this file, via any medium, is strictly prohibited.
9
+ """
10
+
11
+ import jax
12
+ from jax import lax, jit, grad
13
+ import jax.numpy as jnp
14
+ from jax.scipy.optimize import minimize
15
+ from jax._src.scipy.optimize.bfgs import minimize_bfgs
16
+ from scipy.optimize import minimize as minimize_scipy
17
+ import timeit
18
+ from matplotlib import pyplot as plt
19
+
20
+ def dichotomy(f, abi:jnp.array, args:jnp.array, tol:jnp.array=jnp.array([1e-8]), max_iter:jnp.array=jnp.array([1000])):
21
+ """ Dichotomy algorithm to find the root of a function """
22
+
23
+ def cond_fun(val:jnp.array) -> bool:
24
+ """ Condition function for the while loop """
25
+ a, b, i = val
26
+ return jnp.any((b - a) > tol) & jnp.any(i < max_iter)
27
+
28
+ def body_fun(val:jnp.array) -> jnp.array:
29
+ """ Body function for the while loop """
30
+ a, b, i = val
31
+ c = (a + b) / 2.
32
+ fa = f(a, args)
33
+ fc = f(c, args)
34
+ return lax.cond(fc == 0,
35
+ lambda _: jnp.array([c, b, i + 1]),
36
+ lambda _: lax.cond(fa * fc < 0,
37
+ lambda _: jnp.array([a, c, i + 1]),
38
+ lambda _: jnp.array([c, b, i + 1]), None), None)
39
+
40
+ abi = lax.while_loop(cond_fun, body_fun, abi)
41
+ return (abi[0] + abi[1]) / 2
42
+
43
+ @jit
44
+ def _colebrook_white(f:jnp.array, args:jnp.array) -> jnp.array:
45
+ """
46
+ Colebrook-White equation for friction factor
47
+
48
+ @param args: array containing, k = roughness of the pipe [m], diameter of the pipe [m], Reynolds number [-]
49
+ """
50
+ k, diameter, reynolds = args
51
+ ret = 1. / jnp.sqrt(f) + 2. * jnp.log10(k / (3.7 * diameter) + 2.51 / (reynolds * jnp.sqrt(f)))
52
+ return ret
53
+
54
+ @jit
55
+ def _square_colebrook_white(f:jnp.array, args:jnp.array) -> jnp.array:
56
+ """
57
+ Square of Colebrook-White equation for friction factor to be minimized
58
+
59
+ @param f: float, friction factor [-]
60
+ @param args: array containing, k = roughness of the pipe [m], diameter of the pipe [m], Reynolds number [-]
61
+ """
62
+ return _colebrook_white(f,args)**2
63
+
64
+ @jit
65
+ def _scalar_exp_square_colebrook_white(g:jnp.array, args:jnp.array) -> jnp.array: #scalar
66
+ """
67
+ Square of Colebrook-White equation for friction factor to be minimized.
68
+
69
+ Apply a transformation to the friction factor to avoid negative values.
70
+ Exponential transformation is used.
71
+
72
+ @param g: float, friction factor [-]
73
+ @param args: array containing, k = roughness of the pipe [m], diameter of the pipe [m], Reynolds number [-]
74
+ """
75
+ f = jnp.exp(g)
76
+ return jnp.sum(_colebrook_white(f,args)**2)
77
+
78
+ _grad_scalar_colebrook_white = grad(_scalar_exp_square_colebrook_white)
79
+
80
+ @jit
81
+ def grad_colebrook_white(f:jnp.array, args:jnp.array) -> jnp.array:
82
+ """
83
+ Gradient of the Colebrook-White equation for friction factor
84
+
85
+ @param f: float, friction factor [-]
86
+ @param args: array containing, k = roughness of the pipe [m], diameter of the pipe [m], Reynolds number [-]
87
+ """
88
+
89
+ # We must apply the exponential transformation to the friction factor
90
+ # See : _scalar_exp_square_colebrook_white
91
+ return _grad_scalar_colebrook_white(jnp.log(f), args)
92
+
93
+ @jit
94
+ def _min_colebrook_white(f:jnp.array, args:jnp.array) -> jnp.array:
95
+ """
96
+ Minimize the Colebrook-White equation using BFGS
97
+
98
+ @param f: float, initial guess for the friction factor [-]
99
+ @param args: array containing, k = roughness of the pipe [m], diameter of the pipe [m], Reynolds number [-]
100
+ """
101
+
102
+ return jnp.sum(jnp.exp(minimize(_scalar_exp_square_colebrook_white, jnp.log(f), args=(args,), method='BFGS', tol=1e-8).x))
103
+
104
+
105
+ if __name__ == '__main__':
106
+
107
+ args = jnp.array([1.e-4, .5, 1/(jnp.pi*(.5/2.)**2.)*.5/1.e-6])
108
+
109
+ # Find the root of the Colebrook-White equation by dichotomy
110
+ root = dichotomy(_colebrook_white, jnp.array([0.,2.,0]), args)
111
+ print(f"The root of the function is approximately: {root}")
112
+
113
+ optimum = _min_colebrook_white(jnp.array([0.03]), args)
114
+
115
+ print(f"The optimum of the function is approximately: {optimum}")
116
+ print(f"Delta: {jnp.abs(root - optimum)}")
117
+
118
+ # Create a test function to compare the time of execution between dichotomy and BFGS
119
+ @jit
120
+ def test_dichotomy():
121
+ dichotomy(_colebrook_white, jnp.array([0.,2.,0]), args)
122
+
123
+ @jit
124
+ def test_bfgs():
125
+ _min_colebrook_white(jnp.array([0.03]), args)
126
+
127
+ time_dicho = timeit.timeit(test_dichotomy, number=10000)
128
+ time_bfgs = timeit.timeit(test_bfgs, number=10000)
129
+ print(f"Time for dichotomy: {time_dicho}")
130
+ print(f"Time for BFGS: {time_bfgs}")
131
+
132
+ # Plot the function and its gradient
133
+ tested_f = jnp.arange(0.01, 0.03, 0.0001)
134
+ optimum = _min_colebrook_white(jnp.array([0.03]), args)
135
+ all_f = _square_colebrook_white(tested_f, args)
136
+ all_grad_ret = grad_colebrook_white(tested_f, args)
137
+
138
+ fig,ax = plt.subplots()
139
+ ax.plot(tested_f, all_f)
140
+ ax.plot(tested_f, all_grad_ret)
141
+ ax.scatter(optimum, _square_colebrook_white(optimum, args), color='red', marker='o')
142
+ ax.scatter(root, _colebrook_white(root, args), color='green', marker='X')
143
+ plt.show()
@@ -98,7 +98,12 @@ class pipe():
98
98
  def _solve_friction_factor(self):
99
99
  """ Update the friction factor using the Colebrook-White equation """
100
100
 
101
- self.f = f_colebrook_white(self.f, self.k, self.diameter, self.reynolds)
101
+ if self.reynolds==0.: # No flow
102
+ self.f = 0.
103
+ else:
104
+ if self.f ==0.:
105
+ self.f = 0.02
106
+ self.f = f_colebrook_white(self.f, self.k, self.diameter, self.reynolds)
102
107
 
103
108
  return self.f
104
109
 
@@ -113,7 +118,7 @@ class pipe():
113
118
  def solve_flowrate(self):
114
119
 
115
120
  def loc_bernoulli(flowrate):
116
- self.flowrate = flowrate
121
+ self.flowrate = flowrate[0]
117
122
  return self.bernoulli_error
118
123
 
119
124
  flowrate_solution = fsolve(loc_bernoulli, self.flowrate)
@@ -225,16 +225,16 @@ class Parser:
225
225
 
226
226
  def add(self, a, b):
227
227
  return a + b
228
-
228
+
229
229
  def norm(self, a, b):
230
230
  return math.sqrt(a * a + b * b)
231
-
231
+
232
232
  def Froude(self, a, b, c):
233
233
 
234
234
  return math.sqrt(a * a + b * b) / math.sqrt(9.81 * c)
235
-
235
+
236
236
  def sto(self, a, b):
237
- return dict(a = b)
237
+ return {a : b}
238
238
 
239
239
  def sub(self, a, b):
240
240
  return a - b
@@ -12,10 +12,18 @@ import wx
12
12
  import logging
13
13
  from pathlib import Path
14
14
 
15
-
15
+ from ..PyTranslate import _
16
16
  from . import Parser, Expression
17
17
 
18
18
  class Calculator(wx.Frame):
19
+ """
20
+ Calculator/Array creator
21
+
22
+ With this calculator, you can create arrays and perform operations on them.
23
+ It is possible because the operations are parsed and evaluated by the math_parser module
24
+ and mathematic operators are allowed directly on WolfArrays.
25
+
26
+ """
19
27
 
20
28
  def __init__(self, mapviewer=None):
21
29
 
@@ -23,7 +31,7 @@ class Calculator(wx.Frame):
23
31
 
24
32
  super(Calculator, self).__init__(None, title='Calculator', size=(500, 300))
25
33
 
26
- self._memory = {}
34
+ self._memory = {} # dictionary containing the arrays and local stored variables
27
35
 
28
36
  self._parser = Parser()
29
37
  self._parsed_command:Expression = None
@@ -37,7 +45,11 @@ class Calculator(wx.Frame):
37
45
  self._disp = wx.TextCtrl(self, style=wx.TE_RIGHT|wx.TE_RICH2|wx.TE_MULTILINE)
38
46
 
39
47
  self._comment = wx.TextCtrl(self, style=wx.TE_RIGHT|wx.TE_RICH2|wx.TE_MULTILINE)
40
- self.memory = wx.TextCtrl(self, style=wx.TE_RIGHT|wx.TE_RICH2|wx.TE_MULTILINE)
48
+ self._comment.SetToolTip(_('Comment block'))
49
+
50
+ self._memory_txtctrl = wx.TextCtrl(self, style=wx.TE_RIGHT|wx.TE_RICH2|wx.TE_MULTILINE)
51
+ self._memory_txtctrl.SetToolTip(_('Memory positions (contains the ids of the arrays and local variables)'))
52
+
41
53
  self.btn_reset_memory = wx.Button(self, label='Reset Memory')
42
54
 
43
55
  self.Bind(wx.EVT_BUTTON, lambda v: self.bt_press(v.EventObject.Label))
@@ -45,9 +57,9 @@ class Calculator(wx.Frame):
45
57
  self._btns[-1][-2].SetDefault()
46
58
 
47
59
  self.Bind(wx.EVT_CHAR_HOOK, self.char_press)
48
- self.btn_reset_memory.Bind(wx.EVT_BUTTON, lambda v: self._memory.clear())
60
+ self.btn_reset_memory.Bind(wx.EVT_BUTTON, self.memory_clear_event)
49
61
 
50
- self.SetSizer(self.pack([self._disp] + [self.pack(x) for x in self._btns] + [self.pack([self._comment, self.btn_reset_memory, self.memory])], orient=wx.VERTICAL))
62
+ self.SetSizer(self.pack([self._disp] + [self.pack(x) for x in self._btns] + [self.pack([self._comment, self.btn_reset_memory, self._memory_txtctrl])], orient=wx.VERTICAL))
51
63
 
52
64
  self._disp.SetFocus()
53
65
 
@@ -56,6 +68,7 @@ class Calculator(wx.Frame):
56
68
  icon.CopyFromBitmap(wx.Bitmap(str(icon_path), wx.BITMAP_TYPE_ANY))
57
69
  self.SetIcon(icon)
58
70
 
71
+ self.memory_clear()
59
72
  self.Show()
60
73
 
61
74
  def pack(self, items, orient=wx.HORIZONTAL):
@@ -79,7 +92,33 @@ class Calculator(wx.Frame):
79
92
 
80
93
  @comment.setter
81
94
  def comment(self, value):
82
- self._comment.Value = str(value)
95
+ self._comment.Value += str(value)
96
+
97
+ def reset_comment(self):
98
+ self._comment.Value = ''
99
+
100
+ @property
101
+ def memory_txt(self):
102
+ return self._memory_txtctrl.Value
103
+
104
+ @memory_txt.setter
105
+ def memory_txt(self, value):
106
+ self._memory_txtctrl.Value += str(value)+'\n'
107
+
108
+ def reset_memory(self):
109
+ self._memory_txtctrl.Value = ''
110
+
111
+ def memory_clear(self):
112
+ self.reset_memory()
113
+ self._memory.clear()
114
+
115
+ from ..PyDraw import draw_type
116
+ ids = self._mapviewer.get_list_keys(drawing_type=draw_type.ARRAYS, checked_state=None)
117
+ for id in ids:
118
+ self.memory_txt += id
119
+
120
+ def memory_clear_event(self, e):
121
+ self.memory_clear()
83
122
 
84
123
  def check_command(self) -> bool:
85
124
  """ Check if the command is valid """
@@ -121,14 +160,15 @@ class Calculator(wx.Frame):
121
160
 
122
161
  ret = []
123
162
  for command in commands:
163
+ if command == '': continue
124
164
  self.command = command
125
165
  ret.append(str(self.evaluate(mem_last_command=False)))
126
166
 
127
167
  self.command = '\n'.join(ret)
128
168
 
129
-
130
169
  def evaluate(self, mem_last_command=True):
131
170
  """ Evaluate the command """
171
+
132
172
  from ..PyDraw import WolfArray, draw_type
133
173
 
134
174
  if mem_last_command:
@@ -146,9 +186,10 @@ class Calculator(wx.Frame):
146
186
 
147
187
  for key, value in res.items():
148
188
  self._memory[key] = value
149
- comment += f'{key} = {value}\n'
150
189
 
151
- self.comment = comment
190
+ self.comment += f'{key} = {value}\n'
191
+ self.memory_txt += key
192
+
152
193
  self.command = ''
153
194
 
154
195
  elif isinstance(res, str|int|float):