-
Notifications
You must be signed in to change notification settings - Fork 6
Expand file tree
/
Copy pathentrada.py
More file actions
executable file
路332 lines (313 loc) 路 12.8 KB
/
Copy pathentrada.py
File metadata and controls
executable file
路332 lines (313 loc) 路 12.8 KB
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()