def verificar_avanzar(cls, n_pasos=3): try: arch_ref = cls.refs_prb_avanzar() arch_inic = cls.refs_prb_vals_inic()[0] except NotImplementedError: return mod = cls(archivo=arch_inic) res = mod.simular(t_final=n_pasos) try: ref = xr.Dataset.from_dict(cargar_json(arch_ref)) except FileNotFoundError: avisar( _('\nNo encontramos diccionario con los valores corectos de referencia para comprobar que el' '\nmodelo sí esté simulando correctamente. Lo generaremos con base en el los valores' '\nactualmente leídos por el modelo. Asegúrate que los valores generados en' '\n\t"{}"' '\nestén correctos, y si no lo son, bórralo. En el futuro, se empleará este fuente para ' '\ncomprobar la función de simulación de modelo.').format( arch_ref)) guardar_json(res.to_dict(), arch=arch_ref) ref = res xr.testing.assert_equal(ref, res)
def cargar_ref_avanzar(cls, arch_ref, res): """ Parameters ---------- arch_ref : res : xr.DataSet Returns ------- """ try: return xr.Dataset.from_dict(cargar_json(arch_ref)) except FileNotFoundError: avisar( _('\nNo encontramos diccionario con los valores corectos de referencia para comprobar que el' '\nmodelo sí esté simulando correctamente. Lo generaremos con base en el los valores' '\nactualmente leídos por el modelo. Asegúrate que los valores generados en' '\n\t"{}"' '\nestén correctos, y si no lo son, bórralo. En el futuro, se empleará este fuente para ' '\ncomprobar la función de simulación de modelo.').format( arch_ref)) guardar_json(res.to_dict(), arch=arch_ref) return res
def verificar_inic_dic_vals(cls): try: arch_inic, arch_ref = cls.refs_prb_vals_inic() except NotImplementedError: return mod = cls(arch_inic) try: ref = cargar_json(arch_ref) except FileNotFoundError: avisar( _('\nNo encontramos diccionario con los valores corectos de referencia para comprobar que el' '\nmodelo sí esté leyendo bien los datos iniciales. Lo generaremos con base en el los valores' '\nactualmente leídos por el modelo. Asegúrate que los valores generados en' '\n\t"{}"' '\nestén correctos, y si no lo son, bórralo. En el futuro, se empleará este fuente para ' '\ncomprobar la función de lectura de datos iniciales.'). format(arch_ref)) d_vals = copiar_profundo(mod.variables) for d_v in d_vals.values(): if isinstance(d_v['val'], np.ndarray): d_v['val'] = d_v['val'].tolist() guardar_json(d_vals, arch=arch_ref) ref = d_vals for var in mod.variables: npt.assert_equal(ref[var]['val'], mod.obt_val_actual_var(var), err_msg=var)
def obt_val_config(llave, cond=None, mnsj_err=None, respaldo=None): if not isinstance(respaldo, list): respaldo = [respaldo] try: conf, ll = _resolver_conf_anidado(llave) val = conf[ll] if cond is None: return val else: if cond(val): return val else: for a in respaldo: if a is not None and cond(a): return a if mnsj_err is not None: avisar(mnsj_err) return except KeyError: val = None if cond is None: val = respaldo[0] else: for a in respaldo: if a is not None and cond(a): val = a if val is None and mnsj_err is not None: avisar(mnsj_err) return val
def _descargar_whl(nombre, v_py, sis, b): print('Descargando paquete "{}"...'.format(nombre)) llave = url = None repositorios = { 'id_google': 'https://drive.google.com/uc?export=download&id={}', 'id_dropbox': 'https://www.dropbox.com/s/{}?dl=1' } for r, u in repositorios.items(): try: llave = info_paquetes[nombre][v_py][sis][b][r] # type: str except KeyError: pass if llave is not None: url = u.format(llave) break if url is None: avisar('No existe descarga para paquete {} en {} bits.'.format( nombre, bits)) return False nombre_archivo = info_paquetes[nombre]['formato_archivo'] urllib.request.urlretrieve(url, os.path.join(directorio_móds, nombre_archivo)) return True
def agregar_modelo(símismo, modelo): """ Esta función agrega un modelo al SuperConectado. Una vez que dos modelos estén agregados, se pueden conectar y simular juntos. :param modelo: El modelo para agregar. :type modelo: tinamit.Modelo.Modelo """ # Si ya se conectó otro modelo con el mismo nombre, avisarlo al usuario. if modelo.nombre in símismo.modelos: avisar(_('El modelo {} ya existe. El nuevo modelo reemplazará el modelo anterior.').format(modelo.nombre)) # Agregar el nuevo modelo al diccionario de modelos. símismo.modelos[modelo.nombre] = modelo # Ahora, tenemos que agregar los variables del modelo agregado al diccionaro de variables de este modelo # también. Se prefija el nombre del modelo al nombre de su variable para evitar posibilidades de nombres # desduplicados. for var in modelo.variables: nombre_var = '{mod}_{var}'.format(var=var, mod=modelo.nombre) símismo.variables[nombre_var] = modelo.variables[var] # Actualizar la unidad de tiempo del modelo símismo.unidad_tiempo()
def desconectar_vars(símismo, var_fuente, modelo_fuente, modelo_recip=None, var_recip=None): """ Esta función desconecta variables. :param var_fuente: El variable fuente de la conexión. :type var_fuente: str :param modelo_fuente: El modelo fuente de la conexión. :type modelo_fuente: str """ # Verificar parámetros if modelo_recip is None and var_recip is not None: avisar(_('`var_recip` sin `modelo_recip` será ignorado en la función ' '`SuperConectado.desconectar_vars()`.')) # Buscar la conexión correspondiente... for n, conex in enumerate(símismo.conexiones): # Para cada conexión existente... if conex['modelo_fuente'] == modelo_fuente and conex['var_fuente'] == var_fuente: # Si el modelo y variable fuente corresponden... # Identificar si el modelo recipiente corresponde también. quitar = False if modelo_recip is None: quitar = True else: if modelo_recip == conex['modelo_recip']: if var_recip is None or var_recip == conex['var_recip']: quitar = True # Si corresponde todo, quitar la conexión. if quitar: símismo.conexiones.pop(n)
def verificar_leer_egr(cls): try: arch_egr, arch_ref = cls.refs_prb_leer_egr() except NotImplementedError: return egr = cls.leer_arch_resultados(arch_egr) try: ref = cargar_json(arch_ref) except FileNotFoundError: avisar( _('\nNo encontramos diccionario con los valores corectos de referencia para comprobar que el' '\nmodelo sí esté leyendo bien los archivos de egresos. Lo generaremos con base en el los valores' '\nactualmente leídos por el modelo. Asegúrate que los valores generados en' '\n\t"{}"' '\nestén correctos, y si no lo son, bórralo. En el futuro, se empleará este fuente para ' '\ncomprobar la función de lectura de egresos.').format( arch_ref)) for var, val in egr.items(): if isinstance(val, np.ndarray): egr[var] = val.tolist() guardar_json(egr, arch=arch_ref) ref = egr for var in ref: npt.assert_equal(ref[var], egr[var], err_msg=var)
def obt_info_parcelas(símismo, parc): """ Devuelve información de una parcela o lista de parcelas. :param parc: La(s) parcela(s) de interés. :type parc: str | list[str] :return: Un diccionario con información de cada parcela. :rtype: dict """ if not isinstance(parc, list): parc = [parc] parc = [str(x) for x in parc] nombres = símismo.datos['Parcelas']['Nombres'] # type: list superficies = símismo.datos['Parcelas']['Superficies'] # type: list polígonos = símismo.datos['Parcelas']['Polígonos'] # type: list dic_info = {} for p in parc: if p not in nombres: avisar('Parcela "{}" no tiene datos en experimento "{}".'.format(p, símismo.nombre)) continue índ_p = nombres.index(p) dic_info[p] = { 'Superficie': superficies[índ_p] if superficies is not None else None, 'Polígonos': polígonos[índ_p] if superficies is not None else None } return dic_info
def verificar_entero(factor, l_unids): if not np.array_equal(factor.astype(int), factor): # Si todos los factores no son números enteros, tendremos que aproximar. avisar('Las unidades de tiempo de los dos modelos ({}) no tienen denominator común. ' 'Se aproximará la conversión.'.format(', '.join(l_unids))) np.round(factor, out=factor)
def instalar_requísitos(): print('Instalando paquetes requísitos...') lista_paquetes = [] if np is None: lista_paquetes.append('numpy') if matplotlib is None: lista_paquetes.append('matplotlib') if estad is None: lista_paquetes.append('scipy') if pymc is None: lista_paquetes.append('pymc') if len(lista_paquetes): if not os.path.exists(directorio_móds): os.makedirs(directorio_móds) dir_creado = True else: dir_creado = False # Actualizar Pip _actualizar_pip() # Instalar cada paquete necesario for paq in lista_paquetes: _instalar_whl(paq) if dir_creado: shutil.rmtree('Módulos') # Verificar que todo esté bien: try: import numpy as _ import scipy as _ import pymc as _ import matplotlib as _ except ImportError: _ = None pass try: import scipy.stats as _ _.norm() print( '¡Todo bien! Los paquetes Python necesarios han sido instalados.') except ImportError: _ = None avisar( '¡Error! Por experencia personal, probablemente es porque no instalaste la versión del' '"Microsoft C++ 2015 redistributable" {}.\n' 'Lo puedes conseguir de "https://www.microsoft.com/es-ES/download/details.aspx?id=48145".' .format('x86' if bits == '32' else 'x64'))
def _act_vals_clima(símismo, n_paso, f): """ Actualiza los variables climáticos, según la estación. :param n_paso: El número de pasos para avanzar :type n_paso: int :param f: La fecha actual. :type f: ft.datetime | ft.date """ # Si avanzamos por más que un año, perderemos la precisión del clima if n_paso > 12: avisar('El paso es superior a 1 año (12 meses). Las predicciones climáticas perderán su precisión.') # Solamante hay que cambiar los datos si es el principio de un nuevo año. if símismo.mes == 0 and símismo.estación == 0: # La lista de variables climáticos vars_clima = list(símismo.vars_clima) nombres_extrn = [d['nombre_extrn'] for d in símismo.vars_clima.values()] # La lista de maneras de combinar los valores diarios combins = [d['combin'] for d in símismo.vars_clima.values()] # La lista de factores de conversiones de variables de clima convs = [d['conv'] for d in símismo.vars_clima.values()] # La fecha inicial f_inic = f for e, dur in enumerate(símismo.dur_estaciones): # Para cada estación... # La fecha final f_final = f_inic + deltarelativo(months=+dur) # Calcular los datos datos = símismo.lugar.comb_datos(vars_clima=nombres_extrn, combin=combins, f_inic=f_inic, f_final=f_final) # Aplicar los valores de variables calculados for i, var in enumerate(vars_clima): # Para cada variable en la lista de clima... # El nombre oficial del variable de clima var_clima = nombres_extrn[i] # El factor de conversión conv = convs[i] # Guardar el valor para esta estación símismo.datos_internos[var][e, ...] = datos[var_clima] * conv # Avanzar la fecha f_inic = f_final
def _estab_mod_extern(símismo, modelo): if isinstance(modelo, str): if not os.path.isfile(modelo): raise ValueError(_('El archivo "{}" no existe... :(').format(modelo)) if os.path.splitext(modelo)[1] != '.py': raise ValueError(_('El archivo "{}" no parece ser un archivo Python.').format(modelo)) dir_mod, nombre_mod = os.path.split(modelo) sys.path.append(dir_mod) módulo = importar_mod(os.path.splitext(nombre_mod)[0]) candidatos = inspect.getmembers(módulo, inspect.isclass) cands_final = {} for nmb, obj in candidatos: if callable(obj): try: obj = obj() except BaseException: continue if isinstance(obj, ModeloBF): cands_final[nmb] = obj if len(cands_final) == 0: raise AttributeError(_('El fuente especificado ("{}") no contiene subclase de "ModeloBF".') .format(modelo)) elif len(cands_final) == 1: símismo.modelo = cands_final[list(cands_final)[0]] else: try: símismo.modelo = cands_final['Envoltura'] except KeyError: elegido = list(cands_final)[0] símismo.modelo = elegido avisar(_('Había más que una instancia de "ModeloBF" en el fuente "{}", ' 'y ninguna se llamaba "Envoltura". Tomaremos "{}" como la envoltura ' 'y esperaremos que funcione. Si no te parece, asegúrate que la definición de clase u el' 'objeto correcto se llame "Envoltura".').format(modelo, elegido)) else: if callable(modelo): modelo = modelo() if isinstance(modelo, ModeloBF): símismo.modelo = modelo else: raise TypeError(_('El parámetro "modelo" debe ser o una instancia o subclase de "ModeloBF", o un ' 'fuente Python que contiene uno.')) # Crear el vínculo símismo.variables = símismo.modelo.variables símismo.vars_saliendo = símismo.modelo.vars_saliendo símismo.vars_clima = símismo.modelo.vars_clima símismo.archivo = símismo.modelo.archivo
def simular(símismo, t_final=None, t_inic=None, paso=1, nombre_corrida='Corrida Tinamït', vals_inic=None, vals_extern=None, bd=None, lugar_clima=None, clima=None, vars_interés=None, guardar=True): """ Simula el modelo :class:`~tinamit.Conectado.SuperConectado`. :param t_final: El tiempo final de la simulación. :type t_final: int :param paso: El paso (intervalo de intercambio de valores entre los dos submodelos). :type paso: int :param nombre_corrida: El nombre de la corrida. El valor automático es ``Corrida Tinamit``. :type nombre_corrida: str :param t_inic: La fecha inicial de la simulación. Necesaria para simulaciones con cambios climáticos. :type t_inic: ft.datetime | ft.date | int | str :param lugar_clima: El lugares de la simulación. :type lugar_clima: Lugar :param tcr: El escenario climático según el sistema de la IPCC (``2.6``, ``4.5``, ``6.0``, o ``8.5``). ``0`` da el clima histórico. :type tcr: str | float | int :param recalc_clima: Si quieres recalcular los datos climáticos, si ya existen. :type recalc_clima: bool :param clima: Si es una simulación de cambios climáticos o no. :type clima: bool """ vals_inic = símismo._frmt_dic_vars(vals_inic) # ¡No se puede simular con menos de un modelo! if len(símismo.modelos) < 1: raise ValueError(_('Hay que conectar submodelos antes de empezar una simulación.')) # Si no estamos seguro de la conversión de unidades de tiempo, decirlo aquí. if símismo.conv_tiempo_dudoso: l_unids = [m.unidad_tiempo() for m in símismo.modelos.values()] avisar(_('No se pudo inferir la conversión de unidades de tiempo entre {}.\n' 'Especificarla con la función .estab_conv_tiempo().\n' 'Por el momento pusimos el factor de conversión a 1, pero probablemente no es lo que quieres.') .format(', '.join(l_unids))) # Todo el restode la simulación se hace como en la clase pariente return super().simular( t_final=t_final, t_inic=t_inic, paso=paso, nombre_corrida=nombre_corrida, vals_inic=vals_inic, vals_extern=vals_extern, bd=bd, lugar_clima=lugar_clima, clima=clima, vars_interés=vars_interés, guardar=guardar )
def _verificar(símismo): v_f = símismo.var_fuente v_r = símismo.var_recip if v_f.dims != v_r.dims: raise ValueError( _('Dimensiones incompatibles entre variables "{}" {} y "{}" {}.' ).format(v_f, v_f.dims, v_r, v_r.dims)) if not _líms_compat(símismo.var_fuente.líms, símismo.var_recip.líms): avisar( _('Límites potencialmente incompatibles entre variables "{}" y "{}".' ).format(símismo.var_fuente, símismo.var_recip))
def superficies(símismo, parc): """ Devuelve las superficies de unas parcelas de interés. :param parc: La(s) parcela(s) de interés. :type parc: str | list[str] :return: Un vector de superficies de las parcelas. :rtype: np.ndarray """ # Asegurar el formato de las parcelas if not isinstance(parc, list): parc = [parc] n_parc = len(parc) # El número de parcelas # Una matriz vacía para las superficies superficies = np.empty(n_parc) # El nombre de las superficies en este experimento nombres = símismo.datos['Parcelas']['Nombres'] # type: list # Si no hay superficies en este experimento, establecer un valor de 1 ha automáticamente y avisarle al usuario. if símismo.datos['Parcelas']['Superficies'] is None: avisar('Tamaños de parcelas no especificados. Se supondrá un tamaño de 1 ha.') superficies[:] = 1 else: # Si al contrario tenemos datos de superficies... for i, p in enumerate(parc): # Para cada parcela de interés... # Intentar leer sus datos de superficie try: índ_p = nombres.index(p) # Puede causar un ValueError aquí... sfc = símismo.datos['Parcelas']['Superficies'][índ_p] if sfc == np.nan: raise ValueError # ...¡o aquí! else: superficies[i] = sfc except ValueError: # Si no funcionó, darle un valor de 1 ha y avisarle al usuario avisar('Tamaño de parcela no especificado para parcela "{}". Se supondrá un tamaño de 1 ha.' .format(p)) superficies[i] = 1 # Devolver el vector de superficies. return superficies
def simular_grupo(símismo, ops_grupo, nombre='Tinamït', paralelo=False): """ Efectua un grupo de simulaciones. Muy útil para accelerar corridas múltiples. Parameters ---------- ops_grupo: PlantillaOpsSimulGrupo Las opciones de simulación en grupo. nombre: str El nombre de la simulación. paralelo: bool Si se simula en paralelo o no. Si el modelo no soporte corridas en paralelo, se ignorará este argumento. Returns ------- ResultadosGrupo """ if paralelo and not símismo.paralelizable(): avisar( _('\nEl modelo no se identifica como paralelizable. Para evitar el riesgo' '\nde errores de paralelización, correremos las corridas como simulaciones secuenciales ' '\nnormales. ' '\nSi tu modelo sí es paralelizable, crear un método nombrado `.paralelizable()` ' '\nque devuelve ``True`` en tu clase de modelo para activar la paralelización.' )) paralelo = False res_grupo = ResultadosGrupo(nombre) if paralelo: l_trabajos = [] copia_mod = pickle.dumps(símismo) # Una copia de este modelo. # Crear la lista de información necesaria para las simulaciones en paralelo... for ops in ops_grupo: l_trabajos.append((copia_mod, ops)) # Hacer las corridas en paralelo with Reserva() as r: res_paralelo = r.map(_correr_modelo, l_trabajos) for res in res_paralelo: res_grupo[str(res)] = res else: for ops in ops_grupo: res = símismo.simular(**ops) res_grupo[str(res)] = res return res_grupo
def cargar_ref_ejemplo_vals_inic(símismo): if not os.path.isfile(símismo.dic_prb_datos_inic): avisar(_('\nNo encontramos diccionario con los valores corectos de referencia para comprobar que el' '\nmodelo sí esté leyendo bien los datos iniciales. Lo generaremos con base en el los valores' '\nactualmente leídos por el modelo. Asegúrate que los valores generados en' '\n\t"{}"' '\nestén correctos, y si no lo son, bórralo. En el futuro, se empleará este fuente para ' '\ncomprobar la función de lectura de datos iniciales.').format(símismo.dic_prb_datos_inic)) d_vals = copiar_profundo(símismo.variables) for d_v in d_vals.values(): if isinstance(d_v['val'], np.ndarray): d_v['val'] = d_v['val'].tolist() guardar_json(d_vals, arch=símismo.dic_prb_datos_inic) return cargar_json(símismo.dic_prb_datos_inic)
def agregar_frm_regiones(símismo, archivo, col_id, escala_geog=None): """ :param archivo: :type archivo: :param col_id: :type col_id: :return: :rtype: """ af = sf.Reader(archivo) attrs = af.fields[1:] nombres_attr = [field[0] for field in attrs] try: ids = np.array([ x.record[nombres_attr.index(col_id)] for x in af.shapeRecords() ], dtype=str) except ValueError: raise ValueError( _('La columna "{}" no existe en la base de datos.').format( col_id)) if escala_geog is None: ids_no_existen = [ id_ for id_ in ids if str(id_) not in símismo.cód_a_lugar ] if len(ids_no_existen): avisar( _('Las formas con id "{}" no se encuentran en la geografía actual.' ).format(ids_no_existen)) escls_ids = set( símismo.obt_escala_región(id_) for id_ in ids if id_ not in ids_no_existen) if len(escls_ids) > 1: raise ValueError elif len(escls_ids) == 1: if escala_geog is None: escala_geog = list(escls_ids)[0] else: if escala_geog is None: escala_geog = 'Automática' símismo.formas_reg[escala_geog] = {'af': af, 'ids': ids}
def desconectar_vars(símismo, var_fuente, modelo_fuente, modelo_recip=None, var_recip=None): """ Esta función desconecta variables. Parameters ---------- var_fuente : str El variable fuente de la conexión. modelo_fuente : str | Modelo El modelo fuente de la conexión. modelo_recip : str | Modelo El modelo recipiente. Si no se especifica, se quitarán todas conexiones con el variable y modelo fuente. var_recip : str El variable recipiente. Si no se especifica, se quitarán todas conexiones con el variable y modelo fuente y el modelo recipiente especificado. Sin efecto si `modelo_recip` es ``None``. """ # Verificar parámetros if modelo_recip is None and var_recip is not None: avisar( _('`var_recip` sin `modelo_recip` será ignorado en la función ' '`SuperConectado.desconectar_vars()`.')) # Verificar los nombres de modelos modelo_fuente = símismo._verificar_nombre_submodelo(modelo_fuente) modelo_recip = símismo._verificar_nombre_submodelo(modelo_recip) # Buscar la conexión correspondiente... for n, conex in enumerate(símismo.conexiones): # Para cada conexión existente... if conex['modelo_fuente'] == modelo_fuente and conex[ 'var_fuente'] == var_fuente: # Si el modelo y variable fuente corresponden... # Identificar si el modelo recipiente corresponde también. if modelo_recip is None: símismo.conexiones.pop(n) else: if modelo_recip == conex['modelo_recip']: if var_recip is None or var_recip == conex['var_recip']: símismo.conexiones.pop(n)
def valid_archivo(archivo): direc, nombre = os.path.split(archivo) disco, direc = os.path.splitdrive(direc) direc = pathvalidate.sanitize_file_path(direc, replacement_text='_') nombre = pathvalidate.sanitize_filename(nombre, replacement_text='_') if len(direc) >= 260: raise ValueError( 'El archivo siguiente queda demasiado largo...\n\t{}'.format( archivo)) if len(direc) + len(nombre) > 260: avisar( 'Cortamos el nombre "{}" por ser demasiado largo'.format(nombre)) nombre = nombre[:len(direc) - 260] return os.path.join(disco, direc, nombre)
def _interpolar_xr(m, fechas=None): if fechas is not None: raise ValueError interpolado = m.unstack().interpolate(limit_area='inside').stack() if len(interpolado.dropna()): return interpolado avisar('Extrapolando por falta de datos.') return m.unstack().interpolate().stack() if m.sizes[_('fecha')] > 1: m = m.interpolate_na(_('fecha')).fillna(m) if fechas is not None: fechas = [fechas] if not isinstance(fechas, (tuple, list)) else fechas m = m.interp({_('fecha'): pd.DatetimeIndex(fechas)}).fillna(m) m = m.dropna(_('lugar'), how='all') return m.stack(n=[_('lugar'), _('fecha')])
def cargar_ref_ejemplo_egr(símismo): if not os.path.isfile(símismo.dic_prb_egr): avisar(_('\nNo encontramos diccionario con los valores corectos de referencia para comprobar que el' '\nmodelo sí esté leyendo bien los egresos de modelos. Lo generaremos con base en el los valores' '\nactualmente leídos por el modelo. Asegúrate que los valores generados en' '\n\t"{}"' '\nestén correctos, y si no lo son, bórralo. En el futuro, se empleará este fuente para ' '\ncomprobar la función de lectura de egresos.').format(símismo.dic_prb_egr)) d_egr = símismo.leer_archivo_egr(n_años_egr=1, archivo=símismo.prb_arch_egr) for var, val in d_egr.items(): if isinstance(val, np.ndarray): d_egr[var] = val.tolist() guardar_json(d_egr, arch=símismo.dic_prb_egr) d_egr = cargar_json(símismo.dic_prb_egr) return d_egr
def unidad_tiempo(símismo): unids = list({m.unidad_tiempo() for m in símismo.modelos}) factores_conv = [1] factores_conv[0] = 1 for u in unids[1:]: # Intentar convertir la unidad del submodelo a la unidad de base factores_conv.append(convertir(de=unids[0], a=u)) factores_conv = np.array(factores_conv) factores_conv = np.divide(factores_conv, factores_conv.min()) facts_conv_ent = np.round(factores_conv) if not np.array_equal(facts_conv_ent, factores_conv): # Si todos los factores no son números enteros, tendremos que aproximar. avisar( _('Las unidades de tiempo de los modelos ({}) no tienen denominator común. Se aproximará la ' 'conversión.').format(', '.join(unids))) return next(u for u, c in zip(unids, factores_conv) if c == 1)
def cargar_ref_vals_inic(cls, arch_ref, mod): try: return cargar_json(arch_ref) except FileNotFoundError: avisar( _('\nNo encontramos diccionario con los valores corectos de referencia para comprobar que el' '\nmodelo sí esté leyendo bien los datos iniciales. Lo generaremos con base en el los valores' '\nactualmente leídos por el modelo. Asegúrate que los valores generados en' '\n\t"{}"' '\nestén correctos, y si no lo son, bórralo. En el futuro, se empleará este fuente para ' '\ncomprobar la función de lectura de datos iniciales.'). format(arch_ref)) d_vals = copiar_profundo(mod.variables) for d_v in d_vals.values(): if isinstance(d_v['val'], np.ndarray): d_v['val'] = d_v['val'].tolist() guardar_json(d_vals, arch=arch_ref) return d_vals
def guardar_archivo(arch, contenido): """ Guarda un documento de manera segura, sin riesgo de corrumpir el archivo existente si se interrumpe el proceso. Parameters ---------- arch : str El archivo que hay que escribir. contenido : str El contenido deseado del archivo. """ with tempfile.NamedTemporaryFile('w', encoding='UTF-8', delete=False) as temp: # Escribimos primero a un fuente temporario para evitar de corrumpir nuestro fuente principal si el programa # se interrumpe durante la operación. temp.write(contenido) # Crear el directorio, si necesario direc = os.path.split(arch)[0] if len(direc) and not os.path.isdir(direc): # pragma: sin cobertura os.makedirs(os.path.split(arch)[0]) # Después de haber escrito el fuente, ya podemos cambiar el nombre sin riesgo. try: if os.path.splitdrive(temp.name)[0] == os.path.splitdrive(arch)[0]: os.replace(temp.name, arch) else: # En casos de documentos en distintos discos, debemos emplear `shutil` en vez. shutil.move(temp.name, arch) except (PermissionError, FileNotFoundError, OSError): # pragma: sin cobertura # Necesario en el caso de corridas en paralelo en Windows. Sin este, la reimportación de Tinamït ocasionada # por varias corridas paralelas al mismo tiempo puede causar que el mismo documento se escriba por dos procesos # al mismo tiempo, el cual trava el sistema. avisar(arch)
def obt_conf(cls, llave, auto=None, cond=None, mnsj_err=None): """ Obtiene un valor de configuración de la subclase de modelo. Parameters ---------- llave: str El parámetro de configuración. auto: str or int or float or list or bool or dict Un valor automático a aplicar si no se encuentra en el diccionario de configuración. cond: Una condición para validar el valor; si no pasa la condición, se tratará como valor que falta. mnsj_err: Un mensaje de aviso para devolver al usuario si no se encuentra el valor. Returns ------- str, int, float, list, bool, dict El valor de configuración """ auto = auto or [] if isinstance(auto, str): auto = [auto] try: op = conf_mods[cls.__name__][llave] if cond is None or cond(op): return op except KeyError: pass for op in auto: if cond is None or cond(op): conf_mods[cls.__name__, llave] = op return op if mnsj_err: avisar(mnsj_err)
def _resolv_conv(unid_1, unid_2, conv): if conv is None: # Si no se especificó factor de conversión... mensaje = _( 'No se pudo identificar una conversión automática entre {} y {}. ' 'Se está suponiendo un factor de conversión de 1.').format( unid_1, unid_2) if unid_1 is None or unid_2 is None: conv = 1 if not (unid_1 is unid_2 is None): avisar(mensaje) else: # Intentar hacer una conversión automática. try: conv = convertir(de=unid_1, a=unid_2) except ValueError: # Si eso no funcionó, suponer una conversión de 1. conv = 1 avisar(mensaje) return conv
def _extraer_de_archivo(archivo): if not os.path.isfile(archivo): raise FileNotFoundError( _('El archivo siguiente no existe... :(\n\t{}').format(archivo)) if os.path.splitext(archivo)[1] != '.py': raise ValueError( _('El archivo siguiente no parece ser un archivo Python.').format( archivo)) dir_mod, nombre_mod = os.path.split(archivo) sys.path.append(dir_mod) módulo = importar_mod(os.path.splitext(nombre_mod)[0]) instancias = { nmb: cls for nmb, cls in inspect.getmembers(módulo, lambda x: isinstance(x, ModeloBF)) } clases = { nmb: cls for nmb, cls in inspect.getmembers( módulo, lambda x: (inspect.isclass(x) and issubclass(x, ModeloBF))) } if instancias: if 'Envoltura' in instancias: return instancias['Envoltura'] return list(instancias.values())[0] potenciales = {} errores = {} for nmb, cls in clases.items(): # noinspection PyBroadException try: potenciales[nmb] = cls() except NotImplementedError: continue except Exception: errores[nmb] = traceback.format_exc() continue if len(potenciales) == 1: return list(potenciales.values())[0] elif 'Envoltura' in potenciales: return potenciales['Envoltura'] elif potenciales: nmb_elegida = list(potenciales)[0] avisar( _('\nHabía más de una instancia de "ModeloBF" en el fuente' '\n\t{}' '\n...y ninguna se llamaba "Envoltura". Tomaremos "{}" como la envoltura' '\ny esperaremos que funcione. Si no te parece, asegúrate que la definición de clase o el' '\nobjeto correcto se llame "Envoltura".').format( archivo, nmb_elegida)) return potenciales[nmb_elegida] raise AttributeError( _('El archivo especificado: \n\t{}\nno contiene subclase o instancia de "EnvolturaBF" utilizable. ' '\nErrores encontrados:{}').format( archivo, ''.join([ '\n\n\t{}: \n{}'.format(nmb, e) for nmb, e in errores.items() ])))
var_mu_trans = var_mu * fac var_s_trans = var_s * fac var_0 = pm3.Uniform(name='0', lower=0, upper=10) l = [pm3.Uniform(name='z_{}'.format(i), lower=1, upper=2) for i in range(100)] @as_op(itypes=[tt.dscalar, tt.dscalar, tt.dscalar], otypes=[tt.dscalar, tt.dscalar]) def func_todo(mu=var_mu_trans, s=var_s_trans, _=l): a = [x / 10000 for x in _] return mu, s obs = pm3.Normal(name='obs', mu=func_todo[0], sd=func_todo[1], observed=datos) if adaptivo: avisar('Método de paso establecido automáticamente.') t = pm3.sample(draws=n_iter) else: from Matemáticas.Variables import VarPyMC3 var_mu = VarPyMC3('mu', 'Uniforme', {'ubic': 0, 'escl': 10 * fac}) var_s = VarPyMC3('sigma', 'Gamma', {'a': 1, 'ubic': 0, 'escl': 10 * fac}) var_0 = VarPyMC3('0', 'Uniforme', {'ubic': 0, 'escl': 10}) l_0 = [VarPyMC3('z_{}'.format(i), 'Normal', {'ubic': 1, 'escl': 2}) for i in range(100)] l_vars = [v.var for v in l_0] # Unas pruebitas de variables generados a base de densidad y de límites. No afectan el modelo prueba aquí. l_pruebas_extr = [ # VarPyMC2.de_densidad(nombre='prueba_uni', dens=0.8, líms_dens=(-3, 4), líms=(-5, 5), cont=True), # VarPyMC2.de_densidad(nombre='prueba_uni2', dens=1, líms_dens=(-3, 4), líms=(-5, 5), cont=True),
def de_traza(cls, trz, permitidas): # Un diccionario para guardar el mejor ajuste mejor_ajuste = dict(prms={}, tipo='', p=0.0) dists_potenciales = [x for x in dists_potenciales if x in cls.dists_disp()] # Verificar que todavia queden distribuciones para considerar. if len(dists_potenciales) == 0: raise ValueError('Ninguna de las distribuciones especificadas es apropiada para el tipo de distribución.') # Para cada distribución potencial para representar a nuestros datos... for nombre_dist in dists_potenciales: # El diccionario de la distribución dic_dist = Ds.dists[nombre_dist] # El máximo y el mínimo de la distribución mín_dist, máx_dist = dic_dist['límites'] # Verificar que los límites del parámetro y de la distribución sean compatibles lím_igual = (((mín_dist == mín_parám == -np.inf) or (not np.isinf(mín_dist) and not np.isinf(mín_parám))) and ((máx_dist == máx_parám == np.inf) or (not np.isinf(máx_dist) and not np.isinf(máx_parám)))) # Si son compatibles... if lím_igual: if mín_parám == -np.inf and máx_parám != np.inf: inv = True else: inv = False # Restringimos las posibilidades para las distribuciones a ajustar, si necesario if np.isinf(mín_parám): if np.isinf(máx_parám): # Para el caso de un parámetro sín límites teoréticos (-inf, inf), no hay restricciones en la # distribución. restric = {} else: raise ValueError('No debería ser posible llegar hasta este error.') else: if np.isinf(máx_parám): # En el caso [R, inf), limitamos el valor inferior de la distribución al límite inferior del # parámetro restric = {'floc': mín_parám} else: # En el caso [R, R], limitamos los valores inferiores y superiores de la distribución. if nombre_dist == 'Uniforme' or nombre_dist == 'Beta': restric = {'floc': mín_parám, 'fscale': máx_parám - mín_parám} elif nombre_dist == 'NormalTrunc': restric = {'floc': (máx_parám + mín_parám) / 2} elif nombre_dist == 'VonMises': restric = {'floc': mín_parám + mat.pi, 'fscale': máx_parám - mín_parám} else: raise ValueError(nombre_dist) # Ajustar los parámetros de la distribución SciPy para caber con los datos. if nombre_dist == 'Uniforme': # Para distribuciones uniformes, no hay nada que calibrar. prms = {'ubic': restric['floc'], 'escl': restric['fscale']} else: try: tupla_prms = dic_dist['scipy'].fit(datos, **restric) l_prms = dic_dist['paráms'] prms = {p: v for p, v in zip(l_prms, tupla_prms)} except: prms = None if prms is not None: # Medir el ajuste de la distribución prms_scipy = prms.copy() prms_scipy['loc'] = prms_scipy.pop('ubic') prms_scipy['scale'] = prms_scipy.pop('escl') p = estad.kstest(rvs=datos, cdf=dic_dist['scipy'](**prms_scipy).cdf)[1] # Si el ajuste es mejor que el mejor ajuste anterior... if p > mejor_ajuste['p'] or mejor_ajuste['tipo'] == '': # Guardarlo mejor_ajuste['p'] = p mejor_ajuste['prms'] = prms mejor_ajuste['tipo'] = nombre_dist # Inversar la distribución sinecesario if inv and 'escl' in prms: prms['escl'] = -prms['escl'] # Si no logramos un buen aujste, avisar al usuario. if mejor_ajuste['p'] <= 0.10: avisar('El ajuste de la mejor distribución quedó muy mal (p = %f).' % round(mejor_ajuste['p'], 4)) # Para hacer: ¿Permitir transformaciones adicionales a los datos? # Devolver la distribución con el mejor ajuste, tanto como el valor de su ajuste. resultado = {'dist': VarSciPy(tipo_dist=mejor_ajuste['tipo'], paráms=mejor_ajuste['prms']), 'nombre': mejor_ajuste['tipo'], 'prms': mejor_ajuste['prms'], 'p': mejor_ajuste['p']} return resultado
def obt_vals(símismo, n): reemplazar = n > len(símismo.trz) if reemplazar: avisar('Repitiendo valores porque se pidieron más repeticiones que hay disponibles.') return np.random.choice(símismo.trz, n, replace=reemplazar, p=símismo.pesos)