From 193c66300f17240378793fdaa2ab44e3841bf011 Mon Sep 17 00:00:00 2001 From: julienmalard Date: Fri, 6 Mar 2020 16:01:55 -0500 Subject: [PATCH] =?UTF-8?q?Combinaci=C3=B3n=20con=20contexto=5Fredes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../test_cultivo/test_cultivo.py" | 6 +- .../test_cultivo/test_pcse.py" | 4 +- .../test_m\303\263ds/test_rae/rcrs/redes.py" | 29 ++-- .../test_rae/test_ecs/test_depred.py" | 12 +- .../test_rae/test_red/test_red.py" | 80 +++++++++-- tikon/central/coso.py | 18 +++ "tikon/central/par\303\241ms_exper.py" | 2 +- tikon/central/res.py | 7 +- tikon/central/simul.py | 7 +- tikon/datos/datos.py | 2 +- tikon/datos/obs.py | 8 +- tikon/datos/proc.py | 7 +- "tikon/m\303\263ds/rae/manejo.py" | 6 +- "tikon/m\303\263ds/rae/orgs/insectos/ins.py" | 2 +- .../m\303\263ds/rae/orgs/insectos/paras.py" | 29 ++-- "tikon/m\303\263ds/rae/orgs/organismo.py" | 136 +++++++----------- "tikon/m\303\263ds/rae/orgs/plantas/base.py" | 6 +- "tikon/m\303\263ds/rae/red/obs.py" | 5 +- "tikon/m\303\263ds/rae/red/red.py" | 108 +++++++++----- "tikon/m\303\263ds/rae/red/res/cohortes.py" | 2 + 20 files changed, 300 insertions(+), 176 deletions(-) diff --git "a/pruebas/test_m\303\263ds/test_cultivo/test_cultivo.py" "b/pruebas/test_m\303\263ds/test_cultivo/test_cultivo.py" index 57897395..c8fee02a 100644 --- "a/pruebas/test_m\303\263ds/test_cultivo/test_cultivo.py" +++ "b/pruebas/test_m\303\263ds/test_cultivo/test_cultivo.py" @@ -24,8 +24,8 @@ def setUpClass(cls): cls.mód_cult = Cultivo() cls.ins = LotkaVolterra('insecto') cls.tomate = Tomate() - cls.ins.secome(cls.tomate) - cls.red = RedAE([cls.tomate, cls.ins]) + with RedAE([cls.tomate, cls.ins]) as cls.red: + cls.ins.secome(cls.tomate) def _prueba_parc(símismo, parc): res = Modelo( @@ -35,7 +35,7 @@ def _prueba_parc(símismo, parc): npt.assert_equal(res[Cultivo.nombre][RES_BIOMASA].res.values, símismo.biomasa) npt.assert_equal(res[Cultivo.nombre][RES_HUMSUELO].res.values, símismo.hum_suelo) npt.assert_equal( - res[RedAE.nombre][RES_POBS].res.loc[{EJE_ETAPA: símismo.tomate.etapas()}].values, símismo.biomasa + res[RedAE.nombre][RES_POBS].res.loc[{EJE_ETAPA: símismo.tomate.etapas}].values, símismo.biomasa ) def test_combin(símismo): diff --git "a/pruebas/test_m\303\263ds/test_cultivo/test_pcse.py" "b/pruebas/test_m\303\263ds/test_cultivo/test_pcse.py" index 4d517d99..84e3bb89 100644 --- "a/pruebas/test_m\303\263ds/test_cultivo/test_pcse.py" +++ "b/pruebas/test_m\303\263ds/test_cultivo/test_pcse.py" @@ -19,8 +19,8 @@ class PruebaPCSE(unittest.TestCase): def test_pcse(símismo): gusanito = LotkaVolterra('soy gusano') remolacha = RemolachaAzucarera() - gusanito.secome(remolacha) - red = RedAE([remolacha, gusanito]) + with RedAE([remolacha, gusanito]) as red: + gusanito.secome(remolacha) modelo = Wofost71_PP parc = ParcelasCultivoPCSE( diff --git "a/pruebas/test_m\303\263ds/test_rae/rcrs/redes.py" "b/pruebas/test_m\303\263ds/test_rae/rcrs/redes.py" index cc16c2f4..462cf853 100644 --- "a/pruebas/test_m\303\263ds/test_rae/rcrs/redes.py" +++ "b/pruebas/test_m\303\263ds/test_rae/rcrs/redes.py" @@ -9,6 +9,7 @@ esfécido = Esfécido('esfécido') parasitoide = Parasitoide('parasitoide') paras_con_pupa = Parasitoide('parasitoide con pupa', pupa=True) +hiperparasitoide = Parasitoide('hiperparasitoide') metam_completa = MetamCompleta('metamórfosis completa') metam_comp_sin_huevo = MetamCompleta('metamórfosis completa sin huevo', huevo=False) @@ -22,17 +23,27 @@ red_1_insecto = RedAE([sencillo]) -otro_sencillo.secome(sencillo) -otro_más.secome(sencillo) -otro_más.secome(otro_sencillo) -red_depred = RedAE([sencillo, otro_sencillo, otro_más]) +red_depred_mútliples = RedAE([sencillo, otro_sencillo, otro_más]) +red_depred = RedAE([sencillo, otro_más]) -red_depred_sub = RedAE([sencillo, otro_más]) +with red_depred_mútliples: + otro_más.secome(otro_sencillo) + otro_sencillo.secome(sencillo) + with red_depred: + otro_más.secome(sencillo) -parasitoide.parasita(metam_completa, etps_entra=['juvenil'], etp_emerg='pupa') -red_parasitismo = RedAE([metam_completa, parasitoide]) +with RedAE([metam_completa, parasitoide]) as red_parasitismo: + parasitoide.parasita(metam_completa) -esfécido.captura(metam_completa, etps_presa='juvenil') -red_esfécido = RedAE([esfécido, metam_completa]) +with RedAE([esfécido, metam_completa]) as red_esfécido: + esfécido.captura(metam_completa) + +with RedAE([metam_completa, hiperparasitoide, paras_con_pupa]) as red_hiperparasitismo: + paras_con_pupa.parasita(metam_completa) + hiperparasitoide.parasita(paras_con_pupa) + +with RedAE([parasitoide, metam_completa, metam_incompleta]) as red_paras_generalista: + parasitoide.parasita(metam_completa) + parasitoide.parasita(metam_incompleta) exper = Exper('exper', Parcela('parc')) diff --git "a/pruebas/test_m\303\263ds/test_rae/test_ecs/test_depred.py" "b/pruebas/test_m\303\263ds/test_rae/test_ecs/test_depred.py" index 39eecf86..ab819e14 100644 --- "a/pruebas/test_m\303\263ds/test_rae/test_ecs/test_depred.py" +++ "b/pruebas/test_m\303\263ds/test_rae/test_ecs/test_depred.py" @@ -14,17 +14,19 @@ class PruebaDepred(unittest.TestCase): def test_depred(símismo): presa = LotkaVolterra('Presa') depred = LotkaVolterra('Depredador') - depred.secome(presa) - depred_2 = LotkaVolterra('Depredador secundario') - depred_2.secome(presa) - depred_2.secome(depred) + red = RedAE([presa, depred, depred_2]) + + with red: + depred.secome(presa) + depred_2.secome(presa) + depred_2.secome(depred) f_inic, f_final = '2000-01-01', '2000-01-10' t = Tiempo(f_inic, f_final) for ec in EcDepred.cls_ramas: with símismo.subTest(ec.nombre): - mod = gen_modelo_reqs_clima(ec, exper=exper, módulos=RedAE([presa, depred, depred_2]), t=t) + mod = gen_modelo_reqs_clima(ec, exper=exper, módulos=red, t=t) depred.activar_ec(ECS_DEPR, subcateg='Ecuación', ec=ec.nombre) depred_2.activar_ec(ECS_DEPR, subcateg='Ecuación', ec=ec.nombre) mod.simular(str(ec), exper=exper, t=10, depurar=True) diff --git "a/pruebas/test_m\303\263ds/test_rae/test_red/test_red.py" "b/pruebas/test_m\303\263ds/test_rae/test_red/test_red.py" index 820a95a0..f8a0d8ab 100644 --- "a/pruebas/test_m\303\263ds/test_rae/test_red/test_red.py" +++ "b/pruebas/test_m\303\263ds/test_rae/test_red/test_red.py" @@ -1,21 +1,81 @@ import unittest +from pruebas.test_móds.test_rae.rcrs import redes as r from tikon.central import Modelo -from pruebas.test_móds.test_rae.rcrs import redes +from tikon.móds.rae.red import RedAE class PruebaRed(unittest.TestCase): def test_1_insecto(símismo): - res = Modelo(redes.red_1_insecto).simular('1 insecto', exper=redes.exper, t=10, depurar=True) + res = Modelo(r.red_1_insecto).simular('1 insecto', exper=r.exper, t=10, depurar=True) - def test_red_depred(símismo): - res = Modelo(redes.red_depred).simular('depred', exper=redes.exper, t=10, depurar=True) + def test_depred(símismo): + símismo.assertSetEqual(r.red_depred.presas(), set(r.sencillo.etapas)) + res = Modelo(r.red_depred).simular('depred sub', exper=r.exper, t=10, depurar=True) - def test_red_depred_sub(símismo): - res = Modelo(redes.red_depred_sub).simular('depred sub', exper=redes.exper, t=10, depurar=True) + def test_depred_mútliples(símismo): + símismo.assertSetEqual( + set(r.red_depred_mútliples.presas()), set(r.sencillo.etapas).union(r.otro_sencillo.etapas) + ) + res = Modelo(r.red_depred_mútliples).simular('depred', exper=r.exper, t=10, depurar=True) - def test_red_parasitismo(símismo): - res = Modelo(redes.red_parasitismo).simular('parasitismo', exper=redes.exper, t=10, depurar=True) + def test_parasitismo(símismo): + res = Modelo(r.red_parasitismo).simular('parasitismo', exper=r.exper, t=10, depurar=True) - def test_red_esfécido(símismo): - res = Modelo(redes.red_esfécido).simular('esfécido', exper=redes.exper, t=10, depurar=True) \ No newline at end of file + def test_esfécido(símismo): + res = Modelo(r.red_esfécido).simular('esfécido', exper=r.exper, t=10, depurar=True) + + def test_hiperparasitismo(símismo): + res = Modelo(r.red_hiperparasitismo).simular('esfécido', exper=r.exper, t=10, depurar=True) + + def test_parasitismo_circular(símismo): + with símismo.assertRaises(ValueError): + with RedAE(): + r.parasitoide.parasita(r.metam_completa) + r.hiperparasitoide.parasita(r.parasitoide) + r.parasitoide.parasita(r.hiperparasitoide) + + def test_parasitoide_generalista(símismo): + # Verifica que múltiples transiciones a la misma etapa (de huéspedes al parasitoide adulto) funcionen + res = Modelo(r.red_paras_generalista).simular('paras generalista', exper=r.exper, t=10, depurar=True) + + def test_canibalismo(símismo): + pass + + def test_depredador_y_parasitoide(símismo): + pass + + def test_depredador_e_hyperparasitoide(símismo): + pass + + def test_depredador_de_parasitoide(símismo): + pass + + def test_depredador_de_hyperparasitoide(símismo): + pass + + +class PruebaParasitismo(unittest.TestCase): + def test_entra_auto_mútiples_juveniles(símismo): + pass + + def test_entra_auto_sin_juvenil(símismo): + pass + + def test_entra_auto_juvenil_único(símismo): + pass + + def test_entra_auto_huevo(símismo): + pass + + def test_emerg_auto(símismo): + pass + + def test_emerg_auto_entra_final(símismo): + pass + + def test_emerge_antes_entra(símismo): + pass + + def test_sin_espec(símismo): + pass \ No newline at end of file diff --git a/tikon/central/coso.py b/tikon/central/coso.py index 7934e2f2..69b8257c 100644 --- a/tikon/central/coso.py +++ b/tikon/central/coso.py @@ -61,3 +61,21 @@ def _ecs_de_json(símismo, calibs): def __str__(símismo): return símismo.nombre + + def __eq__(símismo, otro): + return isinstance(otro, símismo.__class__) and símismo.nombre == otro.nombre + + def __hash__(símismo): + return hash(símismo.nombre) + + +class SumaCosos(object): + def __init__(símismo, cosos): + símismo.cosos = cosos + + def __add__(símismo, otro): + return SumaCosos(*list(otro), *símismo.cosos) + + def __iter__(símismo): + for coso in símismo.cosos: + yield coso diff --git "a/tikon/central/par\303\241ms_exper.py" "b/tikon/central/par\303\241ms_exper.py" index 0223627e..87a9c2df 100644 --- "a/tikon/central/par\303\241ms_exper.py" +++ "b/tikon/central/par\303\241ms_exper.py" @@ -36,7 +36,7 @@ def __init__(símismo, nombre, exper, sim, datos, n_reps): líms = proc_líms(sim.líms) # para hacer: estandardizar if símismo.datos.obs: - ref = min(líms[1], np.nanmax([o_.datos.values.max() for o_ in símismo.datos.obs])) + ref = min(líms[1], np.nanmax([np.nanmax(o_.datos.values) for o_ in símismo.datos.obs])) if líms == (0, np.inf): apriori = APrioriDist(expon(0, ref)) else: diff --git a/tikon/central/res.py b/tikon/central/res.py index dd933258..c36e5b8c 100644 --- a/tikon/central/res.py +++ b/tikon/central/res.py @@ -125,8 +125,11 @@ def procesar_calib(símismo, proc): for índs in símismo.iter_índs(obs.datos, excluir=EJE_TIEMPO): obs_índs = obs_corresp.loc[índs] - - l_proc.append(proc.calc(obs_índs, res_corresp.loc[índs])) + ejes_combin = [ll for ll in índs if isinstance(índs[ll], tuple)] + res_índs = res_corresp.loc[ + {ll: list(v) if ll in ejes_combin else v for ll, v in índs.items()} + ].sum(ejes_combin) + l_proc.append(proc.calc(obs_índs, res_índs)) pesos.append(proc.pesos(obs_índs)) if l_proc: return proc.combin(np.array(l_proc), pesos=pesos), proc.combin_pesos(pesos) diff --git a/tikon/central/simul.py b/tikon/central/simul.py index cc419d38..ac1f7c5e 100644 --- a/tikon/central/simul.py +++ b/tikon/central/simul.py @@ -41,8 +41,11 @@ def validar(símismo, proc): return Valid({s: símismo[s].validar(proc=proc) for s in símismo}, proc=proc) def procesar_calib(símismo, proc): - vals, pesos = np.array(list(zip(*[símismo[s].procesar_calib(proc) for s in símismo]))) - return proc.combin(vals, pesos=pesos), proc.combin_pesos(pesos) + evl = list(zip(*[símismo[s].procesar_calib(proc) for s in símismo])) + if evl: + vals, pesos = np.array(evl) + return proc.combin(vals, pesos=pesos), proc.combin_pesos(pesos) + return 0, 0 def graficar(símismo, directorio, argsll=None): for s in símismo: diff --git a/tikon/datos/datos.py b/tikon/datos/datos.py index 0e631bda..7d27da90 100644 --- a/tikon/datos/datos.py +++ b/tikon/datos/datos.py @@ -11,7 +11,7 @@ def _índices(símismo, dic): if isinstance(dic, Datos): dic = dic.coords return { - dm: [símismo.datos.coords[dm].index(c) for c in (crds if isinstance(crds, list) else [crds])] + dm: [símismo.datos.coords[dm].index(c) for c in (crds if isinstance(crds, (list, set)) else [crds])] for dm, crds in dic.items() } diff --git a/tikon/datos/obs.py b/tikon/datos/obs.py index 068fc0f4..4395c0ee 100644 --- a/tikon/datos/obs.py +++ b/tikon/datos/obs.py @@ -37,6 +37,9 @@ def de_cuadro(cls, datos_pd, corresp, eje_principal, parc=None, tiempo=None, coo if isinstance(datos_pd, str): datos_pd = pd.read_csv(datos_pd, encoding='utf8') corresp = corresp or {} + for ll, v in corresp.items(): + if isinstance(v, list): + corresp[ll] = tuple(v) coords = { EJE_PARC: parc or EJE_PARC, EJE_TIEMPO: tiempo or EJE_TIEMPO, @@ -46,9 +49,10 @@ def de_cuadro(cls, datos_pd, corresp, eje_principal, parc=None, tiempo=None, coo coords_xr = coords.copy() for dim, crd in coords.items(): if isinstance(dim, str) and crd in datos_pd.columns: - coords_xr[dim] = datos_pd[crd] + coords_xr[dim] = datos_pd[crd].unique() else: coords_xr[dim] = [crd] + coords_xr[eje_principal] = list(corresp.values()) datos = xr.DataArray(np.nan, coords=coords_xr, dims=list(coords_xr)) @@ -60,7 +64,7 @@ def de_cuadro(cls, datos_pd, corresp, eje_principal, parc=None, tiempo=None, coo } vals = d[[x for x in list(d.axes[0]) if x in corresp]] datos.loc[índs] = vals * factor - + datos.coords[EJE_PARC] = [str(prc) for prc in datos.coords[EJE_PARC].values] return cls(datos) def __contains__(símismo, itema): diff --git a/tikon/datos/proc.py b/tikon/datos/proc.py index 09bba499..9dac17a4 100644 --- a/tikon/datos/proc.py +++ b/tikon/datos/proc.py @@ -12,7 +12,12 @@ def n_existen(x): # Funciones criterios def ens(o, s): - return of.nashsutcliffe(o.values, s.median(dim=(EJE_PARÁMS, EJE_ESTOC)).values) + ev = of.nashsutcliffe(o.values, s.median(dim=(EJE_PARÁMS, EJE_ESTOC)).values) + if np.isnan(ev): + return 1 + elif np.isinf(ev): + return -1e6 + return ev def rcep(o, s): diff --git "a/tikon/m\303\263ds/rae/manejo.py" "b/tikon/m\303\263ds/rae/manejo.py" index a31990ce..3941f72a 100644 --- "a/tikon/m\303\263ds/rae/manejo.py" +++ "b/tikon/m\303\263ds/rae/manejo.py" @@ -23,12 +23,12 @@ def __init__(símismo, etapas, prueba, func=Datos.suma, espera=14): class AcciónPob(Acción): def __init__(símismo, etapa): - símismo.etapa = etapa + símismo.etapa = [etapa] if isinstance(etapa, Etapa) else etapa def _proc_pobs(símismo, pobs): if isinstance(pobs, Datos): - return pobs.expandir_dims(coords={EJE_ETAPA: [símismo.etapa]}) - return Datos(pobs.item(), coords={EJE_ETAPA: [símismo.etapa]}, dims=[EJE_ETAPA]) + return pobs.expandir_dims(coords={EJE_ETAPA: símismo.etapa}) + return Datos(pobs.item(), coords={EJE_ETAPA: símismo.etapa}, dims=[EJE_ETAPA]) def __call__(símismo, sim, donde): raise NotImplementedError diff --git "a/tikon/m\303\263ds/rae/orgs/insectos/ins.py" "b/tikon/m\303\263ds/rae/orgs/insectos/ins.py" index 13b3809a..273e73d1 100644 --- "a/tikon/m\303\263ds/rae/orgs/insectos/ins.py" +++ "b/tikon/m\303\263ds/rae/orgs/insectos/ins.py" @@ -49,7 +49,7 @@ def resolver_etapas(símismo, etapas): if etapas is not None and JUVENIL in etapas: etapas.remove(JUVENIL) - for etp in símismo._etapas: + for etp in símismo.etapas: if etp.nombre.startswith(JUVENIL): etapas.append(etp) diff --git "a/tikon/m\303\263ds/rae/orgs/insectos/paras.py" "b/tikon/m\303\263ds/rae/orgs/insectos/paras.py" index 410c39f1..d756a386 100644 --- "a/tikon/m\303\263ds/rae/orgs/insectos/paras.py" +++ "b/tikon/m\303\263ds/rae/orgs/insectos/paras.py" @@ -56,7 +56,7 @@ def __init__(símismo, nombre, pupa=False): nombre=nombre, huevo=False, njuvenil=1, pupa=pupa, adulto=True, tipo_ecs=tipo_ec ) - def parasita(símismo, huésped, etps_entra, etp_emerg, etp_símismo='adulto', etp_recip=None): + def parasita(símismo, huésped, etps_entra=None, etp_emerg=None, etp_símismo='adulto', etp_recip=None): """ Indica la relación de parasitismo. @@ -78,6 +78,19 @@ def parasita(símismo, huésped, etps_entra, etp_emerg, etp_símismo='adulto', e if etp_recip is None: etp_recip = 'pupa' if símismo.pupa else 'adulto' + + if etps_entra is None: + try: + etps_entra = huésped['juvenil'] + except KeyError: + etps_entra = huésped.etapas[0] + + if etp_emerg is None: + siguiente = (etps_entra if isinstance(etps_entra, Etapa) else etps_entra[-1]).siguiente() + etp_emerg = siguiente or huésped.etapas[-1] + + # if etp_emerg.index(): + # raise ValueError('') super().parasita( huésped=huésped, etp_símismo=etp_símismo, etps_entra=etps_entra, etp_emerg=etp_emerg, etp_recip=etp_recip ) @@ -135,17 +148,5 @@ def captura(símismo, presa, etps_presa=None): etps_presa: Etapa or str or list La(s) etapa(s) de la presa que pueden ser víctimas. """ + etps_presa = etps_presa or presa['juvenil'] símismo.secome(presa=presa, etps_presa=etps_presa, etps_símismo='adulto') - - def nocaptura(símismo, presa, etps_presa=None): - """ - Borra una relación entre un Esfécido y una presas. - - Parameters - ---------- - presa: Insecto - La presa. - etps_presa: Etapa or str or list - La(s) etapa(s) de la presa que ya no pueden ser víctimas. - """ - símismo.nosecome(presa=presa, etps_presa=etps_presa, etps_símismo='adulto') diff --git "a/tikon/m\303\263ds/rae/orgs/organismo.py" "b/tikon/m\303\263ds/rae/orgs/organismo.py" index efe8daff..f50ce74f 100644 --- "a/tikon/m\303\263ds/rae/orgs/organismo.py" +++ "b/tikon/m\303\263ds/rae/orgs/organismo.py" @@ -1,9 +1,7 @@ -from typing import List - -from tikon.central.coso import Coso - +from tikon.central.coso import Coso, SumaCosos from .ecs import EcsOrgs from .ecs.utils import ECS_EDAD, ECS_MRTE, ECS_TRANS, ECS_ESTOC +from ..utils import contexto class Organismo(Coso): @@ -21,9 +19,7 @@ def __init__(símismo, nombre, etapas): etapas = [etapas] etapas = [e if isinstance(e, Etapa) else símismo._gen_etapa(e) for e in etapas] - símismo._etapas = etapas - símismo._rels_presas = [] # type: List[RelaciónPresa] - símismo._rels_parás = [] # type: List[RelaciónParas] + símismo.etapas = etapas def activar_ec(símismo, categ, subcateg, ec, etapas=None): etapas = símismo.resolver_etapas(etapas) @@ -52,100 +48,60 @@ def borrar_aprioris(símismo, categ=None, sub_categ=None, ec=None, prm=None, ín etp.borrar_aprioris(categ, sub_categ, ec, prm, índs=índs) def verificar(símismo): - for etp in símismo._etapas: + for etp in símismo.etapas: etp.ecs.verificar() def borrar_calib(símismo, nombre): - for etp in símismo._etapas: + for etp in símismo.etapas: etp.borrar_calib(nombre) def renombrar_calib(símismo, nombre, nuevo): - for etp in símismo._etapas: + for etp in símismo.etapas: etp.renombrar_calib(nombre, nuevo) def secome(símismo, presa, etps_presa=None, etps_símismo=None): etps_presa = presa.resolver_etapas(etps_presa) etps_símismo = símismo.resolver_etapas(etps_símismo) + if not contexto: + raise ValueError('Debes especificar relaciones tróficas adentro de un bloque `with` con la red de interés.') - for e_p in etps_presa: - for e_s in etps_símismo: - obj_rel = RelaciónPresa(presa=presa, etp_presa=e_p, etp_depred=e_s) - símismo._rels_presas.append(obj_rel) - - def nosecome(símismo, presa, etps_presa=None, etps_símismo=None): - - etps_presa = presa.resolver_etapas(etps_presa) - etps_símismo = símismo.resolver_etapas(etps_símismo) - - for rel in list(símismo._rels_presas): - if rel.presa is presa and rel.etp_presa in etps_presa and rel.etp_depred in etps_símismo: - símismo._rels_presas.remove(rel) + for red in contexto: + for e_p in etps_presa: + for e_s in etps_símismo: + obj_rel = RelaciónPresa(presa=presa, etp_presa=e_p, etp_depred=e_s) + red.agregar_relación(obj_rel) def parasita(símismo, huésped, etps_entra, etp_emerg, etp_recip, etp_símismo=None): + if not contexto: + raise ValueError('Debes especificar relaciones tróficas adentro de un bloque `with` con la red de interés.') + etps_entra = huésped.resolver_etapas(etps_entra) etp_emerg = huésped.resolver_etapas(etp_emerg)[0] etp_recip = símismo.resolver_etapas(etp_recip)[0] if etp_símismo is None: - etp_símismo = símismo._etapas[-1] + etp_símismo = símismo.etapas[-1] etp_símismo = símismo.resolver_etapas(etp_símismo)[0] obj_rel = RelaciónParas( huésped=huésped, etps_entra=etps_entra, etp_depred=etp_símismo, etp_emerg=etp_emerg, etp_recip=etp_recip ) - símismo._rels_parás.append(obj_rel) - - def noparasita(símismo, huésped, etps_entra=None, etps_símismo=None): - - etps_entra = símismo.resolver_etapas(etps_entra) - etps_símismo = símismo.resolver_etapas(etps_símismo) - - for rel in list(símismo._rels_parás): - if rel.huésped is huésped and rel.etps_entra in etps_entra and rel.etp_depred in etps_símismo: - símismo._rels_parás.remove(rel) + for red in contexto: + red.agregar_relación(obj_rel) def resolver_etapas(símismo, etapas): if etapas is None: - etapas = símismo._etapas + etapas = símismo.etapas elif isinstance(etapas, (str, Etapa)): etapas = [etapas] etapas = [símismo[e] if isinstance(e, str) else e for e in etapas] return etapas - def etapas(símismo, fantasmas_de=None): - - if fantasmas_de: - etps_fant = [f for r_p in símismo._rels_parás for f in r_p.fantasmas if f.org_hués in fantasmas_de] - else: - etps_fant = [] - - return símismo._etapas + etps_fant - def índice(símismo, etp): if isinstance(etp, str): etp = símismo[etp] - return símismo._etapas.index(etp) - - def presas(símismo, etp=None): - return [rel.etp_presa for rel in símismo._rels_presas if (etp is None or rel.etp_depred == etp)] - - def huéspedes(símismo, etp=None): - """ - Devuelve etapas huéspedes víctimas directas de parasitismo. - - Parameters - ---------- - etp - - Returns - ------- - - """ - return [e_h for rel in símismo._rels_parás for e_h in rel.etps_entra if (etp is None or rel.etp_depred == etp)] - - def fantasmas(símismo): - return [rel.fantasmas[í] for rel in símismo._rels_parás for í in range(len(rel.etps_entra))] + return símismo.etapas.index(etp) def espec_apriori_etp(símismo, etapa, apriori, categ, subcateg, ec, prm, índs=None): símismo[etapa].espec_apriori(apriori, categ, subcateg, ec, prm, índs) @@ -162,24 +118,24 @@ def _ecs_de_json(símismo, calibs): etp._ecs_de_json(calibs[etp.nombre]) def __len__(símismo): - return len(símismo._etapas) + return len(símismo.etapas) def __getitem__(símismo, itema): if isinstance(itema, int): - return símismo._etapas[itema] + return símismo.etapas[itema] try: - return next(e for e in símismo._etapas if e.nombre == itema) + return next(e for e in símismo.etapas if e.nombre == itema) except StopIteration: raise KeyError('Etapa {etp} no existe en organismo {org}.'.format(etp=itema, org=símismo)) def __iter__(símismo): - for etp in símismo._etapas: + for etp in símismo.etapas: yield etp def __contains__(símismo, itema): if isinstance(itema, str): - return any(str(itema) == e.nombre for e in símismo.etapas()) - return any(itema is e for e in símismo.etapas()) + return any(str(itema) == e.nombre for e in símismo.etapas) + return any(itema is e for e in símismo.etapas) class Etapa(Coso): @@ -215,6 +171,12 @@ def __add__(símismo, otro): def __str__(símismo): return str(símismo.org) + ' : ' + símismo.nombre + def __eq__(símismo, otro): + return isinstance(otro, símismo.__class__) and símismo.nombre == otro.nombre and símismo.org == otro.org + + def __hash__(símismo): + return hash(str(símismo)) + categs_parás = [ECS_TRANS, ECS_EDAD, ECS_MRTE, ECS_ESTOC] @@ -249,14 +211,28 @@ def siguiente(símismo): return símismo.sig -class RelaciónPresa(object): +class RelaciónOrgs(object): + def __init__(símismo, orgs): + símismo.orgs = orgs + + @property + def tipo(símismo): + raise NotImplementedError + + +class RelaciónPresa(RelaciónOrgs): + tipo = 'presa' + def __init__(símismo, presa, etp_presa, etp_depred): símismo.presa = presa símismo.etp_presa = etp_presa símismo.etp_depred = etp_depred + super().__init__([presa, etp_depred.org]) -class RelaciónParas(object): +class RelaciónParas(RelaciónOrgs): + tipo = 'paras' + def __init__(símismo, huésped, etps_entra, etp_depred, etp_emerg, etp_recip): símismo.huésped = huésped símismo.etps_entra = etps_entra @@ -274,17 +250,13 @@ def __init__(símismo, huésped, etps_entra, etp_depred, etp_emerg, etp_recip): )) símismo.fantasmas.reverse() + super().__init__([huésped, etp_depred.org]) -class SumaEtapas(object): - def __init__(símismo, etapas): - símismo.etapas = etapas + +class SumaEtapas(SumaCosos): def __add__(símismo, otro): if isinstance(otro, Etapa): - return SumaEtapas([otro, *símismo.etapas]) + return SumaEtapas([otro, *símismo.cosos]) else: - return SumaEtapas(*list(otro), *símismo.etapas) - - def __iter__(símismo): - for etp in símismo.etapas: - yield etp + return SumaEtapas(*list(otro), *símismo.cosos) diff --git "a/tikon/m\303\263ds/rae/orgs/plantas/base.py" "b/tikon/m\303\263ds/rae/orgs/plantas/base.py" index 32c6ce91..6e248673 100644 --- "a/tikon/m\303\263ds/rae/orgs/plantas/base.py" +++ "b/tikon/m\303\263ds/rae/orgs/plantas/base.py" @@ -62,11 +62,7 @@ def __init__(símismo, nombre, raíz, palo, sabia, hoja, flor, fruta, semilla, v def fijar_dens(símismo, apriori, etapas=None): - if etapas is None: - etapas = símismo.etapas() - if isinstance(etapas, (str, Etapa)): - etapas = [etapas] - etapas = [e if isinstance(e, str) else e.nombre for e in etapas] + etapas = [e if isinstance(e, str) else e.nombre for e in símismo.resolver_etapas(etapas)] símismo.activar_ec(ECS_CREC, 'Tasa', 'Nada', etapas=etapas) símismo.activar_ec(ECS_CREC, 'Ecuación', 'Constante', etapas=etapas) diff --git "a/tikon/m\303\263ds/rae/red/obs.py" "b/tikon/m\303\263ds/rae/red/obs.py" index a3b4f226..0ea6235a 100644 --- "a/tikon/m\303\263ds/rae/red/obs.py" +++ "b/tikon/m\303\263ds/rae/red/obs.py" @@ -4,6 +4,7 @@ from tikon.utils import EJE_PARC, EJE_DEST from .red import RedAE +from ..orgs.organismo import Etapa class ObsRAE(Obs): @@ -11,8 +12,10 @@ class ObsRAE(Obs): @classmethod def de_cuadro(cls, datos_pd, corresp, coords=None, tiempo=None, parcela=None, factor=1, **argsll): + corresp = {ll: tuple(v) if not isinstance(v, Etapa) else v for ll, v in corresp.items()} return super().de_cuadro( - datos_pd, corresp=corresp, eje_principal=EJE_ETAPA, parc=parcela, tiempo=tiempo, coords=coords, factor=factor + datos_pd, corresp=corresp, eje_principal=EJE_ETAPA, parc=parcela, tiempo=tiempo, coords=coords, + factor=factor ) @property diff --git "a/tikon/m\303\263ds/rae/red/red.py" "b/tikon/m\303\263ds/rae/red/red.py" index cd7b7eb1..303fb6db 100644 --- "a/tikon/m\303\263ds/rae/red/red.py" +++ "b/tikon/m\303\263ds/rae/red/red.py" @@ -4,12 +4,14 @@ from tikon.central.simul import SimulMódulo from tikon.datos.datos import Datos from tikon.ecs.paráms import Inter -from tikon.móds.rae.utils import RES_POBS, RES_COHORTES, EJE_COH, EJE_ETAPA, EJE_VÍCTIMA +from tikon.móds.rae.utils import RES_POBS, RES_COHORTES, EJE_COH, EJE_ETAPA, EJE_VÍCTIMA, contexto from .res.cohortes import ResCohortes from ..orgs.ecs import EcsOrgs from ..orgs.ecs.utils import ECS_TRANS, ECS_REPR from ..orgs.insectos import Parasitoide -from ..orgs.organismo import EtapaFantasma, Etapa +from ..orgs.insectos.ins import JUVENIL +from ..orgs.insectos.paras import EtapaJuvenilParasitoide +from ..orgs.organismo import EtapaFantasma, Etapa, Organismo from ..red.res import res as res_red @@ -24,7 +26,7 @@ def __init__(símismo, mód, simul_exper, ecs, vars_interés): símismo.etapas = mód.etapas símismo.orgs = mód.orgs presas = mód.presas() - símismo.víctimas = presas + [h for h in mód.huéspedes() if h not in presas] + símismo.víctimas = presas.union({h for h in mód.huéspedes() if h not in presas}) modelo = simul_exper.modelo exper = simul_exper.exper @@ -37,23 +39,23 @@ def __init__(símismo, mód, simul_exper, ecs, vars_interés): if etp.categ_activa(ECS_TRANS, modelo, mód=mód, exper=exper) and etp.siguiente() ] - símismo.parás_hués = [ - (etp, ([etp.etp_hués for etp in mód.fantasmas(etp)], mód.fantasmas(etp))) for etp in símismo.etapas - if isinstance(etp.org, Parasitoide) and etp.nombre == 'adulto' and mód.huéspedes(etp) - ] + símismo.parás_hués = [] + for etp in símismo.etapas: + if isinstance(etp.org, Parasitoide) and etp.nombre == 'adulto': + huéspedes = list(mód.huéspedes(etp)) + fantasmas = sorted(mód.fantasmas(huéspedes, paras=etp), key=lambda x: huéspedes.index(x.etp_hués)) + símismo.parás_hués.append((etp, (huéspedes, fantasmas))) # Índices para luego poder encontrar las interacciones entre parasitoides y víctimas en las matrices de # depredación - depredadores = [ - etp for etp in símismo.etapas if any(pr in símismo.etapas for pr in etp.presas() + etp.huéspedes()) - ] + depredadores = [etp for etp in símismo.etapas if mód.presas(etp) or mód.huéspedes(etp)] símismo.máscara_parás = Datos( False, coords={ EJE_ETAPA: depredadores, EJE_VÍCTIMA: símismo.víctimas }, dims=[EJE_ETAPA, EJE_VÍCTIMA] ) - for parás, hués_fants in símismo.parás_hués: - símismo.máscara_parás.loc[{EJE_ETAPA: parás, EJE_VÍCTIMA: hués_fants[0]}] = True + for paras, hués_fants in símismo.parás_hués: + símismo.máscara_parás.loc[{EJE_ETAPA: paras, EJE_VÍCTIMA: hués_fants[0]}] = True super().__init__(mód, simul_exper=simul_exper, ecs=ecs, vars_interés=vars_interés) @@ -86,10 +88,12 @@ class RedAE(Módulo): def __init__(símismo, orgs=None): super().__init__(cosos=orgs) + símismo.relaciones = {'presa': [], 'paras': []} @property def etapas(símismo): - return [etp for org in símismo for etp in símismo[org].etapas(fantasmas_de=símismo._cosos.values())] + etps_fant = [fnt for r_p in símismo.relaciones['paras'] for fnt in r_p.fantasmas] + return [etp for org in símismo for etp in símismo[org].etapas] + etps_fant @property def orgs(símismo): @@ -102,7 +106,13 @@ def quitar_org(símismo, org): try: símismo._cosos.pop(str(org)) except KeyError: - raise KeyError('El organismo "{org}" no existía en esta red.'.format(org=org)) + raise KeyError('El organismo "{org}" no existía en la red "{r}".'.format(org=org, r=símismo)) + + def agregar_relación(símismo, relación): + for org in relación.orgs: + if org not in símismo.orgs: + raise ValueError('Organismo "{org}" no existe en red "{r}".'.format(org=org, r=símismo)) + símismo.relaciones[relación.tipo].append(relación) def inter(símismo, modelo, coso, tipo): if isinstance(tipo, str): @@ -122,28 +132,62 @@ def inter(símismo, modelo, coso, tipo): if len(etps_inter): return Inter(etps_inter, eje=EJE_VÍCTIMA, coords=coords) - def presas(símismo, etps=None): - if isinstance(etps, Etapa): - etps = [etps] - elif etps is None: - etps = símismo.etapas - presas = [pr for etp in etps for pr in etp.presas() if pr in símismo.etapas] + def presas(símismo, depred=None, presa=None): + presa = símismo._resolver_etapas(presa) + depred = símismo._resolver_etapas(depred) + presas = { + rel.etp_presa for rel in símismo.relaciones['presa'] + if rel.etp_presa in presa and rel.etp_depred in depred + } # Incluir los fantasmas de las presas - fants_presas = [etp for etp in símismo.etapas if isinstance(etp, EtapaFantasma) and etp.etp_hués in presas] + fants_presas = {etp for etp in símismo.etapas if isinstance(etp, EtapaFantasma) and etp.etp_hués in presas} + + return presas.union(fants_presas) + + def huéspedes(símismo, paras=None, hués=None): + """Huéspedes que pueden ser infectados directamente por parasitoide `paras`.""" + paras = símismo._resolver_etapas(paras) + hués = símismo._resolver_etapas(hués) + etps = { + hsp for rel in símismo.relaciones['paras'] if rel.etp_depred in paras + for hsp in rel.etps_entra if hsp in hués + } + + for etp in set(etps): + if isinstance(etp, EtapaJuvenilParasitoide): + etps.remove(etp) + etps.update(símismo.fantasmas(paras=etp.org)) + + return etps + + def fantasmas(símismo, hués=None, paras=None): + hués = símismo._resolver_etapas(hués) + paras = [ + prs for prs in símismo._resolver_etapas(paras) + if isinstance(prs.org, Parasitoide) and prs.nombre == 'adulto' + ] + return [ + fnt for rel in símismo.relaciones['paras'] if rel.etp_depred in paras + for fnt in rel.fantasmas if fnt.etp_hués in hués + ] - return presas + fants_presas + def gen_ecs(símismo, modelo, mód, exper, n_reps): + return EcsOrgs(modelo, mód, exper, cosos=símismo.etapas, n_reps=n_reps) - def huéspedes(símismo, etps=None): - """Huéspedes que pueden ser directamente infectados por parasitoide `etp`.""" - if isinstance(etps, Etapa): + def _resolver_etapas(símismo, etps): + if etps is None: + return símismo.etapas + elif isinstance(etps, (Etapa, Organismo)): etps = [etps] - elif etps is None: - etps = símismo.etapas - return [pr for etp in etps for pr in etp.huéspedes() if pr in símismo.etapas] + etps = [etp for x in etps for etp in ([x] if isinstance(x, Etapa) else x)] + return [etp for etp in etps if etp in símismo.etapas] - def fantasmas(símismo, etp): - return [pr for pr in etp.org.fantasmas() if pr.etp_espejo in símismo.etapas] + def __enter__(símismo): + if símismo not in contexto: + contexto.append(símismo) + return símismo - def gen_ecs(símismo, modelo, mód, exper, n_reps): - return EcsOrgs(modelo, mód, exper, cosos=símismo.etapas, n_reps=n_reps) + def __exit__(símismo, tipo_sld, val_sld, trz_sld): + if símismo in contexto: + contexto.remove(símismo) diff --git "a/tikon/m\303\263ds/rae/red/res/cohortes.py" "b/tikon/m\303\263ds/rae/red/res/cohortes.py" index 5e094249..0219802d 100644 --- "a/tikon/m\303\263ds/rae/red/res/cohortes.py" +++ "b/tikon/m\303\263ds/rae/red/res/cohortes.py" @@ -113,6 +113,8 @@ def quitar(símismo, para_quitar, recips=None): etps_quitar = [x for x in para_quitar.coords[EJE_ETAPA] if x in símismo.datos.coords[EJE_ETAPA]] if not etps_quitar: + if recips: + raise ValueError('Etapas para quitar no tienen cohortes.') return índs = {EJE_ETAPA: etps_quitar} para_quitar = para_quitar.loc[índs]