-
Notifications
You must be signed in to change notification settings - Fork 6
/
Copy pathentrada.py
executable file
·332 lines (313 loc) · 12.8 KB
/
entrada.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
#!/usr/bin/env python3
'''
Intérprete de texto
'''
import sys
import os
pyENL_path = os.path.realpath(__file__)[0:-10]
sys.path.append(pyENL_path)
from solver import solver
from utils import variables, random_lim, variables_string
from numpy import inf
from CoolProp.CoolProp import PropsSI as prop
from CoolProp.CoolProp import HAPropsSI as haprop
from time import time
import optparse
from pint import _DEFAULT_REGISTRY as pyENLu
pyENLu.load_definitions(pyENL_path + "units.txt")
sindim = ((1*pyENLu.m)/(1*pyENLu.m)).units
try:
from .expimp import sols2odt, sols2tex
except:
pass
class pyENL_variable:
'''
Clase creadora de objetos de tipo variable para las resoluciones de las
ecuaciones no lineales.
'''
def __init__(self, nombre):
'''
Función creadora, dado un nombre de variable crea la instancia de la
variable. El nombre es una cadena de texto
'''
self.name = nombre
self.guess = 1.0
self.upperlim = 1e5
self.lowerlim = -1e5
self.comment = 'Variable'
self.units = sindim # Unidad de la variable.
self.solved = False
self.dim = self.units.dimensionality #Dimensión de la variable
def __repr__(self):
return "pyENL variable <" + self.name + ">"
def convert(self):
'''
Regresa la cadena de texto con la que debería reemplazarse el nombre de
la variable para la posterior labor de conversión.
'''
# TODO
pass
def find_between(s, first, last):
'''
Busca una cadena de texto entre dos strings; first y last que hacen parte
del string s.
'''
try:
start = s.index(first) + len(first)
end = s.index(last, start)
return s[start:end]
except ValueError:
return ""
def entradaTexto(ecuaciones, pyENL_timeout, varsObj=None, tol=None, method='hybr'):
'''
ecuaciones es una lista de cadenas de texto con ecuaciones de entrada.
varsObj define si llegan objetos variable como entrada.
La salida de esta función está dada por
'''
lista = []
dicc_condiciones = {}
# Si el método no está listado entonces no se procede
# method = method.strip(' ')
methods = ['hybr', 'lm', 'broyden1', 'broyden2', 'anderson', 'linearmixing',
'diagbroyden', 'excitingmixing', 'krylov', 'df-sane']
if method not in methods:
raise Exception('El método de resolución no está listado, ver ayuda.')
for ie, eqn in enumerate(ecuaciones):
if ((eqn.replace(' ','').replace('\t', '') != '') and ('{' not in eqn)) and ('<<' not in eqn):
expresion = eqn.replace(" ", "")
expresion = expresion.replace('\t','')
# Capacidad de interpretar pow
expresion = expresion.replace("^", "**")
izq_der = expresion.split('=')
operandos = ["+", "-", "*", "/", "("]
# Revisar que no haya operadores incompletos
if (izq_der[0][-1] in operandos) or (izq_der[1][-1] in operandos):
raise Exception('Ecuación mal escrita: ' + str(ie+1))
# Revisar que no hayan paréntesis sin cerrar
par_err1 = izq_der[0].count("(") != izq_der[0].count(")")
par_err2 = izq_der[1].count("(") != izq_der[1].count(")")
if par_err1 or par_err2:
raise Exception("No cierran los paréntesis en " + str(ie+1))
paraRaiz = izq_der[0] + \
'-(' + izq_der[1] + ')' # Igualación de cero
lista.append(paraRaiz)
if '{' in eqn:
# Entonces acá vienen condiciones, que son de la forma:
# {x,first_guess,-lim,+lim}
if '}' not in eqn:
raise Exception("Falt cerrar corchete")
condicion = find_between(eqn, '{', '}')
condicion = condicion.replace(' ', '')
condiciones = condicion.split(',')
dicc_condiciones.update({condiciones[0]: condiciones[1:4]})
# Lista contiene las ecuaciones
lista_vars = []
for ecuacion in lista:
lista_vars = lista_vars + variables(ecuacion)
lista_vars = list(set(lista_vars))
variables_salida = []
for miembro in lista_vars:
# Crear los objetos pyENL_variable a partir de los strings de nombres
# de vars
objeto = pyENL_variable(miembro)
# Ahora verificar que se encuentre listada en las condidiones
# Si se puede definir directamente entonces dejar ese valor inicial
# Es decir, tomar el valor del guess como el sugerido en una ecuación
# Tipo:
# x = ln(y)
# y = 5
# Entonces el valor inicial de y será 5, aún si el usuario no lo deja
# especificado por los corchetes {}
for cadaEqn in lista:
varAux = cadaEqn
varAux = varAux.replace("[", "*pyENLu.parse_units('")
varAux = varAux.replace("]", "')")
# print(objeto.name + "-")
varAux = varAux.replace(objeto.name + "-", "")
# print(varAux)
try:
objeto.guess = eval(varAux)
except:
pass
# Si no, entonces buscar si ya hay una definición:
try:
objeto.guess = float(dicc_condiciones[miembro][0])
except:
pass
try:
objeto.lowerlim = float(dicc_condiciones[miembro][1])
except:
pass
try:
objeto.upperlim = float(dicc_condiciones[miembro][2])
except:
pass
# Se van añadiendo los objetos de salida de las variables:
# print(objeto.guess)
variables_salida.append(objeto)
pyENL_inicio = time() # Tiempo de inicio de llamada al solver
# Llamada al solver
# Si los objetos variables ya vienen entonces:
if varsObj:
variables_salida = varsObj
pyENL_solved = False
try:
pyENL_solucion = solver(lista, variables_salida, tol=tol, method=method)
pyENL_solved = True
pyENL_final = time()
pyENL_transcurrido = pyENL_final - pyENL_inicio
except Exception as e:
# exit(0)
# Intento aleatorio
# Si el error es de sintaxis hay que detectarlo sin que intente
# nuevamente buscar soluciones infructuosamente:
er = str(e)
if 'de tipeo' in er:
raise Exception(er)
if 'Cannot convert' in er or 'is not defined in the unit registry' in er:
raise Exception(er)
if 'Improper input parameters were entered.' in er:
raise Exception('Parámetros inválidos suministrados')
if 'de sintaxis' in er:
raise Exception(er)
if 'No se ha definido' in er:
# Una función no está definida
raise Exception(er)
if 'como variable en' in er:
raise Exception(er)
if 'Faltan argumentos' in er:
raise Exception(er)
if 'inadecuado en función' in er:
raise Exception(er)
if 'Mala entrada' in er:
raise Exception(er)
if 'No se tienen los valores' in er:
raise Exception(er)
if 'debe tener unidades' in er:
raise Exception(er)
pyENL_final = time()
pyENL_transcurrido = pyENL_final - pyENL_inicio
while pyENL_transcurrido < pyENL_timeout:
# Encontrar nuevos valores de guesses:
for cont, objetoVar in enumerate(variables_salida):
obtemp = objetoVar # Objeto variable temporal
# TODO: Solo buscar random si es variable no resuelta
if not objetoVar.solved:
obtemp.guess = random_lim(objeto.lowerlim, objeto.upperlim) * objetoVar.units
variables_salida[cont] = obtemp
# Termina de actualizar, ahora:
try:
pyENL_solucion = solver(lista, variables_salida,
tol=1.49012e-08)
pyENL_solved = True
break
except Exception as e:
er = str(e)
raise Exception(e)
if 'de tipeo' in er:
raise Exception(er)
if 'Cannot convert' in er or 'is not defined in the unit registry' in er:
raise Exception(er)
if 'Improper input parameters were entered.' in er:
raise Exception('Parámetros inválidos suministrados')
if 'de sintaxis' in er:
raise Exception(er)
if 'No se ha definido' in er:
# Una función no está definida
raise Exception(er)
if 'como variable en' in er:
raise Exception(er)
if 'Faltan argumentos' in er:
raise Exception(er)
if 'inadecuado en función' in er:
raise Exception(er)
if 'Mala entrada' in er:
raise Exception(er)
if 'No se tienen los valores' in er:
raise Exception(er)
if 'debe tener unidades' in er:
raise Exception(er)
if 'Error de unidades' in er:
raise Exception(er)
# Actualiza el tiempo que ha transcurido:
pyENL_final = time()
pyENL_transcurrido = pyENL_final - pyENL_inicio
if pyENL_solved == False:
raise Exception(
'El tiempo de espera ha sido superado, verifique las ecuaciones')
if pyENL_solucion == 'Error ecuaciones/variables':
raise ValueError("Hay " + str(len(lista)) + ' ecuación(es) y ' +
str(len(variables_salida)) + ' variable(s)')
return [pyENL_solucion, pyENL_transcurrido]
def main():
'''
Rutina principal de la versión CLI (Command Line Interface)
'''
parser = optparse.OptionParser('Uso: ' + sys.argv[0] + ' -f archivo_texto\
-t timeout(seg) -m método -e archivo_exp')
parser.add_option('-f', dest='foption', type='string',
help='Archivo de texto con el sistema de ecuaciones')
parser.add_option('-t', dest='toption', type='float',
help='Tiempo de espera máximo para la solución')
parser.add_option('-e', dest='eoption', type='string',
help='Archivo de exportación, puede ser .odt, .tex o .pdf (LaTeX)')
parser.add_option('-m', dest='moption', type='string',
help='Métodos: hybr, lm, broyden1, broyden2, anderson, linearmixing, diagbroyden, excitingmixing, krylov, df-sane')
(options, args) = parser.parse_args()
if options.foption == None:
print(parser.usage)
exit(0)
else:
fichero = options.foption
# Verificación de existencia y lectura del archivo de texto:
if not os.path.isfile(fichero):
print('[!] El archivo de texto no se encuentra')
exit(0)
if not os.access(fichero, os.R_OK):
print('[!] No se cuentan con los permisos apropiados para acceder al archivo')
exit(0)
if options.toption == None:
pyENL_timeout = 10
else:
pyENL_timeout = options.toption
if options.moption:
metodo = options.moption
else:
metodo = 'hybr'
with open(fichero, 'rb') as f:
ecuaciones = (f.read()).decode('utf-8')
ecuaciones = ecuaciones.splitlines()
# Ahora a organizar lo de las variables tipo string
ecuaciones = variables_string(ecuaciones)
try:
solucion = entradaTexto(ecuaciones, pyENL_timeout, method=metodo)
except Exception as e:
print(str(e))
exit(0)
# Si se especificó archivo de exportación entonces generarlo:
if options.eoption:
if options.eoption[-4::] not in ['.pdf', '.odt', '.tex']:
print('No se especificó un válido archivo de salida, debe ser .odt\
o .tex (soporte para LaTeX pendiente)')
exit(0)
if '.odt' in options.eoption:
# Intentar guardar el documento para exportación y en caso de error
# lanzar mensaje de advertencia.
try:
sols2odt(solucion[0][0], options.eoption, ecuaciones)
except:
print('No se pudo guardar el archivo de exportación, verifique \
que tenga permisos de escritura o que el nombre sea válido')
else:
# Entonces es .pdf o .tex
try:
autor = input('Nombre de autor para reporte LaTeX: ')
sols2tex(solucion[0][0], options.eoption, ecuaciones, autor)
except:
print('No se pudo generar el archivo, verifique que tenga\
dependencias necesarias instaladas.')
for variable in solucion[0][0]:
print(variable.name, '=', variable.guess)
print('Residuos:', solucion[0][1])
if __name__ == '__main__':
main()