diff --git a/.gitignore b/.gitignore index dc0373c6..8ee8084c 100644 --- a/.gitignore +++ b/.gitignore @@ -29,6 +29,7 @@ eggs/ .eggs/ lib/ lib64/ +.vscode/ parts/ sdist/ var/ @@ -71,6 +72,7 @@ docs/_build/ _build/* _build + # PyBuilder target/ diff --git a/CITATION.cff b/CITATION.cff index e34df189..c4fa576e 100644 --- a/CITATION.cff +++ b/CITATION.cff @@ -2,8 +2,8 @@ cff-version: 1.2.0 message: If you use this software, please cite it using the metadata from this file. type: software title: 'pycopancore: Reference implementation of the copan:CORE World-Earth modelling framework' -version: 0.7.0 -date-released: '2024-07-04' +version: 0.8.0 +date-released: '2025-01-28' abstract: The pycopancore package is a python implementation of the copan:CORE modeling framework as described in this paper. The framework is designed to allow an easy implementation of World-Earth (i.e., global social-ecological) @@ -14,6 +14,18 @@ abstract: The pycopancore package is a python implementation of the copan:CORE stochastic and deterministic events and therefore allows to compare different model and component types and implementations. authors: +- family-names: Breier + given-names: Jannes + email: jannesbr@pik-potsdam.de + orcid: 0000-0002-9055-6904 +- family-names: Schwarz + given-names: Luana + email: lschwarz@pik-potsdam.de + orcid: 0000-0003-1726-1509 +- family-names: Hotz + given-names: Ronja + email: ronja.hotz@kit.edu + orcid: 0000-0003-3425-268X - family-names: Bechthold given-names: Max email: maxbecht@pik-potsdam.de diff --git a/docs/Makefile b/docs/Makefile index c8653f9b..3c94a46a 100644 --- a/docs/Makefile +++ b/docs/Makefile @@ -6,6 +6,7 @@ SPHINXOPTS = -E -a SPHINXBUILD = sphinx-build PYREVERSE = pyreverse APIDOC = sphinx-apidoc +APIDOCOPTS = -l -d 2 -e -P -M -f -o ./docs/_api SPHINX_APIDOC_OPTIONS=members,undoc-members,private-members,special-members,inherited-members,show-inheritance DOT = dot PAPER = @@ -61,7 +62,7 @@ clean: .PHONY: html html: @echo "Creating auto-generated documentation from source" - cd ..; $(APIDOC) --implicit-namespaces -f -o ./docs/_api ./pycopancore/ ./pycopancore/model_components/base/__init__.py ./pycopancore/model_components/seven_dwarfs/__init__.py + cd ..; $(APIDOC) $(APIDOCOPTS) --implicit-namespaces ./pycopancore/ #./pycopancore/model_components/base/__init__.py ./pycopancore/model_components/seven_dwarfs/__init__.py @echo @echo "Sphinx-apidoc is done, building directories" $(SPHINXBUILD) -b html -v $(ALLSPHINXOPTS) $(BUILDDIR)/html @@ -71,7 +72,7 @@ html: .PHONY: api api: @echo - cd ..; $(APIDOC) -f -o ./docs/_api ./pycopancore/ + cd ..; $(APIDOC) $(APIDOCOPTS) ./docs/_api ./pycopancore/ .PHONY : uml uml: diff --git a/docs/conf.py b/docs/conf.py index d80fad29..8b65a5c4 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -44,7 +44,7 @@ # Napoleon settings napoleon_numpy_docstring = True -napoleon_google_docstring = False +napoleon_google_docstring = True napoleon_include_special_with_doc = True # more info at http://www.sphinx-doc.org/en/stable/ext/ # napoleon.html#module-sphinx.ext.napoleon @@ -54,14 +54,15 @@ # The suffix(es) of source filenames. # You can specify multiple suffix as a list of string: -# source_suffix = ['.rst', '.md'] -source_suffix = '.rst' +source_suffix = ['.rst', '.md'] +#source_suffix = '.rst' # The encoding of source files. #source_encoding = 'utf-8-sig' # The master toctree document. master_doc = 'index' +root_doc = 'index' # General information about the project. project = u'pycopancore' @@ -100,15 +101,15 @@ #default_role = None # If true, '()' will be appended to :func: etc. cross-reference text. -#add_function_parentheses = True +add_function_parentheses = True # If true, the current module name will be prepended to all description # unit titles (such as .. function::). -#add_module_names = True +add_module_names = False # If true, sectionauthor and moduleauthor directives will be shown in the # output. They are ignored by default. -#show_authors = False +show_authors = True # The name of the Pygments (syntax highlighting) style to use. pygments_style = 'sphinx' @@ -185,19 +186,19 @@ html_domain_indices = True # If false, no index is generated. -#html_use_index = True +html_use_index = True # If true, the index is split into individual pages for each letter. -#html_split_index = False +html_split_index = True # If true, links to the reST sources are added to the pages. -#html_show_sourcelink = True +html_show_sourcelink = True # If true, "Created using Sphinx" is shown in the HTML footer. Default is True. -#html_show_sphinx = True +html_show_sphinx = True # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. -#html_show_copyright = True +html_show_copyright = True # If true, an OpenSearch description file will be output, and all pages will # contain a tag referring to it. The value of this option must be the diff --git a/docs/index.rst b/docs/index.rst index 097325af..60ae29a1 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -18,7 +18,7 @@ Contents: .. TODO: move introduction to inside this page so that it is more immediately available for reading? .. toctree:: - :maxdepth: 1 + :maxdepth: 3 :titlesonly: introduction diff --git a/examples/__init__.py b/examples/__init__.py deleted file mode 100644 index 46890d1d..00000000 --- a/examples/__init__.py +++ /dev/null @@ -1,8 +0,0 @@ -# This file is part of pycopancore. -# -# Copyright (C) 2016-2017 by COPAN team at Potsdam Institute for Climate -# Impact Research -# -# URL: -# Contact: core@pik-potsdam.de -# License: BSD 2-clause license diff --git a/pycopancore/__init__.py b/pycopancore/__init__.py index 3aba1e22..e2672f34 100644 --- a/pycopancore/__init__.py +++ b/pycopancore/__init__.py @@ -9,14 +9,4 @@ # # URL: # Contact: core@pik-potsdam.de -# License: BSD 2-clause license - -from .data_model import * -from .process_types import * -from .runners import * -from .util import * - -from .model_components import base - -__url__ = "http://www.pik-potsdam.de/copan/software" -__version__ = "0.1.0" +# License: BSD 2-clause license \ No newline at end of file diff --git a/pycopancore/data_model/__init__.py b/pycopancore/data_model/__init__.py index d640954e..cfbe98f7 100644 --- a/pycopancore/data_model/__init__.py +++ b/pycopancore/data_model/__init__.py @@ -1,3 +1,73 @@ +""" +========== +Data model +========== + +************************** +Variable naming convention +************************** + +We suggest to use rather descriptive variable names that make the relevant +dimension clear in the following fashion: + +* Variables that represent integer cardinalities should be called **numbers** + (possibly abbreviated as `n`, `no`, or `num`) or **counts**. + +* Extensive variables of simple physical dimension should be called **stocks**, + e.g. `atmospheric_carbon_stock` of dimension `carbon` and default unit `GtC`, + or `physical_capital_stock` of dimension `monetary_value` and default unit `dollars`. + +* Intensive variables of simple physical dimension should *not* be called 'stocks' + to distinguish them from extensive variables. E.g. `surface_air_temperature` + of dimension `temperature` and default unit `kelvins`. + +* Variables that represent a stock per surface area, volume, or mass should be + called **densities**, e.g., `vegetation_carbon_density` in `GtC/m2` or + `energy_density_of_wood` in `MJ/kg`. + +* Variables that represent (changes of) stocks per time or time derivatives of stocks + should be called **flows**, e.g. `photosynthesis_carbon_flow` of dimension + `carbon/time` and default unit `GtC/yr`, or `income_flow` of dimension `money/time` + and default unit `dollars/yr`. + +* Variables that represent flows per surface area should be called **fluxes**, + e.g. `sensible_heat_flux` of dimension `energy/time/area` and default unit + `W/m^2`. + +* Variables of dimension `time` that represent specific unique time points + should be called **time_points** or **dates**, e.g., `net_zero_date`. + +* Variables of dimension `time` that represent amounts of time *between* + time points should be called **delays**, **intervals**, **durations**, + **periods**, **ages**, etc., or sometimes just **times**. + e.g. `business_cycle_period` or `Individual.age`. + +* Variables of dimension `1/time` referring to periodic occurrences should be + called **frequencies**, i.e., `voting_frequency`. + +* Other variables of dimension `1/time` should be called **rates**, e.g. + `equilibration_rate`, `discount_rate`, `depreciation_rate`, `diffusion_rate`. + Variables of other dimension than `1/time`, in particular fractions or ratios, + should *not* be called 'rates'. + +* Dimensionless variables between 0 and 1 that represent parts of a whole + should be called **fractions** or **shares**, e.g. `dirty_fraction` or + `fossil_energy_share`. + +* Dimensionless variables that represent the relative size of one quantity as + compared to another quantity of the same dimension should be called **ratios**, + e.g., `cost_benefit_ratio`. + +* Variables representing the derivative of one quantity w.r.t. another quantity + (other than time) should be called **sensitivities**, e.g. + `temperature_sensitivity_of_photosynthesis`. + +* Variables representing the derivative of the *logarithm* of one quantity w.r.t. + the logarithm of another quantity should be called **elasticities**, e.g. + `labor_elasticity_of_fossil_energy_production`. +""" + + # This file is part of pycopancore. # # Copyright (C) 2016-2017 by COPAN team at Potsdam Institute for Climate diff --git a/pycopancore/data_model/dimensional_quantity.py b/pycopancore/data_model/dimensional_quantity.py index 90ccd2d3..017e3942 100644 --- a/pycopancore/data_model/dimensional_quantity.py +++ b/pycopancore/data_model/dimensional_quantity.py @@ -9,8 +9,8 @@ # Contact: core@pik-potsdam.de # License: BSD 2-clause license -from . import dimension -from . import unit as U +from pycopancore.data_model import dimension +from pycopancore.data_model import unit as U class DimensionalQuantity(object): diff --git a/pycopancore/data_model/master_data_model/__init__.py b/pycopancore/data_model/master_data_model/__init__.py index f962b122..cb94d9d2 100644 --- a/pycopancore/data_model/master_data_model/__init__.py +++ b/pycopancore/data_model/master_data_model/__init__.py @@ -41,4 +41,3 @@ from .group import Group as group from .group import Group -from .. import unity diff --git a/pycopancore/data_model/master_data_model/cell.py b/pycopancore/data_model/master_data_model/cell.py index ce5ddd66..c0779546 100644 --- a/pycopancore/data_model/master_data_model/cell.py +++ b/pycopancore/data_model/master_data_model/cell.py @@ -9,8 +9,12 @@ # Contact: core@pik-potsdam.de # License: BSD 2-clause license -from . import ENV, MET -from . import square_kilometers +from pycopancore.data_model.master_data_model.environment \ + import Environment as ENV +from pycopancore.data_model.master_data_model.metabolism \ + import Metabolism as MET +from pycopancore.data_model.master_data_model.dimensions_and_units \ + import DimensionsAndUnits as DAU class Cell: @@ -18,7 +22,7 @@ class Cell: # natural: land_area = ENV.land_area.copy() - land_area.default = 1 * square_kilometers + land_area.default = 1 * DAU.km2 atmospheric_carbon = ENV.atmospheric_carbon.copy() surface_air_temperature = ENV.surface_air_temperature.copy() ocean_carbon = ENV.ocean_carbon.copy() diff --git a/pycopancore/data_model/master_data_model/culture.py b/pycopancore/data_model/master_data_model/culture.py index d89d2c82..2917e680 100644 --- a/pycopancore/data_model/master_data_model/culture.py +++ b/pycopancore/data_model/master_data_model/culture.py @@ -9,11 +9,10 @@ # Contact: core@pik-potsdam.de # License: BSD 2-clause license -from .. import Variable - from networkx import DiGraph, Graph -from .. import unity +from pycopancore.data_model.variable import Variable +from pycopancore.data_model.unit import unity class Culture: diff --git a/pycopancore/data_model/master_data_model/dimensions_and_units.py b/pycopancore/data_model/master_data_model/dimensions_and_units.py index c5072bb9..11575438 100644 --- a/pycopancore/data_model/master_data_model/dimensions_and_units.py +++ b/pycopancore/data_model/master_data_model/dimensions_and_units.py @@ -9,8 +9,8 @@ # Contact: core@pik-potsdam.de # License: BSD 2-clause license -from .. import Dimension -from .. import Unit, unity +from pycopancore.data_model.dimension import Dimension +from pycopancore.data_model.unit import Unit, unity class DimensionsAndUnits: @@ -24,14 +24,15 @@ class DimensionsAndUnits: decimeters = (meters / 10).named("decimeters", symbol="dm") time = Dimension("time", "time") - time.default_unit = a = yr = years = Unit("years", "years", symbol="a") + time.default_unit = a = yr = years = Unit("years", "years", symbol="yr") s = seconds = (years / 31556952).named("seconds", symbol="s") minutes = (seconds * 60).named("minutes", symbol="min") h = hours = (minutes * 60).named("hours", symbol="h") days = (hours * 24).named("days", symbol="d") + doy = (hours * 24).named("day of the year", symbol="doy") weeks = (days * 7).named("weeks") months = (years / 12).named("months") - + mass = Dimension("mass", "mass (only use for matter changing its type, otherwise use specific mass dimension, e.g. 'carbon')") mass.default_unit = t = tonnes = \ @@ -40,7 +41,8 @@ class DimensionsAndUnits: symbol="t") Gt = gigatonnes = (tonnes * 1e9).named("gigatonnes", symbol="Gt") kg = kilograms = (tonnes * 1e-3).named("kilograms", symbol="kg") - + g = grams = (tonnes * 1e-6).named("grams", symbol="g") + absolute_temperature = Dimension("absolute temperature", "absolute temperature") absolute_temperature.default_unit = K = kelvins = \ @@ -49,10 +51,9 @@ class DimensionsAndUnits: # other base dimensions and units: - # TODO: maybe rename to monetary monetary_value: - monetary_value = \ - Dimension("monetary_value", - "inflation-adjusted monetary monetary_value of goods, services etc.") + money = monetary_value = \ + Dimension("money or monetary value", + "inflation-adjusted money or monetary value of goods, services etc.") monetary_value.default_unit = dollars = US_dollars_2005 = \ Unit("dollars", "inflation-adjusted 2005 US dollars", symbol="$") @@ -71,7 +72,10 @@ class DimensionsAndUnits: symbol="tC") GtC = gigatonnes_carbon = (tonnes_carbon * 1e9).named("gigatonnes carbon", symbol="GtC") - + kgC = kilograms_carbon = (tonnes_carbon * 1e-3).named("kilograms carbon", + symbol="kgC") + gC = grams_carbon = (tonnes_carbon * 1e-6).named("grams carbon", + symbol="gC") humans = Dimension("humans", "cardinality of a set of human beings") humans.default_unit = H = people = persons = \ Unit("people", "number of human beings", symbol="H") @@ -80,7 +84,7 @@ class DimensionsAndUnits: #energy = (mass * velocity**2).named("energy") #joules = kilograms * meters**2 / seconds**2 # but: - energy = Dimension("energy", "(not convertible to mass velocity²)") + heat = energy = Dimension("energy", "(not convertible to mass velocity²)") J = joules = Unit("joules", "(not convertible to kg m²/s²)", symbol="J", dimension=energy) energy.default_unit = GJ = gigajoules = \ @@ -94,28 +98,37 @@ class DimensionsAndUnits: ).named("gigacalories (thermochemical)", symbol="Gcalth") - # derived flow dimensions: + # derived flow dimensions and units: value_flow = (monetary_value / time).named("monetary_value flow") carbon_flow = (carbon / time).named("carbon flow") human_flow = (humans / time).named("human flow") - + GW = gigawatts = (GWh / h).named("gigawatts", symbol="GW") - + # other derived dimensions and units: - + percent = pct = (unity / 100).named("per cent", symbol="%") - + area = (length**2).named("area", "2D spatial dimension") - square_kilometers = (kilometers**2).named("square kilometers", symbol="km²") - hectares = (meters**2 * 1e4).named("hectares", symbol="ha") - + km2 = square_kilometers = (kilometers**2).named("square kilometers", + symbol="km²") + ha = hectares = (meters**2 * 1e4).named("hectares", symbol="ha") + m2 = square_meters = (meters**2).named("square meters", symbol="m²") + volume = (length**3).named("volume", "3D spatial dimension") - litres = (decimeters**3).named("litres", symbol="l") - + litres = (decimeters**3).named("litres", symbol="l") + velocity = (length / time).named("velocity") - acceleration = (velocity / time).named("acceleration") + tC_per_ha = (t/ha).named("tonnes carbon per hectare", + symbol="tC/ha") + kgC_per_m2 = (kgC/m2).named("kilograms carbon per square meter", + symbol="kgC/m²") + gC_per_m2 = (gC/m2).named("grams carbon per square meter", + symbol="gC/m²") + person_hours = (people * hours).named("person hours") person_months = (people * months).named("person months") + diff --git a/pycopancore/data_model/master_data_model/environment.py b/pycopancore/data_model/master_data_model/environment.py index eb33a8cc..9bae2ccb 100644 --- a/pycopancore/data_model/master_data_model/environment.py +++ b/pycopancore/data_model/master_data_model/environment.py @@ -2,25 +2,28 @@ """Master data model for environment.""" -from .. import Variable -from . import gigatonnes_carbon, kelvins, years, square_kilometers -from .. import unity +from pycopancore.data_model.variable import Variable +from pycopancore.data_model.master_data_model.dimensions_and_units import \ + DimensionsAndUnits as DAU +from pycopancore.data_model.unit import unity -from networkx import DiGraph, Graph +from networkx import Graph class Environment: # Geography: - land_area = Variable("land area", "", unit=square_kilometers, + land_area = Variable("land area", + "", + unit=DAU.square_kilometers, strict_lower_bound=0) # Atmosphere: atmospheric_carbon = Variable("atmospheric carbon stock", "(mass of C in any chemical compound)", - unit=gigatonnes_carbon, + unit=DAU.gigatonnes_carbon, is_extensive=True, lower_bound=0, default=0) # Note: this is NOT the same as the CF var. atmosphere_mass_of_carbon_dioxide @@ -29,7 +32,7 @@ class Environment: """(in the meaning used in climate policy debates, i.e., at 2m above surface, averaged over the day)""", AMIP="tas", # CF="air_temperature"? - unit=kelvins, + unit=DAU.kelvins, is_intensive=True, lower_bound=0, default=287) # TODO: higher layers as a vector by (geopotential) hight? @@ -38,7 +41,7 @@ class Environment: ocean_carbon = Variable("ocean carbon stock", "(mass of C in any chemical compound)", - unit=gigatonnes_carbon, + unit=DAU.gigatonnes_carbon, is_extensive=True, lower_bound=0, default=0) # Note: when using the following, include @@ -46,12 +49,12 @@ class Environment: upper_ocean_carbon = \ Variable("upper ocean carbon stock", "(that which interacts relatively much/fast with atmosphere)", - unit=gigatonnes_carbon, + unit=DAU.gigatonnes_carbon, is_extensive=True, lower_bound=0, default=0) deep_ocean_carbon = \ Variable("deep ocean carbon stock", "(that which interacts relatively little/slow with atmosphere)", - unit=gigatonnes_carbon, + unit=DAU.gigatonnes_carbon, is_extensive=True, lower_bound=0, default=0) # Note: there are no corresponding CF vars. yet @@ -61,19 +64,19 @@ class Environment: terrestrial_carbon = Variable("terrestrial carbon stock", "(mass of C in any chemical compound)", - unit=gigatonnes_carbon, + unit=DAU.gigatonnes_carbon, is_extensive=True, lower_bound=0, default=0) # Note: when using the following, include # Implicit(terrestrial_carbon == soil_carbon + biomass_carbon) soil_carbon = Variable("soil carbon stock", "(mass of C in any chemical compound)", - unit=gigatonnes_carbon, + unit=DAU.gigatonnes_carbon, is_extensive=True, lower_bound=0, default=0) # Note: has to do with CF var. soil_carbon_content biomass_carbon = Variable("biomass/plant carbon stock", "(mass of C in any chemical compound)", - unit=gigatonnes_carbon, + unit=DAU.gigatonnes_carbon, is_extensive=True, lower_bound=0, default=0) # Note: when using the following, include @@ -82,12 +85,12 @@ class Environment: Variable("harvestable biomass carbon stock", """(that which can be accessed easily for direct harvesting, in particular agricultural biomass)""", - unit=gigatonnes_carbon, + unit=DAU.gigatonnes_carbon, is_extensive=True, lower_bound=0, default=0) other_biomass_carbon = \ Variable("other (non-harvestable) biomass carbon stock", "(that which cannot be accessed easily for direct harvesting)", - unit=gigatonnes_carbon, + unit=DAU.gigatonnes_carbon, is_extensive=True, lower_bound=0, default=0) # Note: there are no corresponding CF vars. yet @@ -99,7 +102,7 @@ class Environment: """(mass of C in any chemical compound, potentially accessible for human extraction and combustion)""", - unit=gigatonnes_carbon, + unit=DAU.gigatonnes_carbon, is_extensive=True, lower_bound=0, default=0) # Note: when using the following, include @@ -107,19 +110,21 @@ class Environment: discovered_fossil_reserves = \ Variable("discovered fossil reserves carbon stock", """(that which can currently be accessed for extraction)""", - unit=gigatonnes_carbon, + unit=DAU.gigatonnes_carbon, is_extensive=True, lower_bound=0, default=0) undiscovered_fossil_reserves = \ Variable("undiscovered fossil reserves carbon stock", "(that which cannot currently be accessed for extraction)", - unit=gigatonnes_carbon, + unit=DAU.gigatonnes_carbon, is_extensive=True, lower_bound=0, default=0) # For ocean-atmosphere interactions: ocean_atmosphere_diffusion_coefficient = \ Variable("ocean-atmosphere diffusion coefficient", "", - unit=years**-1, lower_bound=0, default=0.016) + unit=DAU.years**-1, + lower_bound=0, + default=0.016) carbon_solubility_in_sea_water = \ Variable("carbon solubility in sea water", "(in the sense of Nitzbon et al. 2017, not in g/L but unitless!)", @@ -130,11 +135,11 @@ class Environment: photosynthesis_carbon_flow = \ Variable("photosynthesis carbon flow", "", ref="https://en.wikipedia.org/wiki/Photosynthesis", - unit = gigatonnes_carbon / years, + unit = DAU.gigatonnes_carbon / DAU.years, is_extensive=True, lower_bound=0, default=0) terrestrial_respiration_carbon_flow = \ Variable("plant and soil respiration carbon flow", "", - unit = gigatonnes_carbon / years, + unit = DAU.gigatonnes_carbon / DAU.years, is_extensive=True, lower_bound=0, default=0) # Note: when using the following, include @@ -143,12 +148,12 @@ class Environment: plant_respiration_carbon_flow = \ Variable("plant respiration carbon flow", "", ref="https://en.wikipedia.org/wiki/Cellular_respiration", - unit = gigatonnes_carbon / years, + unit = DAU.gigatonnes_carbon / DAU.years, is_extensive=True, lower_bound=0, default=0) soil_respiration_carbon_flow = \ Variable("soil respiration carbon flow", "", ref="https://en.wikipedia.org/wiki/Soil_respiration", - unit = gigatonnes_carbon / years, + unit = DAU.gigatonnes_carbon / DAU.years, is_extensive=True, lower_bound=0, default=0) # Note: there are no corresponding CF vars. yet diff --git a/pycopancore/data_model/master_data_model/group.py b/pycopancore/data_model/master_data_model/group.py index a114e4d9..1d8504da 100644 --- a/pycopancore/data_model/master_data_model/group.py +++ b/pycopancore/data_model/master_data_model/group.py @@ -1,6 +1,6 @@ """Master data model for group.""" -from .. import Variable +from pycopancore.data_model.variable import Variable from networkx import Graph diff --git a/pycopancore/data_model/master_data_model/metabolism.py b/pycopancore/data_model/master_data_model/metabolism.py index a13ca902..2f30812c 100644 --- a/pycopancore/data_model/master_data_model/metabolism.py +++ b/pycopancore/data_model/master_data_model/metabolism.py @@ -9,9 +9,10 @@ # Contact: core@pik-potsdam.de # License: BSD 2-clause license -from .. import Variable -from . import gigajoules, dollars, gigatonnes_carbon, years, utils, people, kelvins -from .. import unity +from pycopancore.data_model.variable import Variable +from pycopancore.data_model.master_data_model.dimensions_and_units import \ + DimensionsAndUnits as DAU +from pycopancore.data_model.unit import unity class Metabolism: @@ -21,7 +22,7 @@ class Metabolism: population = Variable("human population", "", IAMC="Population", CETS="SP.POP", - unit=people, + unit=DAU.people, is_extensive=True, lower_bound=0, default=0) # Note: when using the following, include @@ -30,70 +31,70 @@ class Metabolism: "(in years from 0 to 99+)", IAMC="Population", CETS="SP.POP", - unit=people, + unit=DAU.people, is_extensive=True, lower_bound=0, array_shape=(100,)) # 1d-array migrant_population = Variable("first-generation migrant population", "", - unit=people, + unit=DAU.people, is_extensive=True, lower_bound=0, default=0) fertility = Variable("current human fertility rate", "", - unit=years**-1, + unit=DAU.years**-1, lower_bound=0, is_intensive=True, default=0.02) min_fertility = Variable("minimum human fertility rate", "", - unit=years**-1, + unit=DAU.years**-1, lower_bound=0, is_intensive=True, default=0.008) max_fertility = Variable("maximum human fertility rate", "", - unit=years**-1, + unit=DAU.years**-1, lower_bound=0, is_intensive=True, default=0.05) mortality = Variable("current human mortility rate", "", - unit=years**-1, + unit=DAU.years**-1, lower_bound=0, is_intensive=True, default=0.01) mortality_temperature_sensitivity = \ Variable("mortality temperature sensitivity", "", - unit = years**-1 / kelvins, + unit=DAU.years**-1 / DAU.kelvins, lower_bound=0, is_intensive=True, - default = 5e-5/years / kelvins + default=5e-5/DAU.years / DAU.kelvins ) mortality_reference_temperature = \ Variable("reference temperature for relationship with mortality", "default: pre-industrial value", - unit=kelvins, lower_bound=0, + unit=DAU.kelvins, lower_bound=0, default=287) # TODO: verify! births = Variable("births per time", "", - unit = people / years, + unit=DAU.people / DAU.years, lower_bound=0, is_extensive=True, default=0) deaths = Variable("deaths per time", "", - unit = people / years, + unit=DAU.people / DAU.years, lower_bound=0, is_extensive=True, default=0) - + immigration = Variable("immigrants per time", "", - unit = people / years, + unit=DAU.people / DAU.years, lower_bound=0, is_extensive=True, default=0) emigration = Variable("emigrants per time", "", - unit = people / years, + unit=DAU.people / DAU.years, lower_bound=0, is_extensive=True, default=0) - - + + # Resource extraction and waste: - + biomass_harvest_flow = Variable("biomass harvest flow", "", - unit = gigatonnes_carbon / years, # leave whitespace as it is, for g*ds sake!!!! + unit=DAU.gigatonnes_carbon / DAU.years, # leave whitespace as it is, for g*ds sake!!!! lower_bound=0, is_extensive=True, default=0) - + fossil_extraction_flow = Variable("fossil extraction flow", "", - unit = gigatonnes_carbon / years, + unit=DAU.gigatonnes_carbon / DAU.years, lower_bound=0, is_extensive=True, default=0) carbon_emission_flow = Variable("carbon emission flow", "", - unit = gigatonnes_carbon / years, + unit=DAU.gigatonnes_carbon / DAU.years, IAMC="Emissions|CO2", lower_bound=0, is_extensive=True, default=0) @@ -107,14 +108,14 @@ class Metabolism: # stocks: physical_capital = \ - Variable("physical capital", "(in value units)", unit=dollars, + Variable("physical capital", "(in value units)", unit=DAU.dollars, lower_bound=0, is_extensive=True, default=0) renewable_energy_knowledge = \ Variable("renewable energy production knowledge stock", "= non-depreciated cumulative energy produced in the past. " "Interpreted as in Wright's law", - unit=gigajoules, + unit=DAU.gigajoules, lower_bound=0, is_extensive=True, default=0) # flows: @@ -124,52 +125,52 @@ class Metabolism: Variable("biomass input flow", "(in carbon units)", IAMC="Primary Energy|Biomass", - unit = gigatonnes_carbon / years, + unit=DAU.gigatonnes_carbon / DAU.years, lower_bound=0, is_extensive=True, default=0) fossil_fuel_input_flow = \ Variable("fossil fuels input flow", "(in carbon units)", IAMC="Primary Energy|Fossil", - unit = gigatonnes_carbon / years, + unit=DAU.gigatonnes_carbon / DAU.years, lower_bound=0, is_extensive=True, default=0) renewable_energy_input_flow = \ Variable("non-biomass renewable energy input flow", "", IAMC="Primary Energy|Non-Biomass Renewables", - unit = gigajoules / years, + unit=DAU.gigajoules / DAU.years, lower_bound=0, is_extensive=True, default=0) secondary_energy_flow = \ Variable("secondary energy flow", "(all sources)", IAMC="Secondary Energy", - unit = gigajoules / years, + unit=DAU.gigajoules / DAU.years, lower_bound=0, is_extensive=True, default=0) total_energy_intensity = \ Variable("total energy intensity", "", - unit = gigajoules / dollars, - lower_bound=0, is_intensive=True, default = 1/147) + unit=DAU.gigajoules / DAU.dollars, + lower_bound=0, is_intensive=True, default=1/147) economic_output_flow = \ Variable("total economic output flow", "(in value units)", IAMC="GDP|PPP", # or GDP|MER? - unit = dollars / years, + unit=DAU.dollars / DAU.years, lower_bound=0, is_extensive=True, default=0) consumption_flow = \ Variable("consumption flow", """(in value units)""", IAMC="Consumption", - unit = dollars / years, + unit=DAU.dollars / DAU.years, lower_bound=0, is_extensive=True, default=0) investment_flow = \ Variable("flow of total investment into physical capital", "", # IAMC="Investment", - unit = dollars / years, + unit=DAU.dollars / DAU.years, lower_bound=0, is_extensive=True, default=0) # per-capita quantities: @@ -178,25 +179,25 @@ class Metabolism: Variable("cardinal social welfare flow 'per capita'", "Note that 'per capita' here does not imply that the value is " "an average, but only that it is an intensive quantity", - unit = utils / people / years, + unit=DAU.utils / DAU.people / DAU.years, is_intensive=True, default=0) wellbeing = \ Variable("well-being", "(in utility flow units)", - unit = utils / people / years, + unit=DAU.utils / DAU.people / DAU.years, is_intensive=True, default=0) # productivities, efficiencies etc. - biomass_energy_density = Variable("biomass energy density", + biomass_energy_density = Variable("biomass energy density", "(default from Nitzbon 2016)", - unit = gigajoules / gigatonnes_carbon, + unit=DAU.gigajoules / DAU.gigatonnes_carbon, lower_bound=0, is_intensive=True, default=40e9) - fossil_energy_density = Variable("fossil energy density", + fossil_energy_density = Variable("fossil energy density", "(default from Nitzbon 2016)", - unit = gigajoules / gigatonnes_carbon, + unit=DAU.gigajoules / DAU.gigatonnes_carbon, lower_bound=0, is_intensive=True, default=47e9) @@ -207,13 +208,13 @@ class Metabolism: Variable("protected stock of terrestrial carbon", """what stock of the current terrestrial carbon will be treated as protected and thus not harvested at each point in time""", - unit=gigatonnes_carbon, lower_bound=0, + unit=DAU.gigatonnes_carbon, lower_bound=0, default=0) # may be increased by cultural components protected_fossil_carbon = \ Variable("protected stock of fossil carbon", """what stock of the current fossil carbon will be treated as protected and thus not extracted at each point in time""", - unit=gigatonnes_carbon, lower_bound=0, + unit=DAU.gigatonnes_carbon, lower_bound=0, default=0) # may be increased by cultural components protected_terrestrial_carbon_share = \ Variable("protected share of terrestrial carbon", @@ -233,19 +234,19 @@ class Metabolism: physical_capital_depreciation_rate = \ Variable("physical capital depreciation rate", "", - unit = years**-1, + unit=DAU.years**-1, lower_bound=0, is_intensive=True, default=0.1) basic_physical_capital_depreciation_rate = \ Variable("basic physical capital depreciation rate", "", - unit = years**-1, + unit=DAU.years**-1, lower_bound=0, is_intensive=True, default=0.1) physical_capital_depreciation_rate_temperature_sensitivity = \ Variable("physical capital depreciation rate temperature sensitivity", "", - unit = years**-1 / kelvins, + unit=DAU.years**-1 / DAU.kelvins, lower_bound=0, is_intensive=True, - default = 0.05/years / kelvins + default=0.05/DAU.years / DAU.kelvins # the following gives much too large sensitivity: # (40e9 * dollars / years) / (6e13 * dollars) # / ((1.5*kelvins) / (1000*gigatonnes_carbon)) @@ -253,12 +254,12 @@ class Metabolism: physical_capital_depreciation_rate_reference_temperature = \ Variable("reference temperature for relationship with capital depreciation", "default: pre-industrial value", - unit=kelvins, lower_bound=0, + unit=DAU.kelvins, lower_bound=0, default=287) # TODO: verify! renewable_energy_knowledge_depreciation_rate = \ Variable("renewable energy production knowledge depreciation rate", "", - unit = years**-1, + unit=DAU.years**-1, lower_bound=0, is_intensive=True, default=0.02) diff --git a/pycopancore/data_model/master_data_model/social_system.py b/pycopancore/data_model/master_data_model/social_system.py index fe638196..24c82292 100644 --- a/pycopancore/data_model/master_data_model/social_system.py +++ b/pycopancore/data_model/master_data_model/social_system.py @@ -1,8 +1,10 @@ """Master data model for social_system.""" -from . import MET -from .. import Variable -from . import dollars, gigatonnes_carbon, gigajoules +from pycopancore.data_model.master_data_model.metabolism \ + import Metabolism as MET +from pycopancore.data_model.variable import Variable +from pycopancore.data_model.master_data_model.dimensions_and_units import \ + DimensionsAndUnits as DAU class SocialSystem: @@ -84,10 +86,10 @@ class SocialSystem: emissions_tax_level = \ Variable("emissions tax level", "level of emissions tax when introduced", - unit = dollars / gigatonnes_carbon, + unit=DAU.dollars / DAU.gigatonnes_carbon, lower_bound=0, default=100e9*3.5) renewable_subsidy_level = \ Variable("renewable subsidy level", "level of renewable subsidy when introduced", - unit = dollars / gigajoules, - lower_bound=0, default=50) # FIXME: check plausibility! + unit=DAU.dollars / DAU.gigajoules, + lower_bound=0, default=50) # FIXME: check plausibility! diff --git a/pycopancore/data_model/master_data_model/world.py b/pycopancore/data_model/master_data_model/world.py index 9fe60a2b..d2904e53 100644 --- a/pycopancore/data_model/master_data_model/world.py +++ b/pycopancore/data_model/master_data_model/world.py @@ -9,27 +9,31 @@ # Contact: core@pik-potsdam.de # License: BSD 2-clause license -from . import ENV, MET -from . import gigatonnes_carbon as GtC -from . import square_kilometers as km2 +from pycopancore.data_model.master_data_model.environment \ + import Environment as ENV +from pycopancore.data_model.master_data_model.metabolism \ + import Metabolism as MET + +from pycopancore.data_model.master_data_model.dimensions_and_units \ + import DimensionsAndUnits as DAU class World: # natural: - land_area = ENV.land_area.copy(default=1.5e8*km2) - atmospheric_carbon = ENV.atmospheric_carbon.copy(default=589*GtC) + land_area = ENV.land_area.copy(default=1.5e8*DAU.km2) + atmospheric_carbon = ENV.atmospheric_carbon.copy(default=589*DAU.GtC) surface_air_temperature = ENV.surface_air_temperature.copy() - ocean_carbon = ENV.ocean_carbon.copy(default=38000*GtC) - upper_ocean_carbon = ENV.upper_ocean_carbon.copy(default=900*GtC) - deep_ocean_carbon = ENV.deep_ocean_carbon.copy(default=37100*GtC) - terrestrial_carbon = ENV.terrestrial_carbon.copy(default=2550*GtC) - soil_carbon = ENV.soil_carbon.copy(default=2000*GtC) - biomass_carbon = ENV.biomass_carbon.copy(default=550*GtC) + ocean_carbon = ENV.ocean_carbon.copy(default=38000*DAU.GtC) + upper_ocean_carbon = ENV.upper_ocean_carbon.copy(default=900*DAU.GtC) + deep_ocean_carbon = ENV.deep_ocean_carbon.copy(default=37100*DAU.GtC) + terrestrial_carbon = ENV.terrestrial_carbon.copy(default=2550*DAU.GtC) + soil_carbon = ENV.soil_carbon.copy(default=2000*DAU.GtC) + biomass_carbon = ENV.biomass_carbon.copy(default=550*DAU.GtC) harvestable_biomass_carbon = ENV.harvestable_biomass_carbon.copy() other_biomass_carbon = ENV.other_biomass_carbon.copy() - fossil_carbon = ENV.fossil_carbon.copy(default=1500*GtC) + fossil_carbon = ENV.fossil_carbon.copy(default=1500*DAU.GtC) discovered_fossil_reserves = ENV.discovered_fossil_reserves.copy() undiscovered_fossil_reserves = ENV.undiscovered_fossil_reserves.copy() diff --git a/pycopancore/data_model/ordered_set.py b/pycopancore/data_model/ordered_set.py index 49eddc0d..e47b99e2 100644 --- a/pycopancore/data_model/ordered_set.py +++ b/pycopancore/data_model/ordered_set.py @@ -12,11 +12,14 @@ # python recipe at https://code.activestate.com/recipes/576694/ # plus __add__, __iadd__ -import collections +try: + from collections import MutableSet +except: + from collections.abc import MutableSet # TODO: docstrings -class OrderedSet(collections.MutableSet): +class OrderedSet(MutableSet): """Ordered Set.""" def __init__(self, iterable=None): diff --git a/pycopancore/data_model/reference_variable.py b/pycopancore/data_model/reference_variable.py index 21471444..312dd504 100644 --- a/pycopancore/data_model/reference_variable.py +++ b/pycopancore/data_model/reference_variable.py @@ -9,8 +9,8 @@ # Contact: core@pik-potsdam.de # License: BSD 2-clause license -from . import Variable -from ..private import _DotConstruct +from pycopancore.data_model.variable import Variable +from pycopancore.private._expressions import _DotConstruct # TODO: complete logics, set other Variable attributes, validate etc. diff --git a/pycopancore/data_model/set_variable.py b/pycopancore/data_model/set_variable.py index ec9358b2..7e31e285 100644 --- a/pycopancore/data_model/set_variable.py +++ b/pycopancore/data_model/set_variable.py @@ -9,8 +9,9 @@ # Contact: core@pik-potsdam.de # License: BSD 2-clause license -from . import Variable -from ..private import _DotConstruct, unknown +from pycopancore.data_model.variable import Variable +from pycopancore.private._expressions import _DotConstruct +from pycopancore.private._simple_expressions import unknown # TODO: complete logics, set other Variable attributes, validate etc. diff --git a/pycopancore/data_model/unit.py b/pycopancore/data_model/unit.py index b83bc14c..4cc04052 100644 --- a/pycopancore/data_model/unit.py +++ b/pycopancore/data_model/unit.py @@ -13,7 +13,8 @@ import operator from numpy import log10 -from . import dimension, dimensional_quantity, nondim +from pycopancore.data_model.dimension import nondim +from pycopancore.data_model import dimensional_quantity class Unit (object): @@ -49,7 +50,7 @@ def dimension(self): return reduce(operator.mul, [unit.dimension**ex for unit, ex in self.exponents.items()], - dimension.nondim) + nondim) def __init__(self, name="", @@ -112,7 +113,7 @@ def __init__(self, assert dimension is None, \ "dimension of non-base unit is derived automatically" - def named(self, name, desc=None, *, symbol=None): + def named(self, name, *, desc=None, symbol=None): return Unit(is_base=self.is_base, name=name, symbol=self.symbol if symbol is None else symbol, desc=self.desc if desc is None else desc, diff --git a/pycopancore/data_model/variable.py b/pycopancore/data_model/variable.py index 0ec83a9a..a548e2aa 100644 --- a/pycopancore/data_model/variable.py +++ b/pycopancore/data_model/variable.py @@ -16,8 +16,9 @@ import random from sympy import Symbol -from . import DimensionalQuantity, Unit -from .. import private +from pycopancore.data_model.dimensional_quantity import DimensionalQuantity +from pycopancore.data_model.unit import Unit +from pycopancore.private._simple_expressions import unset, unknown EPS = 1e-10 @@ -44,7 +45,7 @@ class Variable(Symbol): readonly = None """whether variable is read-only, e.g. holding redundant information""" - default = private.unset # can't use None since None is a possible default value + default = unset # can't use None since None is a possible default value """default initial value""" uninformed_prior = None """random value generator (probability distribution) @@ -141,7 +142,7 @@ def __init__(self, ref=None, scale="ratio", readonly=False, - default=private.unset, + default=unset, uninformed_prior=None, CF=None, AMIP=None, @@ -204,10 +205,10 @@ def __init__(self, self.levels = levels if readonly: - assert default is private.unset + assert default is unset assert uninformed_prior is None self.allow_none = True - self.default = private.unknown + self.default = unknown else: self.allow_none = allow_none self.default = default @@ -247,7 +248,7 @@ def default(self): @default.setter def default(self, value): - if value is not private.unset: + if value is not unset: self.assert_valid(value) self._default = value @@ -312,7 +313,7 @@ def __repr__(self): r += ", shape=" + str(self.array_shape) # FIXME: the following was commented out as a dirty fix of the AttributeError # in run_example1.py: -# if self.default is not private.unset: +# if self.default is not unset: # r += ", default=" + str(self.default) return r # + " (uid=" + str(self._uid) + ")" @@ -321,7 +322,7 @@ def __repr__(self): def _check_valid(self, v): """check validity of candidate value""" - assert v is not private.unset, str(self) + " has no value set" + assert v is not unset, str(self) + " has no value set" if self.array_shape is not None: if not v.shape == self.array_shape: @@ -430,6 +431,10 @@ def convert_to_standard_units( self.set_value(i, v) # does the conversion def _get_instances(self, instances): + from pycopancore.private._abstract_entity_mixin import \ + _AbstractEntityMixin + from pycopancore.private._abstract_process_taxon_mixin import \ + _AbstractProcessTaxonMixin """converts argument into a set of instances (entities or process taxa)""" if instances is None: # use all that have this variable @@ -440,8 +445,8 @@ def _get_instances(self, instances): instances.update(self._get_instances(k)) instances.update(self._get_instances(i)) elif isinstance(instances, - (private._AbstractEntityMixin, - private._AbstractProcessTaxonMixin)): + (_AbstractEntityMixin, + _AbstractProcessTaxonMixin)): instances = set([instances]) else: instances = set(instances) @@ -451,7 +456,7 @@ def set_to_default( self, instances=None): # if None: all entities/taxa """Set values in selected entities to default if a default was given""" - if self.default is private.unset: + if self.default is unset: return instances = self._get_instances(instances) if instances: # Maybe variables owning class has no instances! diff --git a/pycopancore/model_components/abstract/cell.py b/pycopancore/model_components/abstract/cell.py index 298000cc..cab731f0 100644 --- a/pycopancore/model_components/abstract/cell.py +++ b/pycopancore/model_components/abstract/cell.py @@ -9,8 +9,8 @@ # Contact: core@pik-potsdam.de # License: BSD 2-clause license -from ...private import _AbstractEntityMixin -from ...data_model import OrderedSet +from pycopancore.private._abstract_entity_mixin import _AbstractEntityMixin +from pycopancore.data_model.ordered_set import OrderedSet class Cell (_AbstractEntityMixin): diff --git a/pycopancore/model_components/abstract/culture.py b/pycopancore/model_components/abstract/culture.py index ee88c3b5..8ae28d78 100644 --- a/pycopancore/model_components/abstract/culture.py +++ b/pycopancore/model_components/abstract/culture.py @@ -8,9 +8,9 @@ # URL: # Contact: core@pik-potsdam.de # License: BSD 2-clause license - -from ...private import _AbstractProcessTaxonMixin -from ...data_model import OrderedSet +from pycopancore.private._abstract_process_taxon_mixin import \ + _AbstractProcessTaxonMixin +from pycopancore.data_model.ordered_set import OrderedSet class Culture (_AbstractProcessTaxonMixin): diff --git a/pycopancore/model_components/abstract/environment.py b/pycopancore/model_components/abstract/environment.py index d7af1c38..39a12861 100644 --- a/pycopancore/model_components/abstract/environment.py +++ b/pycopancore/model_components/abstract/environment.py @@ -8,8 +8,9 @@ # URL: # License: MIT license -from ...private import _AbstractProcessTaxonMixin -from ...data_model import OrderedSet +from pycopancore.private._abstract_process_taxon_mixin import \ + _AbstractProcessTaxonMixin +from pycopancore.data_model.ordered_set import OrderedSet class Environment (_AbstractProcessTaxonMixin): diff --git a/pycopancore/model_components/abstract/group.py b/pycopancore/model_components/abstract/group.py index f919b38e..ad14d30d 100644 --- a/pycopancore/model_components/abstract/group.py +++ b/pycopancore/model_components/abstract/group.py @@ -9,8 +9,8 @@ # Contact: core@pik-potsdam.de # License: BSD 2-clause license -from ...private import _AbstractEntityMixin -from ...data_model import OrderedSet +from pycopancore.private._abstract_entity_mixin import _AbstractEntityMixin +from pycopancore.data_model.ordered_set import OrderedSet class Group (_AbstractEntityMixin): diff --git a/pycopancore/model_components/abstract/individual.py b/pycopancore/model_components/abstract/individual.py index 8b8e8a8a..c538c2af 100644 --- a/pycopancore/model_components/abstract/individual.py +++ b/pycopancore/model_components/abstract/individual.py @@ -9,8 +9,8 @@ # Contact: core@pik-potsdam.de # License: BSD 2-clause license -from ...private import _AbstractEntityMixin -from ...data_model import OrderedSet +from pycopancore.private._abstract_entity_mixin import _AbstractEntityMixin +from pycopancore.data_model.ordered_set import OrderedSet class Individual (_AbstractEntityMixin): diff --git a/pycopancore/model_components/abstract/metabolism.py b/pycopancore/model_components/abstract/metabolism.py index d158464e..4f30a9ac 100644 --- a/pycopancore/model_components/abstract/metabolism.py +++ b/pycopancore/model_components/abstract/metabolism.py @@ -12,8 +12,9 @@ # Contact: core@pik-potsdam.de # License: BSD 2-clause license -from ...private import _AbstractProcessTaxonMixin -from ...data_model import OrderedSet +from pycopancore.private._abstract_process_taxon_mixin import \ + _AbstractProcessTaxonMixin +from pycopancore.data_model.ordered_set import OrderedSet class Metabolism (_AbstractProcessTaxonMixin): diff --git a/pycopancore/model_components/abstract/social_system.py b/pycopancore/model_components/abstract/social_system.py index 7540d1d5..ecc8d752 100644 --- a/pycopancore/model_components/abstract/social_system.py +++ b/pycopancore/model_components/abstract/social_system.py @@ -8,8 +8,8 @@ # URL: # License: MIT license -from ...private import _AbstractEntityMixin -from ...data_model import OrderedSet +from pycopancore.private._abstract_entity_mixin import _AbstractEntityMixin +from pycopancore.data_model.ordered_set import OrderedSet class SocialSystem (_AbstractEntityMixin): diff --git a/pycopancore/model_components/abstract/world.py b/pycopancore/model_components/abstract/world.py index 051c1143..4f1ef8a2 100644 --- a/pycopancore/model_components/abstract/world.py +++ b/pycopancore/model_components/abstract/world.py @@ -9,8 +9,8 @@ # Contact: core@pik-potsdam.de # License: BSD 2-clause license -from ...private import _AbstractEntityMixin -from ...data_model import OrderedSet +from pycopancore.private._abstract_entity_mixin import _AbstractEntityMixin +from pycopancore.data_model.ordered_set import OrderedSet class World (_AbstractEntityMixin): diff --git a/pycopancore/model_components/adaptive_voter_opinion_formation/__init__.py b/pycopancore/model_components/adaptive_voter_opinion_formation/__init__.py deleted file mode 100644 index 6852092c..00000000 --- a/pycopancore/model_components/adaptive_voter_opinion_formation/__init__.py +++ /dev/null @@ -1,26 +0,0 @@ -""" -Model component package template. - -TODO: -Copy this folder, rename it to the name of your model component, -then adjust or fill in code and documentation in all modules wherever marked by "TODO:", -finally remove these instructions. -See the model component development tutorial for details. -""" - -# This file is part of pycopancore. -# -# Copyright (C) 2016-2017 by COPAN team at Potsdam Institute for Climate -# Impact Research -# -# URL: -# Contact: core@pik-potsdam.de -# License: BSD 2-clause license - -from . import interface - -# export all implementation classes: -from .implementation import * - -# export model component mixin class: -from .model import Model diff --git a/pycopancore/model_components/adaptive_voter_opinion_formation/implementation/__init__.py b/pycopancore/model_components/adaptive_voter_opinion_formation/implementation/__init__.py deleted file mode 100644 index 30d00d4d..00000000 --- a/pycopancore/model_components/adaptive_voter_opinion_formation/implementation/__init__.py +++ /dev/null @@ -1,20 +0,0 @@ -""" -Model component implementation subpackage template. -""" - -# This file is part of pycopancore. -# -# Copyright (C) 2016-2017 by COPAN team at Potsdam Institute for Climate -# Impact Research -# -# URL: -# Contact: core@pik-potsdam.de -# License: BSD 2-clause license - -# TODO: adjust the following lists to your needs: - -# export all provided entity type implementation mixin classes: -from .individual import Individual - -# export all provided process taxon implementation mixin classes: -from .culture import Culture diff --git a/pycopancore/model_components/adaptive_voter_opinion_formation/implementation/culture.py b/pycopancore/model_components/adaptive_voter_opinion_formation/implementation/culture.py deleted file mode 100644 index 6e02a436..00000000 --- a/pycopancore/model_components/adaptive_voter_opinion_formation/implementation/culture.py +++ /dev/null @@ -1,298 +0,0 @@ -"""Culture process taxon mixing class template. - -TODO: adjust or fill in code and documentation wherever marked by "TODO:", -then remove these instructions -""" - -# This file is part of pycopancore. -# -# Copyright (C) 2016-2017 by COPAN team at Potsdam Institute for Climate -# Impact Research -# -# URL: -# Contact: core@pik-potsdam.de -# License: BSD 2-clause license - -from .. import interface as I -#from .... import master_data_model as D -from .... import Step - -from ....runners import Hooks - -from blist import sortedlist # more performant for large list modifications -import datetime as dt -from enum import Enum, unique -import random -from time import time - - -class Culture (I.Culture): - """Culture process taxon mixin implementation class.""" - - # standard methods: - - __nodes_by_opinion = None - __nodes = None - - def __filter_by_opinion(opinion, input_list): return list( - filter(lambda ind: ind.opinion == opinion, input_list)) - - def __remove_by_opinion(opinion, input_list): return list( - filter(lambda ind: ind.opinion != opinion, input_list)) - - __update_function = None - - __configuration = dict( # keeps the configuration status, whether the updates are done basic or fast, and clusteredd or non-clustered - configured=False, - process_type=None, - update_mode=None, - synchronous_updates=None - ) - """configuration status""" - @unique - class update_modes(Enum): - """update modes for the adaptive voter model: basic or fast""" - basic = 0 - fast = 1 - - def __init__(self, - *, - rewiring, - opinion_change=1.0, - timestep=0.1, - possible_opinions={0, 1}, - active_neighbor_only=True, - **kwargs): - """Initialize the unique instance of Culture. - - Parameters - ---------- - rewiring : float or function - if float: probability of rewiring - if function: decide whether the link between the two individuals is separated and a link to a new individual is created - takes: active_individual, active_individuals_neighbor - - opinion_change: float or function, optional, default: 1 - if float: probability of opinion adaption if there was no rewiring - if function: decide whether the opinion of the neighbor should be adopted - takes: active_individual, active_individuals_neighbor - - timestep : float, optional, default: 0.1 - interval between opinion updates - - possible_opinions : set-like, optional, default: {0, 1} - set of possible options the individuals can take - - active_neighbor_only : bool, optional, default: True - if False: any neighbor of the active individual is chosen randomly - if True: only neighbors with different opinions are chosen randomly (if there is at least one, else nothing is done) - """ - super().__init__(**kwargs) - - # TODO: ask Jobst, whether this should get the network as input so it - # could be applied to different networks... seems sensible too me but - # might contradict the frameworks idea - - _rewiring = rewiring - if not callable(rewiring): - if rewiring == 1: - def _rewiring(x, y): return True - else: - assert 0 < rewiring < 1, "rewiring_probability should be a float between 0 and 1 or a function" - - def _rewiring(x, y): return random.random() < rewiring - self.rewiring = _rewiring - - if not callable(opinion_change): - if opinion_change == 1: - def opinion_change(x, y): return True - else: - _opinion_change = opinion_change - - def opinion_change( - x, y): return random.random() < _opinion_change - self.opinion_change = opinion_change - - self.possible_opinions = possible_opinions - self.active_neighbor_only = active_neighbor_only - - self.next_update_time = 0 - self.timestep = timestep - - # process-related methods: - - def analyze_graph(self, t): - """analyze the graph so speed-ups can be used later""" - # TODO: test whether sortedlist or sets are faster for large numbers of - # entries - assert t == 0, "This function should be run as a pre-hook of the runner!" - print(" analyzing the graph ... ", end="", flush=True) - start = time() - - self.__nodes = sortedlist(self.acquaintance_network.nodes()) # FIXME: why do you assume entities allow sorting? - self.__nodes_by_opinion = {opinion: sortedlist() - for opinion in self.possible_opinions} - for node in self.acquaintance_network: - self.__nodes_by_opinion[node.opinion].add(node) - - print("done ({})".format(dt.timedelta(seconds=(time() - start)))) - - def clear_graph_analysis(self, t): - """clear everything that was created during analyze_graph""" - print(" deleting lists from graph analysis") - del self.__nodes - del self.__nodes_by_opinion - - def opinion_update_basic(self, t): - """update the aquaintance network following the adaptive voter model prescription by (Holme, Newman - 2006)""" - # this code is currently only precisely following the model prescription - # without any additional speed-ups - - nodes = list(self.acquaintance_network.nodes()) - - active_individual = random.choice(nodes) - neighbors = self.acquaintance_network.neighbors(active_individual) - if self.active_neighbor_only: - active_neighbors = Culture.__remove_by_opinion( - active_individual.opinion, neighbors) - if not active_neighbors: - return # nothing to be done - active_neighbor = random.choice(active_neighbors) - else: - active_neighbor = random.choice(neighbors) - - # decide whether to rewire or to adopt the opinion - if self.rewiring(active_individual, active_neighbor): - # rewire - possible_new_neighbors = Culture.__filter_by_opinion( - active_individual.opinion, nodes) - if not possible_new_neighbors: - return # can't find a new one, active_individual is the last one - new_neighbor = random.choice(possible_new_neighbors) - # new_neighbor = random.choice(list(filter(lambda x: x.opinion == active_individual.opinion, self.acquaintance_network.nodes()))) - self.acquaintance_network.remove_edge( - active_individual, active_neighbor) - self.acquaintance_network.add_edge(active_individual, new_neighbor) - elif self.opinion_change(active_individual, active_neighbor): - # adopt opinion - active_individual.opinion = active_neighbor.opinion - - def opinion_update_fast(self, t): - """update the aquaintance network following the adaptive voter model prescription by (Holme, Newman - 2006)""" - # TODO: there are some intuitive speed-ups: - # 1) (done) use a list with references to nodes of the differing opinions so the statement with filter can be avoided - # 2) cluster the updates instead of making every update separately - # ... this should probably be done as a separate function calling one of the opinion_update_basic/fast functions - # ... make sure that the rest of the model works on longer time scales if you do that - # ... introduce a time scale for that - - # choose only between the active nodes, which are the keys of this - # sortedset - active_individual = random.choice(self.__nodes) - neighbors = self.acquaintance_network.neighbors(active_individual) - if self.active_neighbor_only: - active_neighbors = Culture.__remove_by_opinion( - active_individual.opinion, neighbors) - if not active_neighbors: - return # nothing to be done - active_neighbor = random.choice(active_neighbors) - else: - active_neighbor = random.choice(neighbors) - - # decide whether to rewire or to adopt the opinion - if self.rewiring(active_individual, active_neighbor): - # rewire - - # find new neighbor with same opinion - if not self.__nodes_by_opinion[active_individual.opinion]: - return # active_individual is the last one with this opinion and cannot connect to a new one - new_neighbor = random.choice( - self.__nodes_by_opinion[active_individual.opinion]) - # remove old link - self.acquaintance_network.remove_edge( - active_individual, active_neighbor) - # add new link - self.acquaintance_network.add_edge(active_individual, new_neighbor) - elif self.opinion_change(active_individual, active_neighbor): - # adopt opinion - - # move the active individual to the new opinion list - self.__nodes_by_opinion[active_individual.opinion].remove( - active_individual) - self.__nodes_by_opinion[active_neighbor.opinion].add( - active_individual) - # set the new opinion - # TODO: ask Jobst, whether this is okai within his framework! - active_individual.opinion = active_neighbor.opinion - - # test, update opinion for n individuals at the same time - def opinion_update_multiple(self, t): - for i in range(self.multiple_updates): - self.__update_function(t) - - def next_update_time(self, t): - self.next_update_time += self.timestep - return self.next_update_time - - @classmethod - def configure(cls, *, update_mode, synchronous_updates=1): - """configure the adaptive voter opinion formation model component - - Parameters - ---------- - - update_mode : element of Enum Cultur.update_modes - chooses between the basic and the fast update mode. The fast update mode is preferred but needs the nodes of the acquaintance_network to stay the same - - synchronous_updates : (optional) positive int - how many opinion updates should be done at once - """ - - synchronous_updates = int(synchronous_updates) - assert synchronous_updates >= 1, "can't do a non-positive number of synchronous updates" - - assert update_mode in Culture.update_modes, "choose an update mode from Culture.update_modes Enum" - - cls.multiple_updates = synchronous_updates - - process_type = Step - process_name = "opinion update" - process_variables = [ - I.Culture.acquaintance_network, I.Individual.opinion] - process_time = cls.next_update_time - process_func = cls.opinion_update_multiple - - # unregister everything - Hooks.unregister_hook(Hooks.Types.pre, cls.analyze_graph, - I.Culture, error_if_not_registered=False) - Hooks.unregister_hook(Hooks.Types.post, cls.clear_graph_analysis, - I.Culture, error_if_not_registered=False) - - if update_mode is Culture.update_modes.basic: - cls.__update_function = cls.opinion_update_basic - elif update_mode is Culture.update_modes.fast: - cls.__update_function = cls.opinion_update_fast - # register necessary hooks - Hooks.register_hook(Hooks.Types.pre, cls.analyze_graph, I.Culture) - Hooks.register_hook( - Hooks.Types.post, cls.clear_graph_analysis, I.Culture) - else: - raise ValueError("unknown update_mode '{}'".format(update_mode)) - - # set the configuration dictionary - cls.__configuration["configured"] = True - cls.__configuration["process_type"] = process_type - cls.__configuration["update_mode"] = update_mode - cls.__configuration["synchronous_updates"] = synchronous_updates - - cls.processes = [ - process_type( - process_name, - process_variables, - [process_time, process_func] - ) - ] - - -# set the default configuration of the model component -Culture.configure(update_mode=Culture.update_modes.fast) diff --git a/pycopancore/model_components/adaptive_voter_opinion_formation/implementation/individual.py b/pycopancore/model_components/adaptive_voter_opinion_formation/implementation/individual.py deleted file mode 100644 index 3e0b0123..00000000 --- a/pycopancore/model_components/adaptive_voter_opinion_formation/implementation/individual.py +++ /dev/null @@ -1,56 +0,0 @@ -"""Individual entity type class template. - -TODO: adjust or fill in code and documentation wherever marked by "TODO:", -then remove these instructions -""" - -# This file is part of pycopancore. -# -# Copyright (C) 2016-2017 by COPAN team at Potsdam Institute for Climate -# Impact Research -# -# URL: -# Contact: core@pik-potsdam.de -# License: BSD 2-clause license - -from .. import interface as I -#from .... import master_data_model as D - -import random - - -class Individual (I.Individual): - """Individual entity type mixin implementation class.""" - - # standard methods: - - def __init__(self, - *, - initial_opinion, - **kwargs): - """Initialize an instance of Individual.""" - super().__init__(**kwargs) # must be the first line - self.opinion = initial_opinion - pass - - def __lt__(self, other): - """make objects sortable, so big sorted lists can be used for quick look-ups""" - return self._uid < other._uid - - def deactivate(self): - """Deactivate an individual.""" - # TODO: add custom code here: - pass - super().deactivate() # must be the last line - - def reactivate(self): - """Reactivate an individual.""" - super().reactivate() # must be the first line - # TODO: add custom code here: - pass - - # process-related methods: - - # TODO: add some if needed... - - processes = [] # TODO: instantiate and list process objects here diff --git a/pycopancore/model_components/adaptive_voter_opinion_formation/interface.py b/pycopancore/model_components/adaptive_voter_opinion_formation/interface.py deleted file mode 100644 index 8a15754a..00000000 --- a/pycopancore/model_components/adaptive_voter_opinion_formation/interface.py +++ /dev/null @@ -1,82 +0,0 @@ -"""model component Interface template. - -TODO: adjust or fill in code and documentation wherever marked by "TODO:", then -remove these instructions. -""" - -# This file is part of pycopancore. -# -# Copyright (C) 2016-2017 by COPAN team at Potsdam Institute for Climate -# Impact Research -# -# URL: -# Contact: core@pik-potsdam.de -# License: BSD 2-clause license - -# TODO: use variables from the master data model wherever possible: -from ... import master_data_model as D -# TODO: uncomment and adjust of you need further variables from another -# model component: -# import ..BBB.interface as BBB -# TODO: uncomment and adjust only if you really need other variables: -from ... import Variable # used for opinion here, maybe that should be included in the master data model? But I wouldn't know how? something like discrete opinion -from ..base import interface as baseI - - -class Model (object): - """Interface for Model mixin.""" - - # metadata: - name = "adaptive voter model" - """a unique name for the model component""" - description = "..." - """see (Holme, Newman - 2006)""" - requires = [] - """list of other model components required for this model component to - make sense""" - - # Notes: - # - Model does NOT define variables or parameters, only entity types - # and process taxons do! - # - implementation.Model lists these entity-types and process taxons - - -# entity types: - -class Culture (object): - """Interface for Culture process taxon mixin.""" - - # endogenous variables: - acquaintance_network = D.CUL.acquaintance_network - # TODO: give possible_opinions a type, wait for Wolf's choice stuff in the - # master data model - possible_opinions = Variable( - "possible opinions", - "possible opinions of an individual in the sense of the adaptive voter model" - ) - - opinion_change = Variable("probability to adopt another opinion", "") - - multiple_updates = Variable( - "number of updates", "number of updates that are done at the same time") - - # exogenous variables / parameters: - - -class Individual (object): - """Interface for Individual entity type mixin.""" - - # endogenous variables: - opinion = Variable( - "opinion", - "opinion of an individual in the sense of the adaptive voter model" - ) - """Interface for Culture process taxon mixin.""" - - # endogenous variables: - rewiring_probability = Variable( - "rewiring probability", - "rewiring probability phi in the sense of the adaptive voter model by (Holme, Newman - 2006)" - ) - - # exogenous variables / parameters: diff --git a/pycopancore/model_components/adaptive_voter_opinion_formation/model.py b/pycopancore/model_components/adaptive_voter_opinion_formation/model.py deleted file mode 100644 index b561dc02..00000000 --- a/pycopancore/model_components/adaptive_voter_opinion_formation/model.py +++ /dev/null @@ -1,31 +0,0 @@ -"""Model mixing class template. - -TODO: adjust or fill in code and documentation wherever marked by "TODO:", -then remove these instructions -""" - -# This file is part of pycopancore. -# -# Copyright (C) 2016-2017 by COPAN team at Potsdam Institute for Climate -# Impact Research -# -# URL: -# Contact: core@pik-potsdam.de -# License: BSD 2-clause license - -from . import interface as I -# import all needed entity type implementation classes: -from .implementation import Individual -# import all needed process taxon implementation classes: -from .implementation import Culture - - -class Model (I.Model): - """Model mixin class""" - - # mixins provided by this model component: - - entity_types = [Individual] - """list of entity types augmented by this component""" - process_taxa = [Culture] - """list of process taxa augmented by this component""" diff --git a/pycopancore/model_components/anderies_carbon_cycle/__init__.py b/pycopancore/model_components/anderies_carbon_cycle/__init__.py deleted file mode 100644 index d9f2b43c..00000000 --- a/pycopancore/model_components/anderies_carbon_cycle/__init__.py +++ /dev/null @@ -1,20 +0,0 @@ - -""" -copan_global_like_carbon_cycle model component -""" - -# This file is part of pycopancore. -# -# Copyright (C) 2016-2017 by COPAN team at Potsdam Institute for Climate -# Impact Research -# -# URL: -# Contact: core@pik-potsdam.de -# License: BSD 2-clause license - -from . import interface - -from .implementation import * - -# export model component mixin class: -from .model import Model diff --git a/pycopancore/model_components/anderies_carbon_cycle/implementation/__init__.py b/pycopancore/model_components/anderies_carbon_cycle/implementation/__init__.py deleted file mode 100644 index d6e283c7..00000000 --- a/pycopancore/model_components/anderies_carbon_cycle/implementation/__init__.py +++ /dev/null @@ -1,19 +0,0 @@ -""" -This is the copan_global_like_carbon_cycle model-component implementation subpackage -""" - -# This file is part of pycopancore. -# -# Copyright (C) 2016-2017 by COPAN team at Potsdam Institute for Climate -# Impact Research -# -# URL: -# Contact: core@pik-potsdam.de -# License: BSD 2-clause license - - -from .world import World -from .cell import Cell -from .social_system import SocialSystem - -from .environment import Environment diff --git a/pycopancore/model_components/anderies_carbon_cycle/implementation/cell.py b/pycopancore/model_components/anderies_carbon_cycle/implementation/cell.py deleted file mode 100644 index 45299863..00000000 --- a/pycopancore/model_components/anderies_carbon_cycle/implementation/cell.py +++ /dev/null @@ -1,114 +0,0 @@ -"""Jobst: write docstring.""" - -# This file is part of pycopancore. -# -# Copyright (C) 2016-2017 by COPAN team at Potsdam Institute for Climate -# Impact Research -# -# URL: -# Contact: core@pik-potsdam.de -# License: BSD 2-clause license - -from .... import Explicit, ODE -from .... import master_data_model as D -from ...base import interface as B - -from .. import interface as I - -import numpy as np -import sympy as sp - - -class Cell (I.Cell): - """Jobst: write docstring.""" - - # standard methods: - - def __init__(self, - *, - terrestrial_carbon=1 * D.gigatonnes_carbon, - fossil_carbon=1 * D.gigatonnes_carbon, - **kwargs - ): - """Initialize a cell""" - super().__init__(**kwargs) - # initial values: - self.terrestrial_carbon = terrestrial_carbon - self.fossil_carbon = fossil_carbon - - # abbreviations: - - balance = I.Cell.net_ecosystem_production - I.Cell.human_offtake - - processes = [ # using symbolic expressions for performance reasons: - - Explicit("net ecosystem production", - [I.Cell.net_ecosystem_production], - [B.Cell.environment.ecosystem_dependent_conversion_factor - * I.Cell.terrestrial_carbon * (1 - (I.Cell.terrestrial_carbon - / B.Cell.environment.terrestrial_carbon_carrying_capacity)) - * (I.World.photosynthesis_rate - I.World.respiration_rate) - ]), - - - # capacity per area? - # Explicit("net ecosystem production", - # [I.Cell.net_ecosystem_production], - # [B.Cell.environment.ecosystem_dependent_conversion_factor - # * I.Cell.terrestrial_carbon * (1 - (I.Cell.terrestrial_carbon - # / (B.Cell.environment.terrestrial_carbon_capacity_per_area - # * B.Cell.land_area))) - # * (I.World.photosynthesis_rate - I.World.respiration_rate) - # ]), - - Explicit("human offtake", # Interface - [I.Cell.human_offtake], - [I.SocialSystem.harvest_rate * I.Cell.terrestrial_carbon - ]), - - ODE("effect of photosynthesis and respiration", - [I.Cell.terrestrial_carbon, B.Cell.world.atmospheric_carbon], - [balance, -balance]), - - ] - -# instead of: -# -# def do_photosynthesis(self, unused_t): -# """compute and store rhs of ODE photosynthesis""" -# -# # abbreviations: -# L = self.terrestrial_carbon -# Sigma = self.land_area -# -# self.photosynthesis_carbon_flow = \ -# ((self.environment.basic_photosynthesis_productivity -# - self.environment.photosynthesis_sensitivity_on_atmospheric_carbon -# * self.world.atmospheric_carbon) -# * np.sqrt(self.world.atmospheric_carbon / Sigma) -# * (1 - L / (self.environment.terrestrial_carbon_capacity_per_area -# * Sigma))) \ -# * L -# -# self.world.d_atmospheric_carbon -= self.photosynthesis_carbon_flow -# self.d_terrestrial_carbon += self.photosynthesis_carbon_flow -# -# def do_respiration(self, unused_t): -# """compute and store rhs of ODE respiration""" -# -# self.terrestrial_respiration_carbon_flow = \ -# (self.environment.basic_respiration_rate -# + self.environment.respiration_sensitivity_on_atmospheric_carbon -# * self.world.atmospheric_carbon) \ -# * self.terrestrial_carbon -# -# self.d_terrestrial_carbon -= self.terrestrial_respiration_carbon_flow -# self.world.d_atmospheric_carbon += self.terrestrial_respiration_carbon_flow -# -# processes = [ -# ODE("photosynthesis", [I.Cell.terrestrial_carbon, -# B.Cell.world.atmospheric_carbon], -# do_photosynthesis), -# ODE("respiration", [I.Cell.terrestrial_carbon, I.World.atmospheric_carbon], -# do_respiration), -# ] diff --git a/pycopancore/model_components/anderies_carbon_cycle/implementation/environment.py b/pycopancore/model_components/anderies_carbon_cycle/implementation/environment.py deleted file mode 100644 index a7dcf2b0..00000000 --- a/pycopancore/model_components/anderies_carbon_cycle/implementation/environment.py +++ /dev/null @@ -1,98 +0,0 @@ -"""Environment process taxon mixing class. -""" - -# This file is part of pycopancore. -# -# Copyright (C) 2016-2017 by COPAN team at Potsdam Institute for Climate -# Impact Research -# -# URL: -# Contact: core@pik-potsdam.de -# License: BSD 2-clause license - -from .. import interface as I -from ....data_model.master_data_model.dimensions_and_units import \ - gigatonnes_carbon, years, square_kilometers, kelvins - - -class Environment (I.Environment): - """Environment process taxon mixin implementation class.""" - - # standard methods: - - def __init__(self, - *, # TODO: uncomment when adding named args behind here - ocean_atmosphere_diffusion_coefficient=0.05 / years, # Anderies - carbon_solubility_in_sea_water=1, # Anderies - basic_photosynthesis_productivity=26.4 / years / \ - (gigatonnes_carbon / - square_kilometers)**.5, # see Nitzbon 2016 - photosynthesis_sensitivity_on_atmospheric_carbon=0 \ - # 1.1e6 \ - / years / (gigatonnes_carbon / square_kilometers)**.5 - / kelvins, # see Nitzbon 2016 - terrestrial_carbon_capacity_per_area=5000 / 1.5e8 * \ - gigatonnes_carbon / square_kilometers, # ca. 2 times current value - basic_respiration_rate=0.0298 / years, # see Nitzbon 2016 - respiration_sensitivity_on_atmospheric_carbon=0 \ - # 3200 \ - / years / (gigatonnes_carbon / square_kilometers), # see Nitzbon 2016 - temperature_offset=0.2 * kelvins, # Anderies - temperature_sensitivity_on_atmospheric_carbon=0.8 * \ - kelvins / gigatonnes_carbon, # Anderies - scaling_factor_temperature_respiration=110, # Anderies - exponent_for_increase_in_respiration_low_T=4, # Anderies - exponent_for_increase_in_respiration_high_T=5, # Anderies - strength_of_fertilization_effect=1.5, # Anderies - rapidity_of_fertilization_saturation=0.3, # Anderies - scaling_factor_temperature_photosynthesis=220, # Anderies - exponent_for_increase_in_photosynthesis_low_T=3, # Anderies - exponent_for_increase_in_photosynthesis_high_T=7, # Anderies - ecosystem_dependent_conversion_factor=2.5, - terrestrial_carbon_carrying_capacity=0.7, - **kwargs): - """Initialize the unique instance of Environment.""" - super().__init__(**kwargs) # must be the first line - - self.ocean_atmosphere_diffusion_coefficient = \ - ocean_atmosphere_diffusion_coefficient - self.carbon_solubility_in_sea_water = carbon_solubility_in_sea_water - self.basic_photosynthesis_productivity = \ - basic_photosynthesis_productivity - self.photosynthesis_sensitivity_on_atmospheric_carbon = \ - photosynthesis_sensitivity_on_atmospheric_carbon - self.terrestrial_carbon_capacity_per_area = \ - terrestrial_carbon_capacity_per_area - self.basic_respiration_rate = basic_respiration_rate - self.respiration_sensitivity_on_atmospheric_carbon = \ - respiration_sensitivity_on_atmospheric_carbon - self.temperature_offset = temperature_offset - self.temperature_sensitivity_on_atmospheric_carbon = \ - temperature_sensitivity_on_atmospheric_carbon -# Anderies: - self.scaling_factor_temperature_respiration = \ - scaling_factor_temperature_respiration - self.exponent_for_increase_in_respiration_low_T = \ - exponent_for_increase_in_respiration_low_T - self.exponent_for_increase_in_respiration_high_T = \ - exponent_for_increase_in_respiration_high_T - self.strength_of_fertilization_effect = \ - strength_of_fertilization_effect - self.rapidity_of_fertilization_saturation = \ - rapidity_of_fertilization_saturation - self.scaling_factor_temperature_photosynthesis = \ - scaling_factor_temperature_photosynthesis - self.exponent_for_increase_in_photosynthesis_low_T = \ - exponent_for_increase_in_photosynthesis_low_T - self.exponent_for_increase_in_photosynthesis_high_T = \ - exponent_for_increase_in_photosynthesis_high_T - self.ecosystem_dependent_conversion_factor = \ - ecosystem_dependent_conversion_factor - self.terrestrial_carbon_carrying_capacity = \ - terrestrial_carbon_carrying_capacity - - # process-related methods: - - # TODO: add some if needed... - - processes = [] # TODO: instantiate and list process objects here diff --git a/pycopancore/model_components/anderies_carbon_cycle/implementation/social_system.py b/pycopancore/model_components/anderies_carbon_cycle/implementation/social_system.py deleted file mode 100644 index 442abcde..00000000 --- a/pycopancore/model_components/anderies_carbon_cycle/implementation/social_system.py +++ /dev/null @@ -1,50 +0,0 @@ -"""SocialSystem entity type mixing class template. - -TODO: adjust or fill in code and documentation wherever marked by "TODO:", -then remove these instructions -""" - -# This file is part of pycopancore. -# -# Copyright (C) 2016-2017 by COPAN team at Potsdam Institute for Climate -# Impact Research -# -# URL: -# Contact: core@pik-potsdam.de -# License: BSD 2-clause license - -from .. import interface as I -#from .... import master_data_model as D - - -class SocialSystem (I.SocialSystem): - """SocialSystem entity type mixin implementation class.""" - - # standard methods: - - def __init__(self, - *, - harvest_rate=0.5, - **kwargs): - """Initialize an instance of SocialSystem.""" - super().__init__(**kwargs) # must be the first line - - self.harvest_rate = harvest_rate - - def deactivate(self): - """Deactivate a social_system.""" - # TODO: add custom code here: - pass - super().deactivate() # must be the last line - - def reactivate(self): - """Reactivate a social_system.""" - super().reactivate() # must be the first line - # TODO: add custom code here: - pass - - # process-related methods: - - # TODO: add some if needed... - - processes = [] # TODO: instantiate and list process objects here diff --git a/pycopancore/model_components/anderies_carbon_cycle/implementation/world.py b/pycopancore/model_components/anderies_carbon_cycle/implementation/world.py deleted file mode 100644 index d6f750fe..00000000 --- a/pycopancore/model_components/anderies_carbon_cycle/implementation/world.py +++ /dev/null @@ -1,82 +0,0 @@ -"""Jobst: write docstring.""" - -# This file is part of pycopancore. -# -# Copyright (C) 2016-2017 by COPAN team at Potsdam Institute for Climate -# Impact Research -# -# URL: -# Contact: core@pik-potsdam.de -# License: BSD 2-clause license - -from .... import Explicit, ODE -from .. import interface as I -from ...base import interface as B -from .... import master_data_model as D - -import sympy as sp - - -class World (I.World): - """Jobst: write docstring.""" - - # standard methods: - - def __init__(self, - *, - atmospheric_carbon=1 * D.gigatonnes_carbon, - ocean_carbon=1 * D.gigatonnes_carbon, - surface_air_temperature=1 * D.kelvins, - **kwargs - ): - """Initialize an (typically the unique) instance of World.""" - super().__init__(**kwargs) - # initial values: - self.atmospheric_carbon = atmospheric_carbon - self.ocean_carbon = ocean_carbon - self.surface_air_temperature = surface_air_temperature - - # process-related methods: - - def convert_temperature(self, unused_t): - """(see Anderies et al. 2013)""" - self.surface_air_temperature = self.environment.temperature_offset \ - + self.environment.temperature_sensitivity_on_atmospheric_carbon \ - * self.atmospheric_carbon - - def ocean_atmosphere_diffusion(self, unused_t): - """(see Anderies et al. 2013)""" - flow = self.environment.ocean_atmosphere_diffusion_coefficient * ( - self.environment.carbon_solubility_in_sea_water * self.ocean_carbon - - self.atmospheric_carbon) - self.d_ocean_carbon -= flow - self.d_atmospheric_carbon += flow - - processes = [ - Explicit("convert temperature", - [I.World.surface_air_temperature], - convert_temperature), - ODE("ocean-atmosphere diffusion", - [I.World.ocean_carbon, I.World.atmospheric_carbon], - ocean_atmosphere_diffusion), - - Explicit("respiration rate", - [I.World.respiration_rate], - [(B.World.environment.scaling_factor_temperature_respiration - * I.World.surface_air_temperature ** B.World.environment.exponent_for_increase_in_respiration_low_T - * sp.exp(-B.World.environment.exponent_for_increase_in_respiration_high_T - * B.Cell.world.surface_air_temperature))]), - - Explicit("fertilization", - [I.World.fertilization], - [B.World.environment.strength_of_fertilization_effect * I.World.atmospheric_carbon - ** B.World.environment.rapidity_of_fertilization_saturation]), - - Explicit("photosynthesis rate", - [I.World.photosynthesis_rate], - [I.World.fertilization - * B.World.environment.scaling_factor_temperature_photosynthesis * I.World.surface_air_temperature - ** B.World.environment.exponent_for_increase_in_photosynthesis_low_T - * sp.exp(-B.World.environment.exponent_for_increase_in_photosynthesis_high_T - * I.World.surface_air_temperature)]) - ] diff --git a/pycopancore/model_components/anderies_carbon_cycle/interface.py b/pycopancore/model_components/anderies_carbon_cycle/interface.py deleted file mode 100644 index b0a232c5..00000000 --- a/pycopancore/model_components/anderies_carbon_cycle/interface.py +++ /dev/null @@ -1,103 +0,0 @@ -"""copan_global_like_carbon_cycle model component Interface -""" - -# This file is part of pycopancore. -# -# Copyright (C) 2016-2017 by COPAN team at Potsdam Institute for Climate -# Impact Research -# -# URL: -# Contact: core@pik-potsdam.de -# License: BSD 2-clause license - -from ... import master_data_model as D -from ...data_model.master_data_model import ENV, MET, CUL, W, S, C, I -from ... import Variable - - -class Model (object): - """Interface for Model mixin""" - - # metadata: - name = "Anderies carbon cycle" - """a unique name for the model component""" - description = "see Anderies 2013" - """some longer description""" - requires = [] - """list of other model components required for this model component to - make sense""" - - -# entity types: - - -class World (object): - """Interface for World mixin""" - - # variables: - atmospheric_carbon = W.atmospheric_carbon - ocean_carbon = W.ocean_carbon - surface_air_temperature = W.surface_air_temperature - respiration_rate = Variable("respiration rate", "") # unit - fertilization = Variable("fertilization", "") # unit - photosynthesis_rate = Variable("photosynthesis rate", "") # unit - - -class Cell (object): - """Interface for Cell mixin""" - - # variables: - terrestrial_carbon = C.terrestrial_carbon - photosynthesis_carbon_flow = C.photosynthesis_carbon_flow - terrestrial_respiration_carbon_flow = \ - C.terrestrial_respiration_carbon_flow - human_offtake = Variable("human offtake", "") # unit - net_ecosystem_production = Variable( - "net ecosystem production", "") # unit - - -class SocialSystem (object): - - # variables: - harvest_rate = Variable("harvest rate", "") # unit - - -# process taxa: - - -class Environment (object): - """Interface for Environment mixin""" - - # parameters / exogenous veriables: - ocean_atmosphere_diffusion_coefficient = \ - ENV.ocean_atmosphere_diffusion_coefficient - carbon_solubility_in_sea_water = ENV.carbon_solubility_in_sea_water - - basic_photosynthesis_productivity = \ - Variable("basic photosynthesis productivity", "", - unit=D.years**-1 - / (D.gigatonnes_carbon / D.square_kilometers)**.5, - lower_bound=0) - photosynthesis_sensitivity_on_atmospheric_carbon = \ - Variable("sensitivity of photosynthesis productivity on atmospheric carbon", "", - unit=D.years**-1 - / (D.gigatonnes_carbon / D.square_kilometers)**.5 - / D.kelvins) - terrestrial_carbon_capacity_per_area = \ - Variable("per-area capacity of terrestrial carbon", "", - unit=D.gigatonnes_carbon / D.square_kilometers, - lower_bound=0) - - basic_respiration_rate = Variable("basic respiration rate", "", - unit=D.years**-1) - respiration_sensitivity_on_atmospheric_carbon = \ - Variable("sensitivity of respiration rate on atmospheric carbon", "", - unit=D.years**-1 - / (D.gigatonnes_carbon / D.square_kilometers)) - - temperature_offset = \ - Variable("offset of temperature for zero atmospheric carbon", "", - unit=D.kelvins, lower_bound=0) - temperature_sensitivity_on_atmospheric_carbon = \ - Variable("sensitivity of temperature on atmospheric carbon", "", - unit=D.kelvins / D.gigatonnes_carbon, lower_bound=0) diff --git a/pycopancore/model_components/anderies_carbon_cycle/model.py b/pycopancore/model_components/anderies_carbon_cycle/model.py deleted file mode 100644 index 9d622461..00000000 --- a/pycopancore/model_components/anderies_carbon_cycle/model.py +++ /dev/null @@ -1,26 +0,0 @@ -"""copan_global_like_carbon_cycle model mixing class -""" - -# This file is part of pycopancore. -# -# Copyright (C) 2016-2017 by COPAN team at Potsdam Institute for Climate -# Impact Research -# -# URL: -# Contact: core@pik-potsdam.de -# License: BSD 2-clause license - -from . import interface as I -# import all needed entity type implementation classes: -from .implementation import World, Cell, SocialSystem -# import all needed process taxon implementation classes: -from .implementation import Environment - - -class Model (I.Model): - """Model component mixin class""" - - # mixins provided by this model component: - - entity_types = [World, Cell, SocialSystem] - process_taxa = [Environment] diff --git a/pycopancore/model_components/base/implementation/cell.py b/pycopancore/model_components/base/implementation/cell.py index f34a961c..035521b4 100644 --- a/pycopancore/model_components/base/implementation/cell.py +++ b/pycopancore/model_components/base/implementation/cell.py @@ -10,12 +10,11 @@ # License: BSD 2-clause license # only used in this component, not in others: -from ... import abstract -from ....private import unknown +from pycopancore.model_components import abstract +from pycopancore.private._simple_expressions import unknown # typical imports for implementation classes: from .. import interface as I -from .... import master_data_model as D class Cell (I.Cell, abstract.Cell): diff --git a/pycopancore/model_components/base/implementation/culture.py b/pycopancore/model_components/base/implementation/culture.py index 1d2239af..81d42c40 100644 --- a/pycopancore/model_components/base/implementation/culture.py +++ b/pycopancore/model_components/base/implementation/culture.py @@ -9,8 +9,11 @@ # Contact: core@pik-potsdam.de # License: BSD 2-clause license +from networkx import Graph + # only used in this component, not in others: -from ... import abstract +from pycopancore.model_components import abstract +from pycopancore.private._simple_expressions import unknown from .. import interface as I @@ -64,6 +67,44 @@ def worlds(self): """Get the set of all Worlds this Culture acts in.""" return self._worlds + _individuals = unknown + """cache, depends on self.worlds, world.individuals""" + @property # read-only + def individuals(self): + """Get and set the set of Individuals governed by this Culture.""" + if self._individuals is unknown: + # aggregate from worlds: + self._individuals = set() + for w in self.worlds: + self._individuals.update(w.individuals) + return self._individuals + + @individuals.setter + def individuals(self, u): + assert u == unknown, "setter can only be used to reset cache" + self._individuals = unknown + # reset dependent caches: + pass + + _social_systems = unknown + """cache, depends on self.worlds, world.social_systems""" + @property # read-only + def social_systems(self): + """Get and set the set of SocialSystems governed by this Culture.""" + if self._social_systems is unknown: + # aggregate from worlds: + self._social_systems = set() + for w in self.worlds: + self._social_systems.update(w.social_systems) + return self._social_systems + + @social_systems.setter + def social_systems(self, u): + assert u == unknown, "setter can only be used to reset cache" + self._social_systems = unknown + # reset dependent caches: + pass + @property # read-only def groups(self): """Get the set of all Groups in this Culture.""" diff --git a/pycopancore/model_components/base/implementation/group.py b/pycopancore/model_components/base/implementation/group.py index e28a71e0..74854faf 100644 --- a/pycopancore/model_components/base/implementation/group.py +++ b/pycopancore/model_components/base/implementation/group.py @@ -10,10 +10,7 @@ # License: BSD 2-clause license # only used in this component, not in others: -from ... import abstract -from .... import master_data_model as D -from ....private import unknown - +from pycopancore.model_components import abstract from .. import interface as I diff --git a/pycopancore/model_components/base/implementation/individual.py b/pycopancore/model_components/base/implementation/individual.py index dcaa0ffb..f910da7e 100644 --- a/pycopancore/model_components/base/implementation/individual.py +++ b/pycopancore/model_components/base/implementation/individual.py @@ -10,12 +10,13 @@ # License: BSD 2-clause license # only used in this component, not in others -from ... import abstract +from pycopancore.model_components import abstract # from .... import master_data_model as D -from ....private import unknown +from pycopancore.private._simple_expressions import unknown from .. import interface as I + class Individual (I.Individual, abstract.Individual): """Individual entity type mixin implementation class. diff --git a/pycopancore/model_components/base/implementation/social_system.py b/pycopancore/model_components/base/implementation/social_system.py index b8dac8e3..bbaed494 100644 --- a/pycopancore/model_components/base/implementation/social_system.py +++ b/pycopancore/model_components/base/implementation/social_system.py @@ -10,9 +10,8 @@ # License: BSD 2-clause license # only used in this component, not in others: -from ... import abstract -from .... import master_data_model as D -from ....private import unknown +from pycopancore.model_components import abstract +from pycopancore.private._simple_expressions import unknown from .. import interface as I diff --git a/pycopancore/model_components/base/implementation/world.py b/pycopancore/model_components/base/implementation/world.py index fa6851bb..6f14feaa 100644 --- a/pycopancore/model_components/base/implementation/world.py +++ b/pycopancore/model_components/base/implementation/world.py @@ -10,13 +10,16 @@ # License: BSD 2-clause license # only used in this component, not in others: -from ... import abstract -from .... import master_data_model as D -from ....private import unknown +from pycopancore.private._abstract_process_taxon_mixin import \ + _AbstractProcessTaxonMixin +from pycopancore.data_model.ordered_set import OrderedSet + +from pycopancore.model_components import abstract +from pycopancore.private._simple_expressions import unknown from .. import interface as I -from .... import Explicit +from pycopancore.process_types import Explicit class World (I.World, abstract.World): @@ -32,7 +35,6 @@ def __init__(self, *, environment=None, metabolism=None, - culture=None, **kwargs ): """Instantiate (typically the only) instance of World. @@ -43,8 +45,6 @@ def __init__(self, Environment acting on this World. metabolism : obj Metabolism acting on this World. - culture : obj - Culture acting on this World. **kwargs keyword arguments passed to super() @@ -55,8 +55,6 @@ def __init__(self, self.environment = environment self._metabolism = None self.metabolism = metabolism - self._culture = None - self.culture = culture self._social_systems = set() self._cells = set() self._groups = set() @@ -98,37 +96,6 @@ def metabolism(self, m): m._worlds.add(self) self._metabolism = m - @property - def culture(self): - """Get world's culture.""" - return self._culture - - @culture.setter - def culture(self, c): - """Set world's culture.""" - if self._culture is not None: - # first deregister from previous culture's list of worlds: - self._culture.worlds.remove(self) - if c is not None: - assert isinstance(c, I.Culture), \ - "Culture must be taxon type Culture" - c._worlds.add(self) - self._culture = c - - @property - def culture(self): - """Get the Culture acting in this World.""" - return self._culture - - @culture.setter - def culture(self, c): - """Set the World the SocialSystem is part of.""" - if self._culture is not None: - self._culture._worlds.remove(self) - assert isinstance(c, I.Culture), "culture must be of taxon type Culture" - c._worlds.add(self) - self._culture = c - @property # read-only def social_systems(self): """Get the set of all SocialSystems on this World.""" diff --git a/pycopancore/model_components/base/interface.py b/pycopancore/model_components/base/interface.py index e2fb0de1..a1f1c593 100644 --- a/pycopancore/model_components/base/interface.py +++ b/pycopancore/model_components/base/interface.py @@ -13,13 +13,27 @@ # Contact: core@pik-potsdam.de # License: BSD 2-clause license -from ...private import _MixinType, unknown -from ... import Variable, ReferenceVariable, SetVariable -from ... import master_data_model as D -from ...data_model.master_data_model import ENV, CUL, W, S, C +from pycopancore.private._mixin import _MixinType +from pycopancore.data_model.variable import Variable +from pycopancore.data_model.reference_variable import ReferenceVariable +from pycopancore.data_model.set_variable import SetVariable -# model component: +from pycopancore.data_model.unit import unity + +from pycopancore.data_model.master_data_model.dimensions_and_units \ + import DimensionsAndUnits as DAU + +from pycopancore.data_model.master_data_model.environment \ + import Environment as ENV +from pycopancore.data_model.master_data_model.culture \ + import Culture as CUL +from pycopancore.data_model.master_data_model.world \ + import World as W +from pycopancore.data_model.master_data_model.social_system \ + import SocialSystem as S +from pycopancore.data_model.master_data_model.cell \ + import Cell as C class Model (object): @@ -71,10 +85,12 @@ class Culture (object): group_membership_network = CUL.group_membership_network - # read-only attributes storing redundant information: - worlds = SetVariable("worlds", - "Set of Worlds governed by this Culture", - readonly=True) + social_systems = SetVariable("social systems", + "Set of all SocialSystems governed by this Culture", + readonly=True) + individuals = SetVariable("individuals", + "Set of Individuals governed by this Culture", + readonly=True) # entity types: @@ -190,6 +206,7 @@ class SocialSystem (object, metaclass=_MixinType): SocialSystem.higher_social_systems.type = SocialSystem SocialSystem.next_lower_social_systems.type = SocialSystem SocialSystem.lower_social_systems.type = SocialSystem +Culture.social_systems.type = SocialSystem World.social_systems.type = SocialSystem World.top_level_social_systems.type = SocialSystem @@ -252,7 +269,7 @@ class Individual (object, metaclass=_MixinType): "relative representation weight for social_system's population, " "to be used in determining how many people this individual " "represents", - unit=D.unity, lower_bound=0, default=1) + unit=unity, lower_bound=0, default=1) # attributes storing redundant information: world = ReferenceVariable("world", "", type=World, @@ -288,12 +305,13 @@ class Individual (object, metaclass=_MixinType): "represented population", "absolute population represented by this individual", readonly=True, - unit=D.people, + unit=DAU.people, is_extensive=True) # specified only now to avoid recursion: World.individuals.type = Individual +Culture.individuals.type = Individual SocialSystem.direct_individuals.type = Individual SocialSystem.individuals.type = Individual Cell.individuals.type = Individual diff --git a/pycopancore/model_components/base/model_logics.py b/pycopancore/model_components/base/model_logics.py index a9434aa8..fb1275c0 100644 --- a/pycopancore/model_components/base/model_logics.py +++ b/pycopancore/model_components/base/model_logics.py @@ -15,11 +15,18 @@ # Contact: core@pik-potsdam.de # License: BSD 2-clause license -from .. import abstract -from ... import Variable, ReferenceVariable, SetVariable, \ - ODE, Explicit, Step, Event, OrderedSet -from ...private import _AbstractProcess, unknown, _expressions, \ - _AbstractEntityMixin, _AbstractProcessTaxonMixin +from pycopancore.model_components import abstract +from pycopancore.data_model import Variable, ReferenceVariable, SetVariable, \ + OrderedSet +from pycopancore.process_types import ODE, Explicit, Step, Event + +from pycopancore.private._abstract_process import _AbstractProcess +from pycopancore.private._abstract_entity_mixin import _AbstractEntityMixin +from pycopancore.private._abstract_process_taxon_mixin \ + import _AbstractProcessTaxonMixin + +from pycopancore.private._simple_expressions import unknown +from pycopancore.private._expressions import get_vars import gc import inspect import re @@ -163,6 +170,13 @@ def configure(cls, reconfigure=False, **kwargs): ]) # iterate through all model components: for component in cls.components: + + if "entity_types" not in component.__dict__: + component.entity_types = [] + + if "process_taxa" not in component.__dict__: + component.process_taxa = [] + component_interface = component.__bases__[0] # the first base class of an impl. cl. is its interface print("Model component ", component_interface.name, "(", component, ")...") @@ -194,6 +208,9 @@ def configure(cls, reconfigure=False, **kwargs): "different codename." # find and register all processes defined directly in this # mixin's "process" attribute: + if "processes" not in mixin_interface.__dict__: + mixin.processes = [] + for p in mixin.processes: assert isinstance(p, _AbstractProcess), \ "The 'processes' attribute of an implementation " \ @@ -310,7 +327,7 @@ def new__init__(inst, **kwargs): + str(target.owning_class) \ + str(composed_class) if isinstance(p.specification, list): - deps = _expressions.get_vars(p.specification[i]) + deps = get_vars(p.specification[i]) print(" Derivative of", target.target_variable, "directly depends on", deps) @@ -353,7 +370,7 @@ def new__init__(inst, **kwargs): "reference starts at a wrong " \ "entity-type/taxon:" if isinstance(p.specification, list): - deps = _expressions.get_vars(p.specification[i]) + deps = get_vars(p.specification[i]) print(" Target var.", target.target_variable, "directly depends on", deps) diff --git a/pycopancore/model_components/carbon_voters/__init__.py b/pycopancore/model_components/carbon_voters/__init__.py deleted file mode 100644 index 6852092c..00000000 --- a/pycopancore/model_components/carbon_voters/__init__.py +++ /dev/null @@ -1,26 +0,0 @@ -""" -Model component package template. - -TODO: -Copy this folder, rename it to the name of your model component, -then adjust or fill in code and documentation in all modules wherever marked by "TODO:", -finally remove these instructions. -See the model component development tutorial for details. -""" - -# This file is part of pycopancore. -# -# Copyright (C) 2016-2017 by COPAN team at Potsdam Institute for Climate -# Impact Research -# -# URL: -# Contact: core@pik-potsdam.de -# License: BSD 2-clause license - -from . import interface - -# export all implementation classes: -from .implementation import * - -# export model component mixin class: -from .model import Model diff --git a/pycopancore/model_components/carbon_voters/implementation/__init__.py b/pycopancore/model_components/carbon_voters/implementation/__init__.py deleted file mode 100644 index 24d7babf..00000000 --- a/pycopancore/model_components/carbon_voters/implementation/__init__.py +++ /dev/null @@ -1,21 +0,0 @@ -""" -Model component implementation subpackage template. -""" - -# This file is part of pycopancore. -# -# Copyright (C) 2016-2017 by COPAN team at Potsdam Institute for Climate -# Impact Research -# -# URL: -# Contact: core@pik-potsdam.de -# License: BSD 2-clause license - -# TODO: adjust the following lists to your needs: - -# export all provided entity type implementation mixin classes: -from .world import World -from .social_system import SocialSystem -from .culture import Culture - -# export all provided process taxon implementation mixin classes: diff --git a/pycopancore/model_components/carbon_voters/implementation/culture.py b/pycopancore/model_components/carbon_voters/implementation/culture.py deleted file mode 100644 index e209ab95..00000000 --- a/pycopancore/model_components/carbon_voters/implementation/culture.py +++ /dev/null @@ -1,69 +0,0 @@ -"""Culture process taxon mixing class template. - -TODO: adjust or fill in code and documentation wherever marked by "TODO:", -then remove these instructions -""" - -# This file is part of pycopancore. -# -# Copyright (C) 2016-2017 by COPAN team at Potsdam Institute for Climate -# Impact Research -# -# URL: -# Contact: core@pik-potsdam.de -# License: BSD 2-clause license - -from .. import interface as I -# from .... import master_data_model as D -from .... import Explicit -import sympy as sp -import random - - -class Culture (I.Culture): - """Culture process taxon mixin implementation class.""" - - # standard methods: - - def __init__(self, - *, - impact_scaling_factor=5, - no_impact_atmospheric_carbon_level=0.15, - no_impact_opinion_change=0.5, - **kwargs): - """Initialize the unique instance of Culture.""" - super().__init__(**kwargs) # must be the first line - - self.impact_scaling_factor = impact_scaling_factor - self.no_impact_atmospheric_carbon_level = no_impact_atmospheric_carbon_level - self.no_impact_opinion_change = no_impact_opinion_change - - # process-related methods: - def opinion_change_function(self, x, y): - if self.impact > 0: - _opinion_change_to_awareness = self.no_impact_opinion_change + (1 - self.no_impact_opinion_change) \ - * (1 - sp.exp(- self.impact)) - if x.opinion == 0 and y.opinion == 1: - return random.random() < _opinion_change_to_awareness - elif x.opinion == 1 and y.opinion == 0: - return random.random() < (1 - _opinion_change_to_awareness) - else: - return random.random() < self.no_impact_opinion_change - - def set_opinion_change(self, t): - self.opinion_change = \ - self.opinion_change_function - - processes = [ - - Explicit( - "atmospheric carbon impact", - [I.Culture.impact], - [I.Culture.impact_scaling_factor - * (I.World.atmospheric_carbon - I.Culture.no_impact_atmospheric_carbon_level)] - ), - - Explicit("set probability of opinion adoption", - [I.Culture.opinion_change], - set_opinion_change) - ] # TODO: instantiate and list process objects here diff --git a/pycopancore/model_components/carbon_voters/implementation/social_system.py b/pycopancore/model_components/carbon_voters/implementation/social_system.py deleted file mode 100644 index 0eeeb06c..00000000 --- a/pycopancore/model_components/carbon_voters/implementation/social_system.py +++ /dev/null @@ -1,63 +0,0 @@ -"""SocialSystem entity type mixing class template. - -TODO: adjust or fill in code and documentation wherever marked by "TODO:", -then remove these instructions -""" - -# This file is part of pycopancore. -# -# Copyright (C) 2016-2017 by COPAN team at Potsdam Institute for Climate -# Impact Research -# -# URL: -# Contact: core@pik-potsdam.de -# License: BSD 2-clause license - -from .. import interface as I -from ...base import interface as B -# from .... import master_data_model as D -from .... import Explicit -import sympy as sp - - -class SocialSystem (I.SocialSystem): - """SocialSystem entity type mixin implementation class.""" - - # standard methods: - - def __init__(self, - # *, # TODO: uncomment when adding named args behind here - **kwargs): - """Initialize an instance of SocialSystem.""" - super().__init__(**kwargs) # must be the first line - # TODO: add custom code here: - pass - - def deactivate(self): - """Deactivate a social_system.""" - # TODO: add custom code here: - pass - super().deactivate() # must be the last line - - def reactivate(self): - """Reactivate a social_system.""" - super().reactivate() # must be the first line - # TODO: add custom code here: - pass - - # process-related methods: - - def set_harvest_rate(self, t): - if self.opinion == 0: # indifferent - self.harvest_rate = 0.5 - else: # opinion == 1 - self.harvest_rate = 0.25 - - processes = [ - Explicit( - "harvest rate decision", - [I.SocialSystem.harvest_rate], - set_harvest_rate - ), - - ] # TODO: instantiate and list process objects here diff --git a/pycopancore/model_components/carbon_voters/implementation/world.py b/pycopancore/model_components/carbon_voters/implementation/world.py deleted file mode 100644 index b4cd66e8..00000000 --- a/pycopancore/model_components/carbon_voters/implementation/world.py +++ /dev/null @@ -1,49 +0,0 @@ -"""World entity type mixing class template. - -TODO: adjust or fill in code and documentation wherever marked by "TODO:", -then remove these instructions -""" - -# This file is part of pycopancore. -# -# Copyright (C) 2016-2017 by COPAN team at Potsdam Institute for Climate -# Impact Research -# -# URL: -# Contact: core@pik-potsdam.de -# License: BSD 2-clause license - -from .. import interface as I -# from .... import master_data_model as D - - -class World (I.World): - """World entity type mixin implementation class.""" - - # standard methods: - - def __init__(self, - # *, # TODO: uncomment when adding named args behind here - **kwargs): - """Initialize an instance of World.""" - super().__init__(**kwargs) # must be the first line - # TODO: add custom code here: - pass - - def deactivate(self): - """Deactivate a world.""" - # TODO: add custom code here: - pass - super().deactivate() # must be the last line - - def reactivate(self): - """Reactivate a world.""" - super().reactivate() # must be the first line - # TODO: add custom code here: - pass - - # process-related methods: - - # TODO: add some if needed... - - processes = [] # TODO: instantiate and list process objects here diff --git a/pycopancore/model_components/carbon_voters/interface.py b/pycopancore/model_components/carbon_voters/interface.py deleted file mode 100644 index 8855de4d..00000000 --- a/pycopancore/model_components/carbon_voters/interface.py +++ /dev/null @@ -1,130 +0,0 @@ -"""model component Interface template. - -TODO: adjust or fill in code and documentation wherever marked by "TODO:", then -remove these instructions. -""" - -# This file is part of pycopancore. -# -# Copyright (C) 2016-2017 by COPAN team at Potsdam Institute for Climate -# Impact Research -# -# URL: -# Contact: core@pik-potsdam.de -# License: BSD 2-clause license - -# TODO: use variables from the master data model wherever possible: -from ... import master_data_model as D -# TODO: uncomment and adjust of you need further variables from another -# model component: -# import ..BBB.interface as BBB -from .. import adaptive_voter_opinion_formation as avof -from .. import majority_decision as md -from .. import anderies_carbon_cycle as cc -# TODO: uncomment and adjust only if you really need other variables: -from ... import Variable - - -class Model (object): - """Interface for Model mixin.""" - - # metadata: - name = "carbon voters" - """a unique name for the model component""" - description = "sets the harvest rate by majority decision and " \ - "the probability of awareness opinion adoption is dependent on atmospheric carbon" - """some longer description""" - requires = [avof, md, cc] - """list of other model components required for this model component to - make sense""" - - # Notes: - # - Model does NOT define variables or parameters, only entity types - # and process taxons do! - # - implementation.Model lists these entity-types and process taxons - -# entity types: - - -class World (object): - """Interface for World mixin.""" - - # endogenous variables: - # TODO: use variables from the master data model wherever possible - # wherever possible!: - # X = D.X - # TODO: uncomment and adjust of you need further variables from another - atmospheric_carbon = cc.World.atmospheric_carbon - # TODO: uncomment and adjust only if you really need other variables: - # W = Variable("name", "desc", unit=..., ...) - - # exogenous variables / parameters: - # surface_air_temperature = D.world.surface_air_temperature - - -class SocialSystem (object): - """Interface for SocialSystem entity type mixin.""" - - # endogenous variables: - - # exogenous variables / parameters: - - opinion = md.SocialSystem.opinion - - harvest_rate = cc.SocialSystem.harvest_rate - - -# class Cell (object): -# """Interface for Cell entity type mixin.""" -# -# # endogenous variables: -# -# # exogenous variables / parameters: - - -# class Individual (object): -# """Interface for Individual entity type mixin.""" -# -# # endogenous variables: -# -# # exogenous variables / parameters: - - -# process taxa: - - -# class Environment (object): -# """Interface for Environment process taxon mixin.""" -# -# # endogenous variables: -# -# # exogenous variables / parameters: - - -# class Metabolism (object): -# """Interface for Metabolism process taxon mixin.""" -# -# # endogenous variables: -# -# # exogenous variables / parameters: - - -class Culture (object): - """Interface for Culture process taxon mixin.""" - - # endogenous variables: - - # exogenous variables / parameters: - # - opinion_change = avof.Culture.opinion_change - - impact_scaling_factor = Variable("scaling factor", "") - - no_impact_atmospheric_carbon_level = Variable("", "level of atmospheric carbon that doesn't change peoples " - "probability of opinion change to awareness") - - no_impact_opinion_change = Variable("", "basic probability of opinion change to awareness in " - "avof without climate impact effects") # take adaptive voter model opinion_change? - - impact = Variable("impact of atmospheric carbon / temperature on social_system", - "based on atmospheric carbon level") diff --git a/pycopancore/model_components/carbon_voters/model.py b/pycopancore/model_components/carbon_voters/model.py deleted file mode 100644 index d582c286..00000000 --- a/pycopancore/model_components/carbon_voters/model.py +++ /dev/null @@ -1,31 +0,0 @@ -"""Model mixing class template. - -TODO: adjust or fill in code and documentation wherever marked by "TODO:", -then remove these instructions -""" - -# This file is part of pycopancore. -# -# Copyright (C) 2016-2017 by COPAN team at Potsdam Institute for Climate -# Impact Research -# -# URL: -# Contact: core@pik-potsdam.de -# License: BSD 2-clause license - -from . import interface as I -# import all needed entity type implementation classes: -from .implementation import World, SocialSystem, Culture -# import all needed process taxon implementation classes: -# from .implementation import Environment, Metabolism, Culture - - -class Model (I.Model): - """Model mixin class.""" - - # mixins provided by this model component: - - entity_types = [World, SocialSystem] - """list of entity types augmented by this component""" - process_taxa = [Culture] - """list of process taxa augmented by this component""" diff --git a/pycopancore/model_components/copan_global_like_carbon_cycle/__init__.py b/pycopancore/model_components/copan_global_like_carbon_cycle/__init__.py deleted file mode 100644 index a8a236ad..00000000 --- a/pycopancore/model_components/copan_global_like_carbon_cycle/__init__.py +++ /dev/null @@ -1,19 +0,0 @@ -""" -copan_global_like_carbon_cycle model component -""" - -# This file is part of pycopancore. -# -# Copyright (C) 2016-2017 by COPAN team at Potsdam Institute for Climate -# Impact Research -# -# URL: -# Contact: core@pik-potsdam.de -# License: BSD 2-clause license - -from . import interface - -from .implementation import * - -# export model component mixin class: -from .model import Model diff --git a/pycopancore/model_components/copan_global_like_carbon_cycle/implementation/__init__.py b/pycopancore/model_components/copan_global_like_carbon_cycle/implementation/__init__.py deleted file mode 100644 index 15c21fe9..00000000 --- a/pycopancore/model_components/copan_global_like_carbon_cycle/implementation/__init__.py +++ /dev/null @@ -1,18 +0,0 @@ -""" -This is the copan_global_like_carbon_cycle model-component implementation subpackage -""" - -# This file is part of pycopancore. -# -# Copyright (C) 2016-2017 by COPAN team at Potsdam Institute for Climate -# Impact Research -# -# URL: -# Contact: core@pik-potsdam.de -# License: BSD 2-clause license - - -from .world import World -from .cell import Cell - -from .environment import Environment diff --git a/pycopancore/model_components/copan_global_like_carbon_cycle/implementation/cell.py b/pycopancore/model_components/copan_global_like_carbon_cycle/implementation/cell.py deleted file mode 100644 index 699ad554..00000000 --- a/pycopancore/model_components/copan_global_like_carbon_cycle/implementation/cell.py +++ /dev/null @@ -1,103 +0,0 @@ -"""provides this model component's Cell mixin class""" - -# This file is part of pycopancore. -# -# Copyright (C) 2016-2017 by COPAN team at Potsdam Institute for Climate -# Impact Research -# -# URL: -# Contact: core@pik-potsdam.de -# License: BSD 2-clause license - - -from .... import Explicit, ODE -from ...base import interface as B - -from .. import interface as I - -import sympy as sp # to be able to use sp.sqrt - - -class Cell (I.Cell): - """Jobst: write docstring.""" - - # abbreviation: - - balance = (I.Cell.photosynthesis_carbon_flow - - I.Cell.terrestrial_respiration_carbon_flow) - atmospheric_carbon_density = sp.Max(0, B.Cell.world.atmospheric_carbon - / B.Cell.world.sum.cells.land_area) - - processes = [ # using symbolic expressions for performance and legibility: - - Explicit("photosynthesis flow", - [I.Cell.photosynthesis_carbon_flow], - [((B.Cell.environment.basic_photosynthesis_productivity - - B.Cell.environment.photosynthesis_sensitivity_on_atmospheric_carbon - * atmospheric_carbon_density) - * sp.sqrt(atmospheric_carbon_density) - * (1 - I.Cell.terrestrial_carbon - / (B.Cell.environment.terrestrial_carbon_capacity_per_area - * B.Cell.land_area)) - ) - * I.Cell.terrestrial_carbon - ]), - - Explicit("respiration flow", - [I.Cell.terrestrial_respiration_carbon_flow], - [(B.Cell.world.environment.basic_respiration_rate - + B.Cell.world.environment.respiration_sensitivity_on_atmospheric_carbon - * atmospheric_carbon_density) - * I.Cell.terrestrial_carbon - ]), - - ODE("effect of photosynthesis and respiration", - [I.Cell.terrestrial_carbon, - B.Cell.world.atmospheric_carbon], - [balance, - -balance]), - - ] - -# instead of: -# -# def do_photosynthesis(self, unused_t): -# """compute and store rhs of ODE photosynthesis""" -# -# # abbreviations: -# L = self.terrestrial_carbon -# Sigma = self.land_area -# -# self.photosynthesis_carbon_flow = \ -# ((self.environment.basic_photosynthesis_productivity -# - self.environment.photosynthesis_sensitivity_on_atmospheric_carbon -# * self.world.atmospheric_carbon) -# * np.sqrt(self.world.atmospheric_carbon / Sigma) -# * (1 - L / (self.environment.terrestrial_carbon_capacity_per_area -# * Sigma))) \ -# * L -# -# self.world.d_atmospheric_carbon -= self.photosynthesis_carbon_flow -# self.d_terrestrial_carbon += self.photosynthesis_carbon_flow -# -# def do_respiration(self, unused_t): -# """compute and store rhs of ODE respiration""" -# -# self.terrestrial_respiration_carbon_flow = \ -# (self.environment.basic_respiration_rate -# + self.environment.respiration_sensitivity_on_atmospheric_carbon -# * self.world.atmospheric_carbon) \ -# * self.terrestrial_carbon -# -# self.d_terrestrial_carbon -= self.terrestrial_respiration_carbon_flow -# self.world.d_atmospheric_carbon += (self -# .terrestrial_respiration_carbon_flow) -# -# processes = [ -# ODE("photosynthesis", [I.Cell.terrestrial_carbon, -# B.Cell.world.atmospheric_carbon], -# do_photosynthesis), -# ODE("respiration", [I.Cell.terrestrial_carbon, -# B.Cell.world.atmospheric_carbon], -# do_respiration), -# ] diff --git a/pycopancore/model_components/copan_global_like_carbon_cycle/implementation/environment.py b/pycopancore/model_components/copan_global_like_carbon_cycle/implementation/environment.py deleted file mode 100644 index e681dbd9..00000000 --- a/pycopancore/model_components/copan_global_like_carbon_cycle/implementation/environment.py +++ /dev/null @@ -1,17 +0,0 @@ -"""provides this model component's Environment mixin class""" - -# This file is part of pycopancore. -# -# Copyright (C) 2017 by COPAN team at Potsdam Institute for Climate -# Impact Research -# -# URL: -# License: MIT license - -from .. import interface as I - - -class Environment (I.Environment): - """Environment process taxon mixin implementation class.""" - - processes = [] diff --git a/pycopancore/model_components/copan_global_like_carbon_cycle/implementation/world.py b/pycopancore/model_components/copan_global_like_carbon_cycle/implementation/world.py deleted file mode 100644 index 5db56dd5..00000000 --- a/pycopancore/model_components/copan_global_like_carbon_cycle/implementation/world.py +++ /dev/null @@ -1,44 +0,0 @@ -"""provides this model component's World mixin class""" - -# This file is part of pycopancore. -# -# Copyright (C) 2016-2017 by COPAN team at Potsdam Institute for Climate -# Impact Research -# -# URL: -# Contact: core@pik-potsdam.de -# License: BSD 2-clause license - -from .... import Explicit, ODE -from .. import interface as I -from ...base import interface as B -from .... import master_data_model as D - - -class World (I.World): - """World with ocean-atmosphere diffusion - and linear relationship between temperature and atmospheric carbon - """ - - # abbreviation: - diffusion_flow = (B.World.environment.ocean_atmosphere_diffusion_coefficient - * (I.World.upper_ocean_carbon - - B.World.environment.carbon_solubility_in_sea_water - * I.World.atmospheric_carbon)) - """(See Nitzbon et al. 2017).""" - - processes = [ - - Explicit("immediate greenhouse effect", - [I.World.surface_air_temperature], - [B.World.environment.reference_temperature - + B.World.environment.temperature_sensitivity_on_atmospheric_carbon - * (I.World.atmospheric_carbon - - B.World.environment.reference_atmospheric_carbon)]), - - ODE("ocean-atmosphere diffusion", - [I.World.upper_ocean_carbon, I.World.atmospheric_carbon], - [-diffusion_flow, diffusion_flow] - ) - - ] diff --git a/pycopancore/model_components/copan_global_like_carbon_cycle/interface.py b/pycopancore/model_components/copan_global_like_carbon_cycle/interface.py deleted file mode 100644 index 3cf7a570..00000000 --- a/pycopancore/model_components/copan_global_like_carbon_cycle/interface.py +++ /dev/null @@ -1,110 +0,0 @@ -"""copan_global_like_carbon_cycle model component Interface.""" - -# This file is part of pycopancore. -# -# Copyright (C) 2016-2017 by COPAN team at Potsdam Institute for Climate -# Impact Research -# -# URL: -# Contact: core@pik-potsdam.de -# License: BSD 2-clause license - -from ... import master_data_model as D -from ...data_model.master_data_model import ENV, W, C -from ... import Variable - - -class Model (object): - """Interface for Model mixin.""" - - # metadata: - name = "copan:GLOBAL-like carbon cycle" - """a unique name for the model component""" - description = "Simple carbon cycle as in copan:GLOBAL, " \ - "but with cell-based terrestrial and fossil carbon" - """some longer description""" - requires = [] - """list of other model components required for this model component to - make sense""" - - -# entity types: - - -class World (object): - """Interface for World mixin.""" - - # variables: - atmospheric_carbon = W.atmospheric_carbon - upper_ocean_carbon = W.upper_ocean_carbon - surface_air_temperature = W.surface_air_temperature - - -class Cell (object): - """Interface for Cell mixin.""" - - # variables: - - land_area = C.land_area - land_area.default = 1 * D.square_kilometers - - terrestrial_carbon = C.terrestrial_carbon - terrestrial_carbon.default = 1 * D.gigatonnes_carbon - - photosynthesis_carbon_flow = C.photosynthesis_carbon_flow - terrestrial_respiration_carbon_flow = \ - C.terrestrial_respiration_carbon_flow - -# process taxa: - - -class Environment (object): - """Interface for Environment mixin.""" - - # parameters / exogenous variables / read-only: - - ocean_atmosphere_diffusion_coefficient = \ - ENV.ocean_atmosphere_diffusion_coefficient - carbon_solubility_in_sea_water = ENV.carbon_solubility_in_sea_water - - basic_photosynthesis_productivity = \ - Variable("basic photosynthesis productivity", "", - unit = D.years**-1 - / (D.gigatonnes_carbon / D.square_kilometers)**0.5, - lower_bound=0, - default=34) # higher than 26.4 due to non-infinity capacity - photosynthesis_sensitivity_on_atmospheric_carbon = \ - Variable("sensitivity of photosynthesis productivity on atmospheric " - "carbon density", "", - unit = D.years**-1 - / (D.gigatonnes_carbon / D.square_kilometers)**0.5 - / (D.gigatonnes_carbon / D.square_kilometers), - default=1.1e6) - terrestrial_carbon_capacity_per_area = \ - Variable("per-area capacity of terrestrial carbon", "", - unit = D.gigatonnes_carbon / D.square_kilometers, - lower_bound=0, default = 10 * 2500 / 1.5e8) - # ca. 10 times current value. TODO: improve default - - basic_respiration_rate = Variable("basic respiration rate", "", - unit=D.years**-1, default=.0298) - respiration_sensitivity_on_atmospheric_carbon = \ - Variable("sensitivity of respiration rate on atmospheric carbon", "", - unit = D.years**-1 - / (D.gigatonnes_carbon / D.square_kilometers), - default=3.2e3) - - reference_temperature = \ - Variable("reference temperature for relationship with atmospheric carbon", - "default: pre-industrial value", - unit=D.kelvins, lower_bound=0, - default=287) # TODO: verify! - reference_atmospheric_carbon = \ - Variable("reference atmospheric carbon for relationship with temperature", - "default: pre-industrial value", - unit=D.gigatonnes_carbon, lower_bound=0, - default=589) - temperature_sensitivity_on_atmospheric_carbon = \ - Variable("sensitivity of temperature on atmospheric carbon", "", - unit = D.kelvins / D.gigatonnes_carbon, lower_bound=0, - default = 1.5 / 1000) diff --git a/pycopancore/model_components/copan_global_like_carbon_cycle/model.py b/pycopancore/model_components/copan_global_like_carbon_cycle/model.py deleted file mode 100644 index 4f1e7395..00000000 --- a/pycopancore/model_components/copan_global_like_carbon_cycle/model.py +++ /dev/null @@ -1,25 +0,0 @@ -"""copan_global_like_carbon_cycle model mixing class.""" - -# This file is part of pycopancore. -# -# Copyright (C) 2016-2017 by COPAN team at Potsdam Institute for Climate -# Impact Research -# -# URL: -# Contact: core@pik-potsdam.de -# License: BSD 2-clause license - -from . import interface as I -# import all needed entity type implementation classes: -from .implementation import World, Cell -# import all needed process taxon implementation classes: -from .implementation import Environment - - -class Model (I.Model): - """Model component mixin class.""" - - # mixins provided by this model component: - - entity_types = [World, Cell] - process_taxa = [Environment] diff --git a/pycopancore/model_components/copan_global_like_economic_growth/__init__.py b/pycopancore/model_components/copan_global_like_economic_growth/__init__.py deleted file mode 100644 index c59080ec..00000000 --- a/pycopancore/model_components/copan_global_like_economic_growth/__init__.py +++ /dev/null @@ -1,20 +0,0 @@ -""" -copan_global_like_economic_growth model component package. -""" - -# This file is part of pycopancore. -# -# Copyright (C) 2016-2017 by COPAN team at Potsdam Institute for Climate -# Impact Research -# -# URL: -# Contact: core@pik-potsdam.de -# License: BSD 2-clause license - -from . import interface - -# export all implementation classes: -from .implementation import * - -# export model component mixin class: -from .model import Model diff --git a/pycopancore/model_components/copan_global_like_economic_growth/implementation/__init__.py b/pycopancore/model_components/copan_global_like_economic_growth/implementation/__init__.py deleted file mode 100644 index 5f05fc41..00000000 --- a/pycopancore/model_components/copan_global_like_economic_growth/implementation/__init__.py +++ /dev/null @@ -1,18 +0,0 @@ -""" -Model component implementation subpackage. -""" - -# This file is part of pycopancore. -# -# Copyright (C) 2016-2017 by COPAN team at Potsdam Institute for Climate -# Impact Research -# -# URL: -# Contact: core@pik-potsdam.de -# License: BSD 2-clause license - -from .metabolism import Metabolism - -# export all provided entity type implementation mixin classes: -from .social_system import SocialSystem -from .world import World diff --git a/pycopancore/model_components/copan_global_like_economic_growth/implementation/metabolism.py b/pycopancore/model_components/copan_global_like_economic_growth/implementation/metabolism.py deleted file mode 100644 index de4443f3..00000000 --- a/pycopancore/model_components/copan_global_like_economic_growth/implementation/metabolism.py +++ /dev/null @@ -1,18 +0,0 @@ -"""provides this model component' Metabolism mixin class""" - -# This file is part of pycopancore. -# -# Copyright (C) 2016-2017 by COPAN team at Potsdam Institute for Climate -# Impact Research -# -# URL: -# Contact: core@pik-potsdam.de -# License: BSD 2-clause license - -from .. import interface as I - - -class Metabolism (I.Metabolism): - """Metabolism process taxon mixin implementation class.""" - - processes = [] diff --git a/pycopancore/model_components/copan_global_like_economic_growth/implementation/social_system.py b/pycopancore/model_components/copan_global_like_economic_growth/implementation/social_system.py deleted file mode 100644 index 97cd419f..00000000 --- a/pycopancore/model_components/copan_global_like_economic_growth/implementation/social_system.py +++ /dev/null @@ -1,50 +0,0 @@ -"""provides this model component's SocialSystem mixin class""" - -# This file is part of pycopancore. -# -# Copyright (C) 2016-2017 by COPAN team at Potsdam Institute for Climate -# Impact Research -# -# URL: -# Contact: core@pik-potsdam.de -# License: BSD 2-clause license - -from .. import interface as I -from .... import Explicit, ODE -from ...base import interface as B - - -class SocialSystem (I.SocialSystem): - """SocialSystem entity type mixin implementation class.""" - - processes = [ - - Explicit("investment", - [I.SocialSystem.investment_flow, - I.SocialSystem.consumption_flow], - [I.SocialSystem.savings_rate * I.SocialSystem.economic_output_flow, - (1 - I.SocialSystem.savings_rate) * I.SocialSystem.economic_output_flow] - ), - - Explicit("capital depreciation rate", - [I.SocialSystem.physical_capital_depreciation_rate], - [I.SocialSystem.basic_physical_capital_depreciation_rate - + I.SocialSystem.physical_capital_depreciation_rate_temperature_sensitivity - * (B.SocialSystem.world.surface_air_temperature - - I.SocialSystem.physical_capital_depreciation_rate_reference_temperature)] - ), - - ODE("growth, spillovers, depreciation", - [I.SocialSystem.physical_capital, - I.SocialSystem.renewable_energy_knowledge], - [I.SocialSystem.investment_flow - - I.SocialSystem.physical_capital_depreciation_rate - * I.SocialSystem.physical_capital, - I.SocialSystem.renewable_energy_input_flow - + B.SocialSystem.metabolism.renewable_energy_knowledge_spillover_fraction - * (B.SocialSystem.world.renewable_energy_input_flow - - I.SocialSystem.renewable_energy_input_flow) - - I.SocialSystem.renewable_energy_knowledge_depreciation_rate - * I.SocialSystem.renewable_energy_knowledge]) - - ] diff --git a/pycopancore/model_components/copan_global_like_economic_growth/implementation/world.py b/pycopancore/model_components/copan_global_like_economic_growth/implementation/world.py deleted file mode 100644 index 8161a9f0..00000000 --- a/pycopancore/model_components/copan_global_like_economic_growth/implementation/world.py +++ /dev/null @@ -1,26 +0,0 @@ -"""provides this model component's World mixin class""" - -# This file is part of pycopancore. -# -# Copyright (C) 2016-2017 by COPAN team at Potsdam Institute for Climate -# Impact Research -# -# URL: -# Contact: core@pik-potsdam.de -# License: BSD 2-clause license - -from .... import Explicit -from .. import interface as I -from ...base import interface as B - - -class World (I.World): - """ - """ - - processes = [ - - Explicit("aggregate flows", - [I.World.renewable_energy_input_flow], - [B.World.sum.social_systems.renewable_energy_input_flow]), - ] diff --git a/pycopancore/model_components/copan_global_like_economic_growth/interface.py b/pycopancore/model_components/copan_global_like_economic_growth/interface.py deleted file mode 100644 index c5d495d2..00000000 --- a/pycopancore/model_components/copan_global_like_economic_growth/interface.py +++ /dev/null @@ -1,83 +0,0 @@ -"""model component Interface.""" - -# This file is part of pycopancore. -# -# Copyright (C) 2016-2017 by COPAN team at Potsdam Institute for Climate -# Impact Research -# -# URL: -# Contact: core@pik-potsdam.de -# License: BSD 2-clause license - -from ... import master_data_model as D -from ...data_model.master_data_model import MET, S, W - - -class Model (object): - """Interface for Model mixin.""" - - # metadata: - name = "copan:GLOBAL-like economic growth" - """a unique name for the model component""" - description = """capital investments at fixed savings rate, - learning-by-doing in renewable energy sector""" - """some longer description""" - requires = [] - """list of other model components required for this model component to - make sense""" - - # Notes: - # - Model does NOT define variables or parameters, only entity types - # and process taxons do! - # - implementation.Model lists these entity-types and process taxons - - -class Metabolism (object): - """Interface for Metabolism process taxon mixin.""" - - renewable_energy_knowledge_spillover_fraction = \ - MET.renewable_energy_knowledge_spillover_fraction - - -# entity types: - - -class World (object): - """Interface for World entity type mixin.""" - - renewable_energy_input_flow = W.renewable_energy_input_flow - - -class SocialSystem (object): - """Interface for SocialSystem entity type mixin.""" - - # endogenous variables: - - physical_capital = S.physical_capital - physical_capital.default = 1 * D.dollars - - renewable_energy_knowledge = S.renewable_energy_knowledge - renewable_energy_knowledge.default = 1 * D.gigajoules - - physical_capital_depreciation_rate = S.physical_capital_depreciation_rate - - # output-only variables: - - investment_flow = S.investment_flow - consumption_flow = S.consumption_flow - - # exogenous variables / parameters: - - economic_output_flow = S.economic_output_flow - renewable_energy_input_flow = S.renewable_energy_input_flow - - savings_rate = S.savings_rate - basic_physical_capital_depreciation_rate = \ - S.basic_physical_capital_depreciation_rate - physical_capital_depreciation_rate_temperature_sensitivity = \ - S.physical_capital_depreciation_rate_temperature_sensitivity - physical_capital_depreciation_rate_reference_temperature = \ - S.physical_capital_depreciation_rate_reference_temperature - renewable_energy_knowledge_depreciation_rate = \ - S.renewable_energy_knowledge_depreciation_rate - \ No newline at end of file diff --git a/pycopancore/model_components/copan_global_like_economic_growth/model.py b/pycopancore/model_components/copan_global_like_economic_growth/model.py deleted file mode 100644 index ae46394b..00000000 --- a/pycopancore/model_components/copan_global_like_economic_growth/model.py +++ /dev/null @@ -1,23 +0,0 @@ -"""Model mixing class.""" - -# This file is part of pycopancore. -# -# Copyright (C) 2016-2017 by COPAN team at Potsdam Institute for Climate -# Impact Research -# -# URL: -# Contact: core@pik-potsdam.de -# License: BSD 2-clause license - -from . import interface as I -# import all needed entity type implementation classes: -from .implementation import Metabolism, SocialSystem, World - - -class Model (I.Model): - """Model mixin class.""" - - # mixins provided by this model component: - - entity_types = [SocialSystem, World] - process_taxa = [Metabolism] diff --git a/pycopancore/model_components/copan_global_like_population_growth/__init__.py b/pycopancore/model_components/copan_global_like_population_growth/__init__.py deleted file mode 100644 index 6852092c..00000000 --- a/pycopancore/model_components/copan_global_like_population_growth/__init__.py +++ /dev/null @@ -1,26 +0,0 @@ -""" -Model component package template. - -TODO: -Copy this folder, rename it to the name of your model component, -then adjust or fill in code and documentation in all modules wherever marked by "TODO:", -finally remove these instructions. -See the model component development tutorial for details. -""" - -# This file is part of pycopancore. -# -# Copyright (C) 2016-2017 by COPAN team at Potsdam Institute for Climate -# Impact Research -# -# URL: -# Contact: core@pik-potsdam.de -# License: BSD 2-clause license - -from . import interface - -# export all implementation classes: -from .implementation import * - -# export model component mixin class: -from .model import Model diff --git a/pycopancore/model_components/copan_global_like_population_growth/implementation/__init__.py b/pycopancore/model_components/copan_global_like_population_growth/implementation/__init__.py deleted file mode 100644 index b7d4aa4c..00000000 --- a/pycopancore/model_components/copan_global_like_population_growth/implementation/__init__.py +++ /dev/null @@ -1,20 +0,0 @@ -""" -Model component implementation subpackage template. -""" - -# This file is part of pycopancore. -# -# Copyright (C) 2016-2017 by COPAN team at Potsdam Institute for Climate -# Impact Research -# -# URL: -# Contact: core@pik-potsdam.de -# License: BSD 2-clause license - -# TODO: adjust the following lists to your needs: - -# export all provided entity type implementation mixin classes: -from .social_system import SocialSystem - -# export all provided process taxon implementation mixin classes: -from .metabolism import Metabolism diff --git a/pycopancore/model_components/copan_global_like_population_growth/implementation/metabolism.py b/pycopancore/model_components/copan_global_like_population_growth/implementation/metabolism.py deleted file mode 100644 index de4443f3..00000000 --- a/pycopancore/model_components/copan_global_like_population_growth/implementation/metabolism.py +++ /dev/null @@ -1,18 +0,0 @@ -"""provides this model component' Metabolism mixin class""" - -# This file is part of pycopancore. -# -# Copyright (C) 2016-2017 by COPAN team at Potsdam Institute for Climate -# Impact Research -# -# URL: -# Contact: core@pik-potsdam.de -# License: BSD 2-clause license - -from .. import interface as I - - -class Metabolism (I.Metabolism): - """Metabolism process taxon mixin implementation class.""" - - processes = [] diff --git a/pycopancore/model_components/copan_global_like_population_growth/implementation/social_system.py b/pycopancore/model_components/copan_global_like_population_growth/implementation/social_system.py deleted file mode 100644 index 8f4ee6b1..00000000 --- a/pycopancore/model_components/copan_global_like_population_growth/implementation/social_system.py +++ /dev/null @@ -1,87 +0,0 @@ -"""SocialSystem entity type mixing class template. - -TODO: adjust or fill in code and documentation wherever marked by "TODO:", -then remove these instructions -""" -# This file is part of pycopancore. -# -# Copyright (C) 2016-2017 by COPAN team at Potsdam Institute for Climate -# Impact Research -# -# URL: -# Contact: core@pik-potsdam.de -# License: BSD 2-clause license - -from .... import Explicit, ODE -from ...base import interface as B -from .... import master_data_model as D - -from .. import interface as I - -import sympy as sp # to be able to use sp.sqrt - - -# TODO: move this to a suitable place (like pycopancore.util?): -def sqrtorzero(expr): - """square root if positive, zero otherwise. - needed since ODE solver may pass negative values in Jacobian estimation""" - return sp.sqrt(sp.Max(0, expr)) - - -class SocialSystem (I.SocialSystem): - """SocialSystem entity type mixin implementation class.""" - - # abbreviations: - land_area = B.SocialSystem.sum.cells.land_area - terrestrial_carbon = B.SocialSystem.sum.cells.terrestrial_carbon - min_fert = B.SocialSystem.metabolism.min_fertility - fert_exp = B.SocialSystem.metabolism.fertility_decay_exponent - - pop = I.SocialSystem.population - - fert = (min_fert - + 2 * (B.SocialSystem.metabolism.max_fertility - min_fert) - * I.SocialSystem.wellbeing - * B.SocialSystem.metabolism.fertility_maximizing_wellbeing - ** fert_exp - / (I.SocialSystem.wellbeing ** (1 + fert_exp) - + B.SocialSystem.metabolism.fertility_maximizing_wellbeing - ** (1 + fert_exp) - ) - ) - - mort = (B.SocialSystem.metabolism.characteristic_mortality - / (I.SocialSystem.wellbeing - / B.SocialSystem.metabolism.fertility_maximizing_wellbeing) - ** B.SocialSystem.metabolism.mortality_decay_exponent - + I.SocialSystem.mortality_temperature_sensitivity - * (B.SocialSystem.world.surface_air_temperature - - I.SocialSystem.mortality_reference_temperature) - + B.SocialSystem.metabolism.population_spatial_competition_coefficient - * (I.SocialSystem.population / land_area) - / sp.sqrt(I.SocialSystem.physical_capital)) - - processes = [ - - Explicit("wellbeing, fertility, mortality, births, deaths", - [I.SocialSystem.wellbeing, - I.SocialSystem.fertility, - I.SocialSystem.mortality, - I.SocialSystem.births, - I.SocialSystem.deaths], - [B.SocialSystem.metabolism.wellbeing_sensitivity_to_consumption - * I.SocialSystem.consumption_flow / pop - + B.SocialSystem.metabolism.wellbeing_sensitivity_to_terrestrial_carbon - * terrestrial_carbon / land_area, - fert, - mort, - pop * fert, - pop * mort]), - - ODE("population dynamics", - [pop, - I.SocialSystem.migrant_population], - [I.SocialSystem.births - I.SocialSystem.deaths, - - I.SocialSystem.deaths * I.SocialSystem.migrant_population / pop]) - - ] diff --git a/pycopancore/model_components/copan_global_like_population_growth/interface.py b/pycopancore/model_components/copan_global_like_population_growth/interface.py deleted file mode 100644 index 14a35cbb..00000000 --- a/pycopancore/model_components/copan_global_like_population_growth/interface.py +++ /dev/null @@ -1,121 +0,0 @@ -"""model component Interface template. -""" - -# This file is part of pycopancore. -# -# Copyright (C) 2016-2017 by COPAN team at Potsdam Institute for Climate -# Impact Research -# -# URL: -# Contact: core@pik-potsdam.de -# License: BSD 2-clause license - -# TODO: use variables from the master data model wherever possible: -from ... import master_data_model as D -from ...data_model.master_data_model import MET, S -from ... import Variable - - -class Model (object): - """Interface for Model mixin.""" - - # metadata: - name = "copan:GLOBAL-like population growth" - """a unique name for the model component""" - description = "fertility and mortality act on SocialSystem level and depend on well-being" - """some longer description""" - requires = [] - """list of other model components required for this model component to - make sense""" - - # Notes: - # - Model does NOT define variables or parameters, only entity types - # and process taxons do! - # - implementation.Model lists these entity-types and process taxons - - -# entity types: - - -class SocialSystem (object): - """Interface for SocialSystem entity type mixin.""" - - # endogenous variables: - - population = S.population - population.default = 1 * D.people - - migrant_population = S.migrant_population - - wellbeing = S.wellbeing - wellbeing.default = 1 * D.utils / D.people / D.years - - fertility = S.fertility - mortality = S.mortality - mortality_temperature_sensitivity = S.mortality_temperature_sensitivity - mortality_reference_temperature = S.mortality_reference_temperature - - births = S.births - deaths = S.deaths - - # exogenous variables / parameters: - - physical_capital = S.physical_capital - consumption_flow = S.consumption_flow - - -# process taxa: - - -class Metabolism (object): - """Interface for Metabolism process taxon mixin.""" - - # endogenous variables: - - # exogenous variables / parameters: - min_fertility = MET.min_fertility - max_fertility = MET.max_fertility - fertility_maximizing_wellbeing = Variable( - "fertility-maximizing value of well-being", - "", - unit = D.utils / D.people / D.years, - lower_bound=0, is_intensive=True, - default=2000) - fertility_decay_exponent = Variable( - "exponent of power-law shaped asymptotic decay of fertility " - "for large wellbeing", "", - unit = D.unity, - strict_lower_bound=0, is_intensive=True, - default=1/2) - characteristic_mortality = Variable( - "characteristic mortality rate", - "mortality rate at fertility-maximizing value of well-being", - unit = D.years**-1, - lower_bound=0, is_intensive=True, - default=0.02) - mortality_decay_exponent = Variable( - "exponent of power-law shaped asymptotic decay of mortality " - "for large wellbeing", "", - unit = D.unity, - strict_lower_bound=0, is_intensive=True, - default=1/12) -# renewable_energy_knowledge_depreciation_rate = \ -# MET.renewable_energy_knowledge_depreciation_rate - population_spatial_competition_coefficient = Variable( - "coeff. of spatial competition in population dynamics", - "causes a capital- and well-being-dependent per-area population limit", - unit = D.dollars**0.5 / (D.people / D.square_kilometers) / D.years, - lower_bound=0, is_intensive=True, - default=0 # TODO: set properly - ) - wellbeing_sensitivity_to_consumption = Variable( - "sensitivity of wellbeing to per capita consumption flow", "", - is_intensive=True, allow_None=False, - default = 1 * D.utils / D.dollars) - wellbeing_sensitivity_to_terrestrial_carbon = Variable( - "sensitivity of wellbeing to terrestrial carbon density", "", - unit = (D.utils/D.people/D.years) - / (D.gigatonnes_carbon/D.square_kilometers), - is_intensive=True, allow_None=False, - default = 1e-8 * (2000*D.utils / D.people / D.years) - / (5500*D.gigatonnes_carbon / (1.5e8*D.square_kilometers))) diff --git a/pycopancore/model_components/copan_global_like_population_growth/model.py b/pycopancore/model_components/copan_global_like_population_growth/model.py deleted file mode 100644 index 8b28535f..00000000 --- a/pycopancore/model_components/copan_global_like_population_growth/model.py +++ /dev/null @@ -1,31 +0,0 @@ -"""Model mixing class template. - -TODO: adjust or fill in code and documentation wherever marked by "TODO:", -then remove these instructions -""" - -# This file is part of pycopancore. -# -# Copyright (C) 2016-2017 by COPAN team at Potsdam Institute for Climate -# Impact Research -# -# URL: -# Contact: core@pik-potsdam.de -# License: BSD 2-clause license - -from . import interface as I -# import all needed entity type implementation classes: -from .implementation import SocialSystem -# import all needed process taxon implementation classes: -from .implementation import Metabolism - - -class Model (I.Model): - """Model mixin class.""" - - # mixins provided by this model component: - - entity_types = [SocialSystem] - """list of entity types augmented by this component""" - process_taxa = [Metabolism] - """list of process taxa augmented by this component""" diff --git a/pycopancore/model_components/copan_global_like_production/__init__.py b/pycopancore/model_components/copan_global_like_production/__init__.py deleted file mode 100644 index 80076629..00000000 --- a/pycopancore/model_components/copan_global_like_production/__init__.py +++ /dev/null @@ -1,20 +0,0 @@ -""" -copan_global_like_economy model component -""" - -# This file is part of pycopancore. -# -# Copyright (C) 2016-2017 by COPAN team at Potsdam Institute for Climate -# Impact Research -# -# URL: -# Contact: core@pik-potsdam.de -# License: BSD 2-clause license - -from . import interface - -# export all implementation classes: -from .implementation import * - -# export model component mixin class: -from .model import Model diff --git a/pycopancore/model_components/copan_global_like_production/implementation/__init__.py b/pycopancore/model_components/copan_global_like_production/implementation/__init__.py deleted file mode 100644 index aad5cd43..00000000 --- a/pycopancore/model_components/copan_global_like_production/implementation/__init__.py +++ /dev/null @@ -1,22 +0,0 @@ -""" -Model component implementation subpackage template. -""" - -# This file is part of pycopancore. -# -# Copyright (C) 2016-2017 by COPAN team at Potsdam Institute for Climate -# Impact Research -# -# URL: -# Contact: core@pik-potsdam.de -# License: BSD 2-clause license - -# TODO: adjust the following lists to your needs: - -# export all provided entity type implementation mixin classes: -from .world import World -from .social_system import SocialSystem -from .cell import Cell - -# export all provided process taxon implementation mixin classes: -from .metabolism import Metabolism diff --git a/pycopancore/model_components/copan_global_like_production/implementation/cell.py b/pycopancore/model_components/copan_global_like_production/implementation/cell.py deleted file mode 100644 index 261ecc8b..00000000 --- a/pycopancore/model_components/copan_global_like_production/implementation/cell.py +++ /dev/null @@ -1,86 +0,0 @@ -"""Cell entity type mixing class template.""" - -# This file is part of pycopancore. -# -# Copyright (C) 2016-2017 by COPAN team at Potsdam Institute for Climate -# Impact Research -# -# URL: -# Contact: core@pik-potsdam.de -# License: BSD 2-clause license - -from .... import Explicit, ITE -from .... import master_data_model as D -from .. import interface as I -from ...base import interface as B -from sympy import Min, Max - - -# import numpy as np - - -class Cell (I.Cell): - """Cell entity type mixin implementation class.""" - - # TODO: allocate protected stock more adequately than this: - quotient = (B.Cell.social_system.protected_terrestrial_carbon - / B.Cell.social_system.sum.cells.terrestrial_carbon) - - unprotected_terrestrial_carbon_squared = ITE(quotient < 1, - (I.Cell.terrestrial_carbon * (1 - quotient))**2, - 0) #Min(1, quotient) - - processes = [ - - Explicit("sectoral relative productivities", - [I.Cell.biomass_relative_productivity, - I.Cell.fossil_relative_productivity, - I.Cell.renewable_relative_productivity], - [ - I.Cell.biomass_sector_productivity - # TODO: verify the following: - * ITE(B.Cell.social_system.has_emissions_tax > 0, - # FIXME: clarify why it does not work without the "> 0" above - ITE(quotient < 1, - (I.Cell.terrestrial_carbon * (1 - quotient))**2 - * (1 - - B.Cell.social_system.emissions_tax_level - * I.Cell.total_energy_intensity - / B.Cell.metabolism.biomass_energy_density), - 0), - unprotected_terrestrial_carbon_squared), - ITE(B.Cell.social_system.has_fossil_ban > 0, - 0, - I.Cell.fossil_sector_productivity - # TODO: verify the following: - * ITE(B.Cell.social_system.has_emissions_tax > 0, - (I.Cell.fossil_carbon - * (1 - B.Cell.social_system.protected_fossil_carbon_share) - )**2 * ( - 1 - - B.Cell.social_system.emissions_tax_level - * I.Cell.total_energy_intensity - / B.Cell.metabolism.fossil_energy_density), - (I.Cell.fossil_carbon - * (1 - B.Cell.social_system.protected_fossil_carbon_share) - )**2) - ), - I.Cell.renewable_sector_productivity - # TODO: verify the following: - * ITE(B.Cell.social_system.has_renewable_subsidy > 0, - (B.Cell.social_system.renewable_energy_knowledge)**2 * ( - 1 - + B.Cell.social_system.renewable_subsidy_level - * I.Cell.total_energy_intensity), - (B.Cell.social_system.renewable_energy_knowledge)**2) - ]), - - Explicit("total relative productivity", - [I.Cell.total_relative_productivity], - [ - Max(0, I.Cell.biomass_relative_productivity) - + Max(0, I.Cell.fossil_relative_productivity) - + Max(0, I.Cell.renewable_relative_productivity) - ]) - - ] diff --git a/pycopancore/model_components/copan_global_like_production/implementation/metabolism.py b/pycopancore/model_components/copan_global_like_production/implementation/metabolism.py deleted file mode 100644 index 14a41271..00000000 --- a/pycopancore/model_components/copan_global_like_production/implementation/metabolism.py +++ /dev/null @@ -1,20 +0,0 @@ -"""Metabolism process taxon mixin class.""" - -# This file is part of pycopancore. -# -# Copyright (C) 2016-2017 by COPAN team at Potsdam Institute for Climate -# Impact Research -# -# URL: -# Contact: core@pik-potsdam.de -# License: BSD 2-clause license - -from .. import interface as I - - -class Metabolism (I.Metabolism): - """Metabolism process taxon mixin implementation class.""" - - # standard methods: - - processes = [] diff --git a/pycopancore/model_components/copan_global_like_production/implementation/social_system.py b/pycopancore/model_components/copan_global_like_production/implementation/social_system.py deleted file mode 100644 index fee3a191..00000000 --- a/pycopancore/model_components/copan_global_like_production/implementation/social_system.py +++ /dev/null @@ -1,177 +0,0 @@ -"""SocialSystem entity type mixing class template. - -TODO: adjust or fill in code and documentation wherever marked by "TODO:", -then remove these instructions -""" -# This file is part of pycopancore. -# -# Copyright (C) 2016-2017 by COPAN team at Potsdam Institute for Climate -# Impact Research -# -# URL: -# Contact: core@pik-potsdam.de -# License: BSD 2-clause license - -from .... import Explicit, ODE -from .. import interface as I -from ...base import interface as B - -import numpy as np - - -class SocialSystem (I.SocialSystem): - """SocialSystem entity type mixin implementation class.""" - - - # process-related methods: - - def do_economic_production(self, unused_t): - """Do something. - - It needs to be described so other people want to use it. - Parameters - ---------- - unused_t - """ - # list of cells in some fixed order, so that we can use arrays below: - C = list(self.cells) - # collect cellwise input for energy subsectors: - intensity = np.array([c.total_energy_intensity for c in C]) - # use the copan:GLOBAL Leontieff/Cobb-Douglas nested production - # function: - relative_productivity = np.array([c.total_relative_productivity - for c in C]) - """an aggregate, production-function specific indicator""" - # distribute population and capital to cells so that wages and rents - # are equal across cells (efficient allocation): - if np.any(relative_productivity == np.inf): - # give equal prod. to those with inf relative prod.: - wh = np.where(relative_productivity < np.inf)[0] - relative_productivity[:] = 1 - relative_productivity[wh] = 0 - relative_weight = relative_productivity - total_relative_weight = sum(relative_weight) - else: - relative_weight = relative_productivity - total_relative_weight = sum(relative_weight) - if total_relative_weight == 0: - # unimportant since relative_weight == 0, just to avoid division error: - total_relative_weight = 1 - weight = relative_weight / total_relative_weight - P = weight * self.population - K = weight * self.physical_capital - # resulting cell-wise harvest, extraction and production: - denom = relative_productivity**0.8 - # unimportant since numerator is then 0, just to avoid division error: - denom[np.where(denom == 0)] = 1 - fac = (P * K)**0.4 / denom - if any(np.isnan(fac)): - w = np.where(np.isnan(fac))[0] -# print("fac",self.physical_capital,P[w],K[w],weight[w],relative_productivity[w],intensity[w]) - exit() - eB = self.metabolism.biomass_energy_density - eF = self.metabolism.fossil_energy_density - # TODO: FIX occurrence of intensity: - B = np.array([max(0, c.biomass_relative_productivity) for c in C]) * fac / eB - F = np.array([max(0, c.fossil_relative_productivity) for c in C]) * fac / eF - R = np.array([max(0, c.renewable_relative_productivity) for c in C]) * fac - E = eB * B + eF * F + R - Y = E / intensity - if any(Y < 0): - w = np.where(np.isnan(fac))[0] -# print("Y",P[w],K[w],weight[w],relative_productivity[w],intensity[w],E[w]) - exit() - - # tell cells what their harvest and extraction is: - for i in range(len(C)): - C[i].biomass_harvest_flow = B[i] - C[i].fossil_extraction_flow = F[i] - # store social_systems' total harvest and extraction, emissions, - # and production: - self.biomass_input_flow = sum(B) - self.fossil_fuel_input_flow = sum(F) - self.renewable_energy_input_flow = sum(R) - self.secondary_energy_flow = sum(E) - self.economic_output_flow = sum(Y) - self.carbon_emission_flow = \ - self.biomass_input_flow + self.fossil_fuel_input_flow - - def do_harvest_extraction_emissions(self, unused_t): - """Add carbon emission flow to world's athmospheric carbon. - - Parameters - ---------- - unused_t - """ - # this is an example of a process that is owned by SocialSystem - # but affects its cells and the world: - for c in self.cells: - c.d_terrestrial_carbon -= c.biomass_harvest_flow - c.d_fossil_carbon -= c.fossil_extraction_flow - self.world.d_atmospheric_carbon += self.carbon_emission_flow - - - # abbreviations: - - this = I.SocialSystem - met = B.SocialSystem.metabolism - cs = B.SocialSystem.cells - # distribute population and capital to cells so that wages and rents - # are equal across cells (efficient allocation): - relative_weight = cs.total_relative_productivity - total_relative_weight = B.SocialSystem.sum(relative_weight) - weight = relative_weight / total_relative_weight - P = weight * this.population - K = weight * this.physical_capital - # resulting cell-wise harvest, extraction and production: - intensity = cs.total_energy_intensity - denom = (cs.total_relative_productivity * intensity)**0.8 - fac = (P * K)**0.4 / denom - eB = met.biomass_energy_density - eF = met.fossil_energy_density - Bcell = cs.biomass_relative_productivity * fac / eB - Fcell = cs.fossil_relative_productivity * fac / eF - Rcell = cs.renewable_relative_productivity * fac - Ecell = eB * Bcell + eF * Fcell + Rcell - Ycell = Ecell / intensity - # societal aggregates: - Bsoc = B.SocialSystem.sum(Bcell) - Fsoc = B.SocialSystem.sum(Fcell) - Rsoc = B.SocialSystem.sum(Rcell) - Esoc = B.SocialSystem.sum(Ecell) - Ysoc = B.SocialSystem.sum(Ycell) - emissions = Bsoc + Fsoc - - processes = [ - - Explicit("economic production", - [B.SocialSystem.cells.biomass_harvest_flow, - B.SocialSystem.cells.fossil_extraction_flow, - I.SocialSystem.biomass_input_flow, - I.SocialSystem.fossil_fuel_input_flow, - I.SocialSystem.renewable_energy_input_flow, - I.SocialSystem.secondary_energy_flow, - I.SocialSystem.economic_output_flow, - I.SocialSystem.carbon_emission_flow], -# [Bcell, -# Fcell, -# Bsoc, -# Fsoc, -# Rsoc, -# Esoc, -# Ysoc, -# emissions -# ]), - do_economic_production), - - ODE("harvest, extraction, emissions", - [B.SocialSystem.cells.terrestrial_carbon, - B.SocialSystem.cells.fossil_carbon, - B.SocialSystem.world.atmospheric_carbon], -# [-Bcell, -# -Fcell, -# emissions -# ]) - do_harvest_extraction_emissions) - - ] diff --git a/pycopancore/model_components/copan_global_like_production/implementation/world.py b/pycopancore/model_components/copan_global_like_production/implementation/world.py deleted file mode 100644 index 7960a530..00000000 --- a/pycopancore/model_components/copan_global_like_production/implementation/world.py +++ /dev/null @@ -1,21 +0,0 @@ -"""World entity type mixing class template. - -TODO: adjust or fill in code and documentation wherever marked by "TODO:", -then remove these instructions -""" -# This file is part of pycopancore. -# -# Copyright (C) 2016-2017 by COPAN team at Potsdam Institute for Climate -# Impact Research -# -# URL: -# Contact: core@pik-potsdam.de -# License: BSD 2-clause license - -from .. import interface as I - - -class World (I.World): - """World entity type mixin implementation class.""" - - processes = [] \ No newline at end of file diff --git a/pycopancore/model_components/copan_global_like_production/interface.py b/pycopancore/model_components/copan_global_like_production/interface.py deleted file mode 100644 index 7aa69952..00000000 --- a/pycopancore/model_components/copan_global_like_production/interface.py +++ /dev/null @@ -1,146 +0,0 @@ -"""copan_global_like_production model component Interface.""" - -# This file is part of pycopancore. -# -# Copyright (C) 2016-2017 by COPAN team at Potsdam Institute for Climate -# Impact Research -# -# URL: -# Contact: core@pik-potsdam.de -# License: BSD 2-clause license - -from ... import master_data_model as D -from ...data_model.master_data_model import MET, W, S, C -from ... import Variable - - -class Model (object): - """Interface for Model mixin.""" - - # metadata: - name = "copan:GLOBAL-like economic production" - """a unique name for the model component""" - description = """Simple four-sector (three energy, one final) economy - as in copan:GLOBAL, but with cell-based harvesting of terrestrial - and extraction of fossil carbon and perfect allocation between cells. - Restriction: cannot deal with nested social_systems yet.""" - """some longer description""" - requires = [] - """list of other model components required for this model component to - make sense""" - - -# entity types: - - -class World (object): - """Interface for World mixin.""" - - # endogenous variables: - - atmospheric_carbon = W.atmospheric_carbon - - # exogenous variables / parameters: - - -class SocialSystem (object): - """Interface for SocialSystem entity type mixin.""" - - # pure output variables: - - biomass_input_flow = S.biomass_input_flow - fossil_fuel_input_flow = S.fossil_fuel_input_flow - renewable_energy_input_flow = S.renewable_energy_input_flow - secondary_energy_flow = S.secondary_energy_flow - carbon_emission_flow = S.carbon_emission_flow - economic_output_flow = S.economic_output_flow - - # exogenous variables / parameters: - - population = S.population - physical_capital = S.physical_capital - renewable_energy_knowledge = S.renewable_energy_knowledge - - protected_terrestrial_carbon = S.protected_terrestrial_carbon - protected_fossil_carbon = S.protected_fossil_carbon - protected_terrestrial_carbon_share = S.protected_terrestrial_carbon_share - protected_fossil_carbon_share = S.protected_fossil_carbon_share - - has_renewable_subsidy = S.has_renewable_subsidy - has_emissions_tax = S.has_emissions_tax - has_fossil_ban = S.has_fossil_ban - emissions_tax_level = S.emissions_tax_level - renewable_subsidy_level = S.renewable_subsidy_level - - -class Cell (object): - """Interface for Cell entity type mixin.""" - - # endogenous variables: - - terrestrial_carbon = C.terrestrial_carbon - fossil_carbon = C.fossil_carbon - - # pure output variables: - - biomass_relative_productivity = \ - Variable("biomass relative productivity", - "used to determine energy input", - unit=D.unity, - lower_bound=0, default=1) - - fossil_relative_productivity = \ - Variable("fossil relative productivity", - "used to determine energy input", - unit=D.unity, - lower_bound=0, default=1) - - renewable_relative_productivity = \ - Variable("renewable relative productivity", - "used to determine energy input", - unit=D.unity, - lower_bound=0, default=1) - - total_relative_productivity = \ - Variable("total relative productivity", - "used as weights in allocation of labour and capital", - unit=D.unity, - lower_bound=0, default=3) - - biomass_harvest_flow = C.biomass_harvest_flow - fossil_extraction_flow = C.fossil_extraction_flow - - # exogenous variables / parameters: - - biomass_sector_productivity = \ - Variable("biomass sector productivity", - "(Parameter aB in Nitzbon et al. 2017)", - unit = (D.gigajoules / D.years)**5 - / (D.gigatonnes_carbon * D.dollars * D.people)**2, - lower_bound=0, is_intensive=True, default=3e5) - fossil_sector_productivity = \ - Variable("fossil sector productivity", - "(Parameter aF in Nitzbon et al. 2017)", - unit = (D.gigajoules / D.years)**5 - / (D.gigatonnes_carbon * D.dollars * D.people)**2, - lower_bound=0, is_intensive=True, default=5e6) - renewable_sector_productivity = \ - Variable("renewable sector productivity", "", - unit = D.gigajoules**3 / D.years**5 - / (D.dollars * D.people)**2, - lower_bound=0, is_intensive=True, default=7e-18) - total_energy_intensity = C.total_energy_intensity - - -# process taxa: - - -class Metabolism (object): - """Interface for Metabolism process taxon mixin.""" - - # endogenous variables: - - biomass_energy_density = MET.biomass_energy_density - fossil_energy_density = MET.fossil_energy_density - - # exogenous variables / parameters: diff --git a/pycopancore/model_components/copan_global_like_production/model.py b/pycopancore/model_components/copan_global_like_production/model.py deleted file mode 100644 index 547812ea..00000000 --- a/pycopancore/model_components/copan_global_like_production/model.py +++ /dev/null @@ -1,25 +0,0 @@ -"""copan_global_like_economy model mixing class.""" - -# This file is part of pycopancore. -# -# Copyright (C) 2016-2017 by COPAN team at Potsdam Institute for Climate -# Impact Research -# -# URL: -# Contact: core@pik-potsdam.de -# License: BSD 2-clause license - -from . import interface as I -# import all needed entity type implementation classes: -from .implementation import World, SocialSystem, Cell -# import all needed process taxon implementation classes: -from .implementation import Metabolism - - -class Model (I.Model): - """Model mixin class.""" - - # mixins provided by this model component: - - entity_types = [World, SocialSystem, Cell] - process_taxa = [Metabolism] diff --git a/pycopancore/model_components/environmental_awareness/__init__.py b/pycopancore/model_components/environmental_awareness/__init__.py deleted file mode 100644 index c429726b..00000000 --- a/pycopancore/model_components/environmental_awareness/__init__.py +++ /dev/null @@ -1,20 +0,0 @@ -""" -Model component package template. -""" - -# This file is part of pycopancore. -# -# Copyright (C) 2016-2017 by COPAN team at Potsdam Institute for Climate -# Impact Research -# -# URL: -# Contact: core@pik-potsdam.de -# License: BSD 2-clause license - -from . import interface - -# export all implementation classes: -from .implementation import * - -# export model component mixin class: -from .model import Model diff --git a/pycopancore/model_components/environmental_awareness/implementation/__init__.py b/pycopancore/model_components/environmental_awareness/implementation/__init__.py deleted file mode 100644 index c09e5c02..00000000 --- a/pycopancore/model_components/environmental_awareness/implementation/__init__.py +++ /dev/null @@ -1,22 +0,0 @@ -""" -Model component implementation subpackage template. -""" - -# This file is part of pycopancore. -# -# Copyright (C) 2016-2017 by COPAN team at Potsdam Institute for Climate -# Impact Research -# -# URL: -# Contact: core@pik-potsdam.de -# License: BSD 2-clause license - -# TODO: adjust the following lists to your needs: - -# export all provided entity type implementation mixin classes: -from .social_system import SocialSystem -from .individual import Individual -from .cell import Cell - -# export all provided process taxon implementation mixin classes: -from .culture import Culture diff --git a/pycopancore/model_components/environmental_awareness/implementation/cell.py b/pycopancore/model_components/environmental_awareness/implementation/cell.py deleted file mode 100644 index e461b725..00000000 --- a/pycopancore/model_components/environmental_awareness/implementation/cell.py +++ /dev/null @@ -1,36 +0,0 @@ -"""Cell entity type mixing class template. - -TODO: adjust or fill in code and documentation wherever marked by "TODO:", -then remove these instructions -""" -# This file is part of pycopancore. -# -# Copyright (C) 2016-2017 by COPAN team at Potsdam Institute for Climate -# Impact Research -# -# URL: -# Contact: core@pik-potsdam.de -# License: BSD 2-clause license - -from .... import Explicit, ODE, ITE -from .. import interface as I -from ...base import interface as B - -class Cell (I.Cell): - """Cell entity type mixin implementation class.""" - - processes = [ - ODE("exponentially discounted running mean of carbon", - [I.Cell.mean_past_terrestrial_carbon], - [ITE(B.Cell.world.culture.terrestrial_carbon_averaging_time > 0, - (I.Cell.terrestrial_carbon - I.Cell.mean_past_terrestrial_carbon) - / B.Cell.world.culture.terrestrial_carbon_averaging_time, - 0) # if zero, then the Explicit process governs this variable - ]), - Explicit("infinitely fast discounted running mean of carbon", - [I.Cell.mean_past_terrestrial_carbon], - [ITE(B.Cell.world.culture.terrestrial_carbon_averaging_time > 0, - I.Cell.mean_past_terrestrial_carbon, # if nonzero, then the ODE process governs this variable - I.Cell.terrestrial_carbon) - ]) - ] diff --git a/pycopancore/model_components/environmental_awareness/implementation/culture.py b/pycopancore/model_components/environmental_awareness/implementation/culture.py deleted file mode 100644 index feb9fbfe..00000000 --- a/pycopancore/model_components/environmental_awareness/implementation/culture.py +++ /dev/null @@ -1,42 +0,0 @@ -"""Culture process taxon mixing class template. -""" - -# This file is part of pycopancore. -# -# Copyright (C) 2016-2017 by COPAN team at Potsdam Institute for Climate -# Impact Research -# -# URL: -# Contact: core@pik-potsdam.de -# License: BSD 2-clause license -from .... import Event -from .. import interface as I -from ...base import interface as B -from numpy import inf -from numpy.random import exponential, uniform - - -class Culture (I.Culture): - """Culture process taxon mixin implementation class.""" - - # process-related methods: - - def next_awareness_update_time(self, t): - """time of next awareness update""" - return (inf if self.awareness_update_rate == 0 - else t + exponential(1. / self.awareness_update_rate)) - - def update_individuals_awareness(self, t): - """let some individuals update their awareness""" - for w in self.worlds: - for i in w.individuals: - if uniform() < self.awareness_update_fraction: - i.update_awareness(t) - - processes = [ - Event("update individuals' awareness", - [B.Culture.worlds.individuals.is_environmentally_friendly], - ["time", - next_awareness_update_time, - update_individuals_awareness]) - ] diff --git a/pycopancore/model_components/environmental_awareness/implementation/individual.py b/pycopancore/model_components/environmental_awareness/implementation/individual.py deleted file mode 100644 index cd0357d4..00000000 --- a/pycopancore/model_components/environmental_awareness/implementation/individual.py +++ /dev/null @@ -1,34 +0,0 @@ -"""Individual entity type class template. - -TODO: adjust or fill in code and documentation wherever marked by "TODO:", -then remove these instructions -""" -# This file is part of pycopancore. -# -# Copyright (C) 2016-2017 by COPAN team at Potsdam Institute for Climate -# Impact Research -# -# URL: -# Contact: core@pik-potsdam.de -# License: BSD 2-clause license - -from .. import interface as I -from numpy.random import exponential - -class Individual (I.Individual): - """Individual entity type mixin implementation class.""" - - def update_awareness(self, unused_t): - """stochastically change awareness status depending on - terrestrial carbon density. - - This method is called by Culture's awareness updating process - """ - r = exponential() - density = self.cell.mean_past_terrestrial_carbon / self.cell.land_area - if r * self.culture.awareness_lower_carbon_density > density: - self.is_environmentally_friendly = True - elif r * self.culture.awareness_upper_carbon_density < density: - self.is_environmentally_friendly = False - - processes = [] diff --git a/pycopancore/model_components/environmental_awareness/implementation/social_system.py b/pycopancore/model_components/environmental_awareness/implementation/social_system.py deleted file mode 100644 index 084b4613..00000000 --- a/pycopancore/model_components/environmental_awareness/implementation/social_system.py +++ /dev/null @@ -1,38 +0,0 @@ -"""SocialSystem entity type mixing class template. - -TODO: adjust or fill in code and documentation wherever marked by "TODO:", -then remove these instructions -""" -# This file is part of pycopancore. -# -# Copyright (C) 2016-2017 by COPAN team at Potsdam Institute for Climate -# Impact Research -# -# URL: -# Contact: core@pik-potsdam.de -# License: BSD 2-clause license - -from .... import Explicit, ITE -from .. import interface as I -from ...base import interface as B - -# from .... import master_data_model as D - - -class SocialSystem (I.SocialSystem): - """SocialSystem entity type mixin implementation class.""" - - processes = [ - Explicit("biomass protection due to awareness", -# [I.SocialSystem.protected_terrestrial_carbon_share], -# [B.SocialSystem.culture.max_protected_terrestrial_carbon_share -# * B.SocialSystem.sum( -# ITE(B.SocialSystem.individuals.is_environmentally_friendly, -# B.SocialSystem.individuals.population_share, 0.0))] - [I.SocialSystem.protected_terrestrial_carbon], - [I.SocialSystem.max_protected_terrestrial_carbon - * B.SocialSystem.sum( - ITE(B.SocialSystem.individuals.is_environmentally_friendly, - B.SocialSystem.individuals.population_share, 0.0))] - ) - ] diff --git a/pycopancore/model_components/environmental_awareness/interface.py b/pycopancore/model_components/environmental_awareness/interface.py deleted file mode 100644 index b61cbb58..00000000 --- a/pycopancore/model_components/environmental_awareness/interface.py +++ /dev/null @@ -1,114 +0,0 @@ -"""model component Interface template. -""" - -# This file is part of pycopancore. -# -# Copyright (C) 2016-2017 by COPAN team at Potsdam Institute for Climate -# Impact Research -# -# URL: -# Contact: core@pik-potsdam.de -# License: BSD 2-clause license - -# TODO: use variables from the master data model wherever possible: -from ... import master_data_model as D -from ...data_model.master_data_model import CUL, I, S, C -from ... import Variable - - -class Model (object): - """Interface for Model mixin.""" - - # metadata: - name = "environmental awareness" - """a unique name for the model component""" - description = "Declining/growing terrestrial carbon increases likelihood" \ - "of individuals becoming environmentally friendly/careless" - """some longer description""" - requires = [] - """list of other model components required for this model component to - make sense""" - - -# entity types: - - -class SocialSystem (object): - """Interface for Individual entity type mixin.""" - - # endogenous variables: - protected_terrestrial_carbon = S.protected_terrestrial_carbon - protected_terrestrial_carbon_share = S.protected_terrestrial_carbon_share - - # exogenous variables / parameters: - max_protected_terrestrial_carbon = \ - Variable("maximal protected stock of terrestrial carbon", - """what stock of the current terrestrial carbon would be treated - as protected if population is environmentally friendly""", - unit=D.gigatonnes_carbon, lower_bound=0, - default=0) - - -class Individual (object): - """Interface for Individual entity type mixin.""" - - # endogenous variables: - is_environmentally_friendly = I.is_environmentally_friendly - - # exogenous variables / parameters: - - -# process taxa: - -class Culture (object): - """Interface for Culture process taxon mixin.""" - - # endogenous variables: - - # exogenous variables / parameters: - awareness_update_rate = \ - Variable("awareness update rate", - "rate at which a fraction of individuals update their " \ - "awareness", - unit=D.years**-1, lower_bound=0, default=1) - awareness_update_fraction = \ - Variable("awareness update fraction", - "fraction of individuals updating their awareness" \ - "simultaneously", - unit=D.unity, lower_bound=0, upper_bound=1, default=0.1) - awareness_lower_carbon_density = \ - Variable("awareness lower carbon density", - "characteristic value of terrestrial carbon density below which " \ - "individuals get more likely to become environmentally aware", - unit = D.gigatonnes_carbon / D.square_kilometers, - lower_bound=0, - default=1e-5) # ca. 2e-5 is the current global mean - awareness_upper_carbon_density = \ - Variable("awareness upper carbon density", - "characteristic value of terrestrial carbon density above which " \ - "individuals get more likely to become environmentally unaware", - unit = D.gigatonnes_carbon / D.square_kilometers, - lower_bound=0, - default=2e-5) # ca. 2e-5 is the current global mean - max_protected_terrestrial_carbon_share = \ - Variable("maximal protected share of terrestrial carbon", - """what share of the current terrestrial carbon would be treated - as protected if population is environmentally friendly""", - unit=D.unity, lower_bound=0, upper_bound=1, - default=0.5) # TODO: a plausible value? - - terrestrial_carbon_averaging_time = \ - Variable("terrestrial carbon averaging time", - """characteristic time for time-averaging of terrestrial carbon""", - unit=D.years, lower_bound=0, - default=0 # for backwards compatibility - ) - -class Cell (object): - - terrestrial_carbon = C.terrestrial_carbon - mean_past_terrestrial_carbon = \ - Variable("mean past terrestrial carbon", - "running exponentially discounted mean over 50 years", - unit=D.gigatonnes_carbon) - \ No newline at end of file diff --git a/pycopancore/model_components/environmental_awareness/model.py b/pycopancore/model_components/environmental_awareness/model.py deleted file mode 100644 index aa37131f..00000000 --- a/pycopancore/model_components/environmental_awareness/model.py +++ /dev/null @@ -1,28 +0,0 @@ -"""Model mixing class template. -""" - -# This file is part of pycopancore. -# -# Copyright (C) 2016-2017 by COPAN team at Potsdam Institute for Climate -# Impact Research -# -# URL: -# Contact: core@pik-potsdam.de -# License: BSD 2-clause license - -from . import interface as I -# import all needed entity type implementation classes: -from .implementation import SocialSystem, Individual, Cell -# import all needed process taxon implementation classes: -from .implementation import Culture - - -class Model (I.Model): - """Model mixin class.""" - - # mixins provided by this model component: - - entity_types = [SocialSystem, Individual, Cell] - """list of entity types augmented by this component""" - process_taxa = [Culture] - """list of process taxa augmented by this component""" diff --git a/pycopancore/model_components/exodus/__init__.py b/pycopancore/model_components/exodus/__init__.py deleted file mode 100644 index 6852092c..00000000 --- a/pycopancore/model_components/exodus/__init__.py +++ /dev/null @@ -1,26 +0,0 @@ -""" -Model component package template. - -TODO: -Copy this folder, rename it to the name of your model component, -then adjust or fill in code and documentation in all modules wherever marked by "TODO:", -finally remove these instructions. -See the model component development tutorial for details. -""" - -# This file is part of pycopancore. -# -# Copyright (C) 2016-2017 by COPAN team at Potsdam Institute for Climate -# Impact Research -# -# URL: -# Contact: core@pik-potsdam.de -# License: BSD 2-clause license - -from . import interface - -# export all implementation classes: -from .implementation import * - -# export model component mixin class: -from .model import Model diff --git a/pycopancore/model_components/exodus/implementation/__init__.py b/pycopancore/model_components/exodus/implementation/__init__.py deleted file mode 100644 index 42d65a79..00000000 --- a/pycopancore/model_components/exodus/implementation/__init__.py +++ /dev/null @@ -1,24 +0,0 @@ -""" -Model component implementation subpackage template. -""" - -# This file is part of pycopancore. -# -# Copyright (C) 2016-2017 by COPAN team at Potsdam Institute for Climate -# Impact Research -# -# URL: -# Contact: core@pik-potsdam.de -# License: BSD 2-clause license - -# TODO: adjust the following lists to your needs: - -# export all provided entity type implementation mixin classes: -from .world import World -from .social_system import SocialSystem -from .cell import Cell -from .individual import Individual - -# export all provided process taxon implementation mixin classes: -from .metabolism import Metabolism -from .culture import Culture diff --git a/pycopancore/model_components/exodus/implementation/cell.py b/pycopancore/model_components/exodus/implementation/cell.py deleted file mode 100644 index 4392798c..00000000 --- a/pycopancore/model_components/exodus/implementation/cell.py +++ /dev/null @@ -1,47 +0,0 @@ -"""Cell entity type mixing class template. - -TODO: adjust or fill in code and documentation wherever marked by "TODO:", -then remove these instructions -""" - -# This file is part of pycopancore. -# -# Copyright (C) 2016-2017 by COPAN team at Potsdam Institute for Climate -# Impact Research -# -# URL: -# Contact: core@pik-potsdam.de -# License: BSD 2-clause license - -from .. import interface as I -# from .... import master_data_model as D - - -class Cell (I.Cell): - """Cell entity type mixin implementation class.""" - - # standard methods: - - def __init__(self, - *, - characteristic=None, - average_precipitation=None, - **kwargs): - """Initialize an instance of Cell.""" - super().__init__(**kwargs) # must be the first line - self.characteristic = characteristic - self.average_precipitation = average_precipitation - - self.assert_valid() - - # assert that farmland is owned by county and city by municipality: - if self.characteristic == 'farmland': - assert self.social_system.municipality_like is False - if self.characteristic == 'city': - assert self.social_system.municipality_like is True - - # process-related methods: - - # TODO: add some if needed... - - processes = [] # TODO: instantiate and list process objects here diff --git a/pycopancore/model_components/exodus/implementation/culture.py b/pycopancore/model_components/exodus/implementation/culture.py deleted file mode 100644 index c13b9f57..00000000 --- a/pycopancore/model_components/exodus/implementation/culture.py +++ /dev/null @@ -1,103 +0,0 @@ -"""Culture process taxon mixing class template. - -TODO: adjust or fill in code and documentation wherever marked by "TODO:", -then remove these instructions -""" - -# This file is part of pycopancore. -# -# Copyright (C) 2016-2017 by COPAN team at Potsdam Institute for Climate -# Impact Research -# -# URL: -# Contact: core@pik-potsdam.de -# License: BSD 2-clause license - -from .. import interface as I -from pycopancore.model_components.base import interface as B -# from .... import master_data_model as D -from pycopancore import Explicit, Step -import networkx as nx -import community - - -class Culture (I.Culture): - """Culture process taxon mixin implementation class.""" - - def __init__(self, - *, - network_clustering=0, # this is stupid but necessary, plotting failes otherwise - fully_connected_network=True, # static network - **kwargs): - """Initialize the unique instance of Metabolism.""" - super().__init__(**kwargs) # must be the first line - - self.network_clustering = network_clustering - self.fully_connected_network = fully_connected_network - - def calculate_av_clustering(self, unused_t): - """Calculate clustering wih networkx.""" - # only if not fully connected: - if not self.fully_connected_network: - self.network_clustering = nx.average_clustering( - self.acquaintance_network) - - def calculate_partition(self, graph): - """Calculate the partition of the Graph using Louvain algo.""" - partition = community.best_partition(graph) - return partition - - def calculate_modularity(self, unused_t): - """Calculate modularity from partition.""" - # only if not fully connected: - if not self.fully_connected_network: - shallow_network = nx.from_scipy_sparse_matrix( - nx.adjacency_matrix(self.acquaintance_network)) - partition = self.calculate_partition(shallow_network) - self.modularity = community.modularity( - partition, - shallow_network) - # print('modularity: ', self.modularity) - - def modularity_timing(self, t): - """Timing for step process to calculate modularity.""" - # only if not fully connected: - if not self.fully_connected_network: - return t + 1 - else: - return t + 1000 # just a high number, so it doesnt happen... - - def calculate_transitivity(self, unused_t): - """Calculate the transitivity of the network""" - # only if not fully connected: - if not self.fully_connected_network: - self.transitivity = nx.transitivity(self.acquaintance_network) - - def check_for_split(self): - """Check if network has split into to groups.""" - # Iterate through all individuals and see if they know someone from - # another profession: - connection = False - for ind in self.acquaintance_network: - for acq in ind.acquaintances: - if ind.profession != acq.profession: - # if one has another profession, the split has not - # taken place: - connection = True - break - self.split = False - if connection is False: - self.split = True - return self.split - - processes = [ - Explicit("calculate average clustering", - [I.Culture.network_clustering], - calculate_av_clustering), - Step("Calculate Modularity", - [I.Culture.modularity], - [modularity_timing, calculate_modularity]), - Step("Calculate Transitivity", - [I.Culture.transitivity], - [modularity_timing, calculate_transitivity]) - ] # TODO: instantiate and list process objects here diff --git a/pycopancore/model_components/exodus/implementation/individual.py b/pycopancore/model_components/exodus/implementation/individual.py deleted file mode 100644 index 231f66c2..00000000 --- a/pycopancore/model_components/exodus/implementation/individual.py +++ /dev/null @@ -1,349 +0,0 @@ -"""Individual entity type class template. - -TODO: adjust or fill in code and documentation wherever marked by "TODO:", -then remove these instructions -""" - -# This file is part of pycopancore. -# -# Copyright (C) 2016-2017 by COPAN team at Potsdam Institute for Climate -# Impact Research -# -# URL: -# Contact: core@pik-potsdam.de -# License: BSD 2-clause license - -from .. import interface as I -from pycopancore.model_components.base import interface as B -from pycopancore import Event, Explicit -import math -import random -import numpy as np -from scipy import stats - - -class Individual (I.Individual): - """Individual entity type mixin implementation class.""" - - # standard methods: - - def __init__(self, - *, - profession=None, - nutrition_need=1240, - liquidity=None, - nutrition=None, - second_degree_rewire_prob=0.3, - outspokenness=None, - random_rewire=0.05, - farm_size=None, - gross_income=None, - **kwargs): - """Initialize an instance of Cell.""" - super().__init__(**kwargs) # must be the first line - self.profession = profession - self.nutrition_need = nutrition_need - self.second_degree_rewire_prob = second_degree_rewire_prob - self.outspokenness = outspokenness - self.random_rewire = random_rewire - self.gross_income = gross_income - self.farm_size = farm_size - self.liquidity = liquidity - self.nutrition = nutrition - - if self.profession == 'farmer': - assert self.cell.characteristic == 'farmland' - if self.profession == 'townsman': - assert self.cell.characteristic == 'city' - - def calc_farm_size(self): - """Get the farm size.""" - # Check, if not already been calculated: - if self.farm_size is None: - # If townsman, individual has no farm: - if self.social_system.municipality_like is True: - self.farm_size = 0 - # If farmer, distribute farm size: - if self.social_system.municipality_like is False: - # Let social_system distribute farm size - self.farm_size = self.social_system.calc_gross_income_or_farmsize() - # return self.farm_size - - def calc_gross_income(self): - """Get the gross income.""" - # Check if not already been calculated: - if self.gross_income is None: - # Check if farmer or townsman: - if self.social_system.municipality_like is True: - # Let social_system distribute income: - self.gross_income = self.social_system.calc_gross_income_or_farmsize() - # If not townsman, income = 0 - if self.social_system.municipality_like is False: - self.gross_income = 0 - # return self.gross_income - - # process-related methods: - def social_update_timer(self, t): - """Calculate when a social update takes place""" - return t + np.random.exponential(self.outspokenness) - # outspokenness = 1 means in average once a year, 0.1 = 10 times a year, - # 10 means once every 10 years in average. - - def social_update(self, unused_t): - """Do social update. - - Either migration or de- and re-friending takes place. - In case of a fully connected network only migration takes place. - """ - # Set Flag to prevent agents from migrating twice when continuos - # exploration is True: - migrated = False - # First: determine if fully connected network: - if self.culture.fully_connected_network: - # First check if continuos exploration is turned on: - if self.social_system.continuous_exploration: - # define threshold for noise: - if random.random() < 0.05: - # Do exploration -> Move to any cell/social system - ss = random.sample(self.world.social_systems, 1)[0] - # Get the social systems cell (cells is a set) - print(ss) - for cell in ss.cells: - new_cell = cell - # If social system is idle/deactivated: - if ss.__class__.idle_entities and \ - ss in ss.__class__.idle_entities: - # reactivate it: - ss.reactivate() - self.migrate(new_cell) - migrated = True - - # Network is fully connected: - chosen_one = random.choice(self.culture.acquaintance_network.nodes()) - # Add event to social systems migration counter: - self.social_system.migration_counter[0] += 1 - self.social_system.migration_counter[1].append( - chosen_one.social_system) - if self.decide_migration(chosen_one) and not migrated: - # in case of preferential migration, checks are done - if self.preferential_migration: - # Add successful event to migration counter: - self.social_system.migration_counter[2].append( - chosen_one.social_system) - self.preferential_migrate(chosen_one.cell) - else: - # Add successful event to migration counter: - self.social_system.migration_counter[2].append( - chosen_one.social_system) - # Migrate - self.migrate(chosen_one.cell) - - else: # Not fully connected: - # Chose Acquaintance, if existent: - if self.acquaintances: - chosen_one = random.choice(self.acquaintances) - # Get the Chosen One's Profession: - chosen_profession = chosen_one.profession - # Check, whether same profession, therefore define - # if migration or rewiring takes place or nothing - if chosen_profession != self.profession: - # Compare utility and decide if migration takes place: - if self.decide_migration(chosen_one): - # Migrate - self.migrate(chosen_one.cell) - else: - self.rewire(chosen_one) - if (chosen_profession == self.profession - and random.random() <= self.random_rewire): - # Noise: Rewire to a random individual - random_guy = random.choice(tuple(self.world.individuals)) - if (random_guy not in self.acquaintances): - # Add edge: - self.culture.acquaintance_network.add_edge(self, random_guy) - # remove old edge: - self.culture.acquaintance_network.remove_edge(self, - chosen_one) - - def decide_migration(self, neighbour): - """Decide, if rewire or migration takes place. - - Parameters - ---------- - neighbour: exodus.individual - Object of type individual that has different profession than the - self object. - - Returns - ------- - bool: - True if migration takes place - """ - # If last one standing is active, check if there are more than one - # agent in the social system: - if self.social_system.last_one_standing: - if self.social_system.population == 1: - return False - # Difference in utility: - delta_utility = neighbour.utility - self.utility - # print('delta util', delta_utility) - # Tanh function: - tanh = 0.5 * (1 + math.tanh(delta_utility / 2)) - if random.random() <= tanh: - # Migrate if enough liquidity - if self.liquidity > neighbour.social_system.migration_cost: - # Next line is causing liquidities to drop below 0 if the - # social_system update takes place: - # self.liquidity -= neighbour.social_system.migration_cost - return True - else: - # Not enough money to migrate - return False - else: - # Rewire - return False - - def rewire(self, neighbour): - """Do rewiring. - - Detaches from neighbour and rewires to a neighbour of degree n. - This process is only used, if the network is not static! - Parameters. - ---------- - neighbour: exodus.individual - neighbour from which to detach - """ - # Remove edge: - self.culture.acquaintance_network.remove_edge(self, neighbour) - # Chose another random neighbour - # Check if individuals has acquaintances: - if not self.acquaintances: - # If so, connect to random one in model: - random_one = random.choice(tuple(self.world.individuals)) - self.culture.acquaintance_network.add_edge(self, random_one) - random_neighbour = random.choice(self.acquaintances) - third_degree_neighbors = [] - break_cond = False - # Iterate through second degree neighbours of random neighbour: - for n in random_neighbour.acquaintances: - # Attach with second_degree_rewire_prob, if not already connected - # or if not just detached: - if (random.random() < self.second_degree_rewire_prob - and n != neighbour - and n not in self.acquaintances): - self.culture.acquaintance_network.add_edge(self, n) - break_cond = True - break - # If rewiring did not take place, add his neighbours to third - # degree neighbour list: - if (n != neighbour - and n not in self.acquaintances): - for nn in n.acquaintances: - third_degree_neighbors.append(nn) - # Iterate through 3 degree neighbours, if ne neighbour was not found: - if break_cond is False: - for n in third_degree_neighbors: - # Attach with second_degree_rewire_prob^2, if not already - # connected or if not just detached: - if (random.random() < (self.second_degree_rewire_prob**2) - and n != neighbour - and n not in self.acquaintances): - self.culture.acquaintance_network.add_edge(self, n) - break_cond = True - break - # if nobody has connected yet, chose any random individual: - if break_cond is False: - # tuple is necessary since self.world.individuals is a set, - # therefore random.choice alone does not work! - random_guy = random.choice(tuple(self.world.individuals)) - if (random_guy != neighbour - and random_guy not in self.acquaintances): - self.culture.acquaintance_network.add_edge(self, random_guy) - else: - print('this is very unlikely, nobody has been found, ' - 'individual loses a connection.') - - def preferential_migrate(self, cell): - """Calls migragte in case of preferential migration.""" - # 3 cases: city-city, farmland-farmland, city-farmland/vice versa - # first, check city-city - if (self.cell.social_system.municipality_like and - cell.social_system.municipality_like): - if random.random() < 0.2: # need of number that makes sense - self.migrate(cell) - # second, check farmlad farmland - elif (not self.cell.social_system.municipality_like and - not cell.social_system.municipality_like): - if random.random() < 0.2: # need of number that makes sense - self.migrate(cell) - # third: check city-farmland/farmland-city - else: - # check if neighbours - if ((cell.location[0] ^ self.cell.location[0]) - ^ (cell.location[1] ^ self.cell.location[1])): - # cells are neighbouring - if random.random() < 1: - self.migrate(cell) - - def migrate(self, cell): - """Migrate to Cell. - - Parameters - ---------- - cell: exodus.cell - cell to migrate to. - """ - # Change cell and social_system (done in base.individual): - self.cell = cell - # Change Profession: - if cell.social_system.municipality_like is False: - self.profession = 'farmer' - elif cell.social_system.municipality_like is True: - self.profession = 'townsman' - else: - raise TypeError('Neither Municipality nor County!') - # Set Values to None, so they can be recalculated: - self.farm_size = None - self.gross_income = None - self.calc_gross_income() - self.calc_farm_size() - - def calculate_harvest(self, unused_t): - """Calculate the harvest of an Individual.""" - self.harvest = self.farm_size * self.cell.average_precipitation * 1000000 - - def calculate_utility(self, unused_t): - """Calculate utility if an Individual.""" - try: - self.utility = math.sqrt( - self.liquidity * self.nutrition - / self.social_system.average_liquidity / 1240) - # 1240 m^3 is the annual need, maybe need to incorporate it - # The folloeing should not happen but do so on the cluster: - except ValueError: - print('liquidity could not be calculated! Setting it to 0') - print(self.liquidity, self.nutrition, - self.social_system.average_liquidity) - self.utility = 0 - except TypeError: - print('liquidity could not be calculated! Setting it to 0') - print(self.liquidity, self.nutrition, - self.social_system.average_liquidity) - self.utility = 0 - - processes = [ - Event("social update", - [B.Individual.social_system, - # B.Individual.culture.acquaintance_network TOO BIG TO SAVE! - I.Individual.farm_size, - I.Individual.gross_income, - I.Individual.liquidity, - B.Individual.social_system.migration_counter - ], - ["time", social_update_timer, social_update]), - Explicit("Calculate harvest", - [I.Individual.harvest], - calculate_harvest), - Explicit("Calculate Utility", - [I.Individual.utility], - calculate_utility) - ] # TODO: instantiate and list process objects here diff --git a/pycopancore/model_components/exodus/implementation/metabolism.py b/pycopancore/model_components/exodus/implementation/metabolism.py deleted file mode 100644 index e6dfc59f..00000000 --- a/pycopancore/model_components/exodus/implementation/metabolism.py +++ /dev/null @@ -1,108 +0,0 @@ -"""Metabolism process taxon mixin class template. - -TODO: adjust or fill in code and documentation wherever marked by "TODO:", -then remove these instructions -""" - -# This file is part of pycopancore. -# -# Copyright (C) 2016-2017 by COPAN team at Potsdam Institute for Climate -# Impact Research -# -# URL: -# Contact: core@pik-potsdam.de -# License: BSD 2-clause license - -from .. import interface as I -from pycopancore.model_components.base import interface as B -from pycopancore import Step, Explicit - -from scipy import optimize -import numpy as np -import math - - -class Metabolism (I.Metabolism): - """Metabolism process taxon mixin implementation class.""" - - # standard methods: - - def __init__(self, - *, - market_frequency=1, - **kwargs): - """Initialize the unique instance of Metabolism.""" - super().__init__(**kwargs) # must be the first line - - self.market_frequency = market_frequency - - # At last, check for validity of all variables that have been - # initialized and given a value: - - # Following method is defined in abstract_process_taxon_mixin which is - # inherited only by mixing in the model: - self.assert_valid() - - @property - def total_gross_income(self): - """Get the total gross income.""" - # Chose a world as world. When having several, this must be changed! - for w in self.worlds: - world = w - break - tgi = 0 - for individual in world.individuals: - tgi += individual.gross_income - return tgi - - # process-related methods: - - def do_market_clearing(self, unused_t): - """Calculate water price and market movements.""" - print('market clearing takes place at time', unused_t) - # Iterate through worlds - for w in self.worlds: - world = w - w.calc_total_harvest(unused_t) - w.calc_total_gross_income(unused_t) - price = world.water_price = w.total_gross_income / w.total_harvest - for ind in w.individuals: - ind.nutrition = (ind.gross_income + price * ind.harvest) / ( - 2 * price) - ind.liquidity = (ind.gross_income + price * ind.harvest) / 2 - w.calc_total_nutrition(unused_t) - w.calc_total_liquidity(unused_t) - tgi = world.total_gross_income - th = world.total_harvest - tn = world.total_nutrition - tl = world.total_liquidity - print('market clearing is done at time', unused_t, - 'price is now at', world.water_price) - # Break condition if suppy and demand are not equal: - if round(tn) != round(th): - print('Market clearing failed') - print('nutrition - harvest', tn - th, - 'income - liquidity', tgi-tl) - self.non_equilibrium_checker = True - - def market_timing(self, t): - """Define how often market clearing takes place.""" - return t + 1 / self.market_frequency - - def check_for_market_equilibrium(self): - """Check if the market equilibrium is still in order.""" - if self.non_equilibrium_checker is True: - return self.non_equilibrium_checker - else: - return False - - processes = [ - Step("market clearing", - [B.Metabolism.worlds.individuals.liquidity, - B.Metabolism.worlds.water_price, - B.Metabolism.worlds.individuals.nutrition - ], - [market_timing, - do_market_clearing] - ) - ] # TODO: instantiate and list process objects here diff --git a/pycopancore/model_components/exodus/implementation/social_system.py b/pycopancore/model_components/exodus/implementation/social_system.py deleted file mode 100644 index 88500bb1..00000000 --- a/pycopancore/model_components/exodus/implementation/social_system.py +++ /dev/null @@ -1,282 +0,0 @@ -"""SocialSystem entity type mixing class template. - -TODO: adjust or fill in code and documentation wherever marked by "TODO:", -then remove these instructions -""" - -# This file is part of pycopancore. -# -# Copyright (C) 2016-2017 by COPAN team at Potsdam Institute for Climate -# Impact Research -# -# URL: -# Contact: core@pik-potsdam.de -# License: BSD 2-clause license - -from .. import interface as I -from pycopancore.model_components.base import interface as B -from pycopancore import Explicit, Step -# from .... import master_data_model as D - -from scipy import stats -import numpy as np -import math -import random - - -class SocialSystem (I.SocialSystem): - """SocialSystem entity type mixin implementation class.""" - - # standard methods: - - def __init__(self, - *, - municipality_like=False, - base_mean_income=1000, - pdf_sigma=0.34, # 0.34 taken from Clementi, Gallegati 2005 for income distribution - scaling_parameter=1.12, # taken from Bettencourt paper - migration_cost=1000, - last_one_standing=False, # measures to ensure ergodicity - continuous_exploration=False, # kind of a noise term - **kwargs): - """Initialize an instance of SocialSystem.""" - super().__init__(**kwargs) # must be the first line - - self.municipality_like = municipality_like - self.base_mean_income = base_mean_income - self.pdf_sigma = pdf_sigma - self.scaling_parameter = scaling_parameter - self.migration_cost = migration_cost - self.migration_counter = [0, [], []] - self.last_one_standing = last_one_standing - self.continuous_exploration = continuous_exploration - # Initializing self.migration_rates list with length of number of - # social systems not possibble here, since not all social systems - # are initialized yet. - - def calc_gross_income_or_farmsize(self): - "Get random income or farm size distributed log-normal." - - # Use log-normal - number = random.random() - sigma = self.pdf_sigma - # calculate ´median from mean: - median = (self.mean_income_or_farmsize / np.exp(sigma**2 / 2)) - lognormal_random = stats.lognorm.ppf(number, s=sigma, scale=median) - return lognormal_random - - def calc_population(self, unused_t): - """Calculate the social_systems population explicitly. - - Parameters - ---------- - unused_t - """ - if len(self.individuals) == 0: - self.deactivate() - print(f'social_system {self} died out at time {unused_t}') - # to prevent division by zero: - self.population = 1 - else: - self.population = len(self.individuals) - - def update_incomes(self): - """Update incomes to adjust to population in some manner.""" - # first: Check if really a municipaity: - if self.municipality_like is not True: - raise SocialSystemTypeError('SocialSystem not a municipality') - # Define factor how fast adjusting takes place - factor = 0.5 - sum = 0 - for ind in self.individuals: - sum += ind.gross_income - # Now divide by number of individuals to get mean: - real_mean = sum / self.population - adaption_rate = self.mean_income_or_farmsize / real_mean - adaption = adaption_rate + (1 - adaption_rate) * factor - for ind in self.individuals: - ind.gross_income *= adaption - - def update_farmsizes(self): - """Update farmsizes to adjust to population.""" - # first: Check if really a county: - if self.municipality_like is not False: - raise SocialSystemTypeError('SocialSystem not a county') - # Define factor how fast adjusting takes place - factor = 0.5 - sum = 0 - for ind in self.individuals: - sum += ind.farm_size - # Now divide by number of individuals to get mean: - real_mean = sum / self.population - adaption_rate = self.mean_income_or_farmsize / real_mean - adaption = adaption_rate + (1 - adaption_rate) * factor - for ind in self.individuals: - ind.farm_size *= adaption - - def update_timing(self, t): - """Decide how often income and farm size are adjusted.""" - return t + 1 - - def do_update(self, unused_t): - """Do the adjustment of income or farmsize""" - if self.is_active: - if self.municipality_like is True: - self.update_incomes() - print('incomes updated of social_system', self) - elif self.municipality_like is False: - self.update_farmsizes() - print('farmsizes updated of social_system', self) - else: - raise SocialSystemTypeError('Neither County nor Municipality!') - - def calculate_mean_income_or_farmsize(self, unused_t): - """Calculate mean income (if municipality) or farm size (county).""" - if self.is_active: - if self.municipality_like: - # in case of municipality - total_income = self.base_mean_income * ( - self.population**self.scaling_parameter) - self.mean_income_or_farmsize = total_income / self.population - if not self.municipality_like: - # in case of county - for c in self.direct_cells: - # mean farm size: - self.mean_income_or_farmsize = c.land_area / self.population - - def calculate_average_liquidity(self, unused_t): - """Calculate average liquidity of social_system.""" - if self.is_active: - sum = 0 - for ind in self.individuals: - sum += ind.liquidity - self.average_liquidity = sum / self.population - else: - # This should not happen, but apparently does nevertheless... - self.average_liquidity = 1 - - def calculate_average_utility(self, unused_t): - """Calculate the average utility in this social_system.""" - if self.is_active: - summe = 0 - for ind in self.individuals: - summe += ind.utility - self.average_utility = summe / self.population - - def calculate_gini(self, unused_t): - """Calculate the gini coefficient of the utility. - - This is using the Relative mean absolute difference: - https://en.wikipedia.org/wiki/Mean_absolute_difference#Relative_mean_absolute_difference - """ - # Mean absolute difference - if self.is_active: - utilities = [] - for ind in self.individuals: - utilities.append(ind.utility) - mad = np.abs(np.subtract.outer(utilities, utilities)).mean() - # Relative mean absolute difference - rmad = mad / np.mean(utilities) - # Gini coefficient - self.gini_coefficient = 0.5 * rmad - - def calculate_migration_rate(self, unused_t): - """Calculate migration rates""" - # First time this is called, a list of length of number of social - # systems is generated: - if self.migration_rates is None: - self.migration_rates = [0] * len(self.world.social_systems) - - # Every time this is called, this list needs to be reset: - for i in range(len(self.migration_rates)): - self.migration_rates[i] = 0 - # The two above steps are not performed as one, since some social - # systems might be deactivated during run, resulting in a new length - # for the list. - - # Now copy this list for theoretical migration rates: - self.theoretical_mig_rate = list(self.migration_rates) - if self.is_active: - # print(self.migration_counter) - tot_tries = self.migration_counter[0] # total number of tries - mig_attempts = self.migration_counter[1] # list of social systems where attempted - mig_moves = self.migration_counter[2] # list of social system where success - - # for the following to work, it is important, that we know the - # smallest uid of the social systems and all other social systems - # have following uids! - min_uid = min(ss._uid for ss in self.world.social_systems) - # attempted moves: - attempt_list = self.migration_rates.copy() - for element in mig_attempts: - for i, soc in enumerate(attempt_list): - # since uids start with min_uid, we need to add it: - if str(element).endswith(str(i+min_uid)+']'): - attempt_list[i] += 1 - - # successful moves: - for element in mig_moves: - for i, soc in enumerate(self.migration_rates): - # print(i) - # since uids start with min_uid, we need to add it: - if element._uid == i+min_uid: - self.migration_rates[i] += 1 - # Now divide success by attempts - for i, el in enumerate(self.migration_rates): - try: - self.migration_rates[i] = self.migration_rates[i] - # If probability is needed, following is needed: - # self.migration_rates[i] = (self.migration_rates[i] - # / attempt_list[i]) - except ZeroDivisionError: - # Both entries 0 - self.migration_rates[i] = 0 - - # Theoretical Calculation: - for ss in self.world.social_systems: - # Put in values according to the uids. Since uids start with - # min_uid, we have to account for that by subtracting it: - self.theoretical_mig_rate[(ss._uid-min_uid)] = (1/2 + ( - math.sqrt(ss.average_liquidity) - - math.sqrt(self.average_liquidity))/(4 * math.sqrt( - self.world.water_price * 1240))) * attempt_list[(ss._uid-min_uid)] - # if probability is wanted, leave out * attempt_list[(ss._uid-min_uid)] - # 1240 is the water need, also set in Individual.calculate_utility - # print(self.migration_rates, self.theoretical_mig_rate) - # reset migration counter for next step: - self.migration_counter = [0, [], []] - #print(self.migration_counter) - - processes = [ - Explicit('calculate population', - [B.SocialSystem.population, - # Following is only done to determine if soc is a city or - # not afterwards, since this is not saved otherwise: - I.SocialSystem.municipality_like], - calc_population), - Explicit('calculate mean income or farmsize', - [I.SocialSystem.mean_income_or_farmsize], - calculate_mean_income_or_farmsize), - Explicit("Calculate average liquidities", - [I.SocialSystem.average_liquidity], - calculate_average_liquidity), - Explicit("Calculate average utilities", - [I.SocialSystem.average_utility], - calculate_average_utility), - Explicit("Calculate gini", - [I.SocialSystem.gini_coefficient], - calculate_gini), - Step("Calculate Migration Rates", - [I.SocialSystem.migration_rates, - I.SocialSystem.theoretical_mig_rate], - [update_timing, calculate_migration_rate]), - Step("Update incomes/farmsizes", - [B.SocialSystem.individuals.farm_size, - B.SocialSystem.individuals.gross_income], - [update_timing, do_update]) - ] - - -class SocialSystemTypeError(Exception): - """Error Class if wrong type of social_system.""" - pass diff --git a/pycopancore/model_components/exodus/implementation/world.py b/pycopancore/model_components/exodus/implementation/world.py deleted file mode 100644 index 5d1e31b7..00000000 --- a/pycopancore/model_components/exodus/implementation/world.py +++ /dev/null @@ -1,102 +0,0 @@ -"""World entity type mixing class template. - -TODO: adjust or fill in code and documentation wherever marked by "TODO:", -then remove these instructions -""" - -# This file is part of pycopancore. -# -# Copyright (C) 2016-2017 by COPAN team at Potsdam Institute for Climate -# Impact Research -# -# URL: -# Contact: core@pik-potsdam.de -# License: BSD 2-clause license - -from .. import interface as I -from pycopancore.model_components.base import interface as B -import numpy -from pycopancore import Explicit -# from .... import master_data_model as D - - -class World (I.World): - """World entity type mixin implementation class.""" - - # standard methods: - - def __init__(self, - *, - water_price, - **kwargs): - """Initialize an instance of World.""" - super().__init__(**kwargs) # must be the first line - - self.water_price = water_price - # At last, check for validity of all variables that have been - # initialized and given a value: - - # Following method is defined in abstract_entity_mixin which is - # inherited only by mixing in the model: - self.assert_valid() - - def calc_total_gross_income(self, unused_t): - """Calculate total gross income explicitly.""" - tgi = 0 - for individual in self.individuals: - tgi += individual.gross_income - self.total_gross_income = tgi - - def calc_total_harvest(self, unused_t): - """Calculate total harves exlicitly""" - th = 0 - for individual in self.individuals: - th += individual.harvest - self.total_harvest = th - - def calc_total_nutrition(self, unused_t): - """Calculate total nutrition explicitly.""" - """Get the total nutrition.""" - tn = 0 - for individual in self.individuals: - # print(individual.nutrition) - tn += individual.nutrition - if numpy.isnan(tn): - self.exception_checker = True - # raise BaseException('some individuals nutrition is nan!') - print('some individuals nutrition is nan!') - self.total_nutrition = tn - - def calc_total_liquidity(self, unused_t): - """Calculate total liquidity explicitly.""" - tl = 0 - for individual in self.individuals: - # print(individual.liquidity) - tl += individual.liquidity - if numpy.isnan(tl): - self.exception_checker = True - # raise BaseException('some individuals liquidity is nan!') - print('some individuals nutrition is nan!') - self.total_liquidity = tl - - def check_for_exceptions(self): - """Check if the market equilibrium is still in order.""" - if self.exception_checker is True: - return self.exception_checker - else: - return False - - processes = [ - Explicit('calculate total gross income', - [I.World.total_gross_income], - calc_total_gross_income), - Explicit('calculate total harvest', - [I.World.total_harvest], - calc_total_harvest), - Explicit('calculate total nutrition', - [I.World.total_nutrition], - calc_total_nutrition), - Explicit('calculate total liquidity', - [I.World.total_liquidity], - calc_total_liquidity) - ] diff --git a/pycopancore/model_components/exodus/interface.py b/pycopancore/model_components/exodus/interface.py deleted file mode 100644 index 1aabc778..00000000 --- a/pycopancore/model_components/exodus/interface.py +++ /dev/null @@ -1,260 +0,0 @@ -"""model component Interface template. - -TODO: adjust or fill in code and documentation wherever marked by "TODO:", then -remove these instructions. -""" - -# This file is part of pycopancore. -# -# Copyright (C) 2016-2017 by COPAN team at Potsdam Institute for Climate -# Impact Research -# -# URL: -# Contact: core@pik-potsdam.de -# License: BSD 2-clause license - -from ... import master_data_model as D -from ... import Variable - - -class Model (object): - """Interface for Model mixin.""" - - # metadata: - name = "Exodus" - description = "..." - """A migration model in the urban rural space.""" - requires = [] - """list of other model components required for this model component to - make sense""" - - # Notes: - # - Model does NOT define variables or parameters, only entity types - # and process taxons do! - # - implementation.Model lists these entity-types and process taxons - - -# entity types: - - -class World (object): - """Interface for World mixin.""" - - total_gross_income = Variable("total gross income", - "Total income generated in the world.", - lower_bound=0, - unit=D.dollars) - total_harvest = Variable("total harvest", - "All water that has been harvested in the world", - lower_bound=0, - dimension=D.volume * D.time, - unit=D.meters ** 3 / D.years) - total_nutrition = Variable("total nutrition", - "All water that is being consumed in the world", - lower_bound=0, - dimension=D.volume * D.time, - unit=D.meters ** 3 / D.years) - total_liquidity = Variable("total liquidity", - "All the liquidity in the world, shall be equal" - "to the total gross income", - lower_bound=0, - unit=D.dollars) - water_price = Variable("water price", - "price of water that is calculated by market " - "clearing", - lower_bound=0, - unit=D.dollars, - default=1) - exception_checker = Variable("Exception checker", - "Check for exceptions to terminate run", - default=False) - - -class SocialSystem (object): - """Interface for SocialSystem entity type mixin.""" - - # endogenous variables: - municipality_like = Variable("municipality like", - "If true, social_system is a Municipality, " - "otherwise a county", - datatype=bool) - base_mean_income = Variable("base income", - "Base of scaling mean income dependend on " - "population, only important for municipality", - default=1000) - mean_income_or_farmsize = Variable("Mean income or farmsize", - "Mean income or farm size dependend on " - "population and base_mean_income", - default=0) - average_liquidity = Variable("Average Liquidity", - "Average over all liquidities in social_system", - lower_bound=0, - unit=D.dollars) - average_utility = Variable("Average Utility", - "Average Utility in a social_system") - gini_coefficient = Variable("Gini Coefficient", - "Gini coefficient of utilities") - scaling_parameter = Variable("Scaling Parameter", - "Parameter that scales income as in " - "Total_income = base_inc ** parameter, " - "default from bettencourt paper", - default=1.12) - migration_cost = Variable("Migration Cost", - "Cost to migrate to this social_system", - default=1000) - migration_counter = Variable("Migration Counter", - "List of: " - "-number of events that could lead to " - "migration," - "-list of social systems uids of possible " - "taget social systems," - "-list of social system and uids " - "of target SocialSystems", - datatype=list) - migration_rates = Variable("Migration Rates", - "List with migration rates to all other " - "social systems", - datatype=list, - allow_none=True, - default=None) - theoretical_mig_rate = Variable("Theoretical Migration Rate", - "Analytical approximation of rates", - datatype=list, - allow_none=True, - default=None) - last_one_standing = Variable("Last one standing", - "Bool that if True prohibits the last agent " - "in a social system from migrating", - datatype=bool, - default=False) - continuous_exploration = Variable("Continuos Exploration", - "Bool, that if True leads to a noise in" - "migration", - datatype=bool, - default=False) - - # exogenous variables / parameters: - - -class Cell (object): - """Interface for Cell entity type mixin.""" - - # endogenous variables: - - characteristic = Variable("characteristic", - "sort of cell, e.g 'farmland' or 'city' ") - average_precipitation = Variable("average precipitation", - "average precipitation per square meter " - "of cell's area and year", - lower_bound=0, - dimension=D.volume / (D.area * D.time), - unit=D.meters/D.years) - - # exogenous variables / parameters: - - -class Individual (object): - """Interface for Individual entity type mixin.""" - - # endogenous variables: - profession = Variable("profession", - "profession of an Individual, eg. 'farmer' or " - " 'townsman' ") - farm_size = Variable("farm size", - "Size of the farm of an individual, if his " - "profession is farmer", - lower_bound=0, - unit=D.square_kilometers, - allow_none=True) # farm size is None until distributed by social system - gross_income = Variable("gross income", - "Income before trade, distributed by social_system if " - "social_system is a municipality", - lower_bound=0, - unit=D.dollars, - allow_none=True) # incomes are none until distributed by social system - harvest = Variable("harvest", - "Water harvested before trade, calculated by farm size " - "and average farmland precipitation", - lower_bound=0, - dimension=D.volume*D.time, - unit=D.meters**3 / D.years, - default=0) - liquidity = Variable("liquidity", - "income after trade", - lower_bound=0, - unit=D.dollars) - nutrition = Variable("nutrition", - "water after trade. Since it is virtual water, " - "it can be subsumed into nutrition.", - lower_bound=0, - dimension=D.volume / D.time) - nutrition_need = Variable("nutrition need", - "need of nutrition per time", - dimension=D.volume / D.time, - unit=D.meters**3 / D.years) - utility = Variable("utility", - "Utility of an agent, calculated by any useful " - "function", - lower_bound=0, - upper_bound=1) - second_degree_rewire_prob = Variable("second degree rewire probability", - "Probability to rewire to a neighbour " - "of degree 2.", - default=0.3) - outspokenness = Variable("outspokenness", - "Describes how often per year an individual does " - "social updates in average", - default=1) - random_rewire = Variable("Random rewire", - "Probability to rewire to a random individual" - "and cutiing a connection with a known one.", - default=0.05) - preferential_migration = Variable("preferential migration", - "Define if migration is hindered in some " - "direction", - datatype=bool, - default=False) - - # exogenous variables / parameters: - - -# process taxa: - - -class Metabolism (object): - """Interface for Metabolism process taxon mixin.""" - - # endogenous variables: - market_frequency = Variable("market frequency", - "Defines how often per year the market " - "clearing is calculated", - default=1) - - non_equilibrium_checker = Variable("Nonequilibrium Checker", - "Is set true, if market is not in " - "equilibrium anymore", - default=False) - - -class Culture (object): - """Interface for Culture process taxon mixin.""" - - # endogenous variables: - network_clustering = Variable("network clustering", - "Average clustering of network, values from" - "networkx.average_clustering", - default=0) - modularity = Variable("Modularity", - "Modularity of a partition of the network", - default=0) - transitivity = Variable("Transitivity", - "Transitivity of the network") - split = Variable("Split", - "Shows if network has split", - default=False) - fully_connected_network = Variable("Fully connected Network", - "This var is set true when the " - "acquaintance network is fully " - "connected", - default=False, - datatype=bool) diff --git a/pycopancore/model_components/exodus/model.py b/pycopancore/model_components/exodus/model.py deleted file mode 100644 index f93ee5db..00000000 --- a/pycopancore/model_components/exodus/model.py +++ /dev/null @@ -1,31 +0,0 @@ -"""Model mixing class template. - -TODO: adjust or fill in code and documentation wherever marked by "TODO:", -then remove these instructions -""" - -# This file is part of pycopancore. -# -# Copyright (C) 2016-2017 by COPAN team at Potsdam Institute for Climate -# Impact Research -# -# URL: -# Contact: core@pik-potsdam.de -# License: BSD 2-clause license - -from . import interface as I -# import all needed entity type implementation classes: -from .implementation import World, SocialSystem, Cell, Individual -# import all needed process taxon implementation classes: -from .implementation import Metabolism, Culture - - -class Model (I.Model): - """Model mixin class.""" - - # mixins provided by this model component: - - entity_types = [World, SocialSystem, Cell, Individual] - """list of entity types augmented by this component""" - process_taxa = [Metabolism, Culture] - """list of process taxa augmented by this component""" diff --git a/pycopancore/model_components/exploit_social_learning/__init__.py b/pycopancore/model_components/exploit_social_learning/__init__.py deleted file mode 100644 index 1e1226a7..00000000 --- a/pycopancore/model_components/exploit_social_learning/__init__.py +++ /dev/null @@ -1,18 +0,0 @@ -"""Model component package simple_extraction.""" - -# This file is part of pycopancore. -# -# Copyright (C) 2016-2017 by COPAN team at Potsdam Institute for Climate -# Impact Research -# -# URL: -# Contact: core@pik-potsdam.de -# License: BSD 2-clause license - -from . import interface - -# export all implementation classes: -from .implementation import * - -# export model component mixin class: -from .model import Model diff --git a/pycopancore/model_components/exploit_social_learning/implementation/__init__.py b/pycopancore/model_components/exploit_social_learning/implementation/__init__.py deleted file mode 100644 index f990b981..00000000 --- a/pycopancore/model_components/exploit_social_learning/implementation/__init__.py +++ /dev/null @@ -1,22 +0,0 @@ -""" -Model component implementation subpackage exploit_social_learning. -""" - -# This file is part of pycopancore. -# -# Copyright (C) 2016-2017 by COPAN team at Potsdam Institute for Climate -# Impact Research -# -# URL: -# Contact: core@pik-potsdam.de -# License: BSD 2-clause license - -# TODO: adjust the following lists to your needs: - -# export all provided entity type implementation mixin classes: -from .world import World -from .individual import Individual - -# export all provided process taxon implementation mixin classes: - -from .culture import Culture diff --git a/pycopancore/model_components/exploit_social_learning/implementation/culture.py b/pycopancore/model_components/exploit_social_learning/implementation/culture.py deleted file mode 100644 index 734b0ccf..00000000 --- a/pycopancore/model_components/exploit_social_learning/implementation/culture.py +++ /dev/null @@ -1,211 +0,0 @@ -"""Culture process taxon mixing class exploit_social_learning.""" - -# This file is part of pycopancore. -# -# Copyright (C) 2016-2017 by COPAN team at Potsdam Institute for Climate -# Impact Research -# -# URL: -# Contact: core@pik-potsdam.de -# License: BSD 2-clause license - -from pycopancore.model_components.base import interface as B -from .. import interface as I -from .... import Step - -import numpy as np -import networkx as nx - - -class Culture (I.Culture): - """Culture process taxon mixin for exploit_social_learning.""" - - # process-related methods: - - def social_update(self, t): - """Execute the social update. - - Parameters - ---------- - t : float - time - - Returns - ------- - - """ - self.last_execution_time = t - agent_i = self.get_update_agent() - - # Step (1) - if self.acquaintance_network.neighbors(agent_i): - agent_j = np.random.choice( - list(self.acquaintance_network.neighbors(agent_i))) - # Step (2): Compare strategies of i and j: - # If they are the same, do nothing. Else change i's strategy. - if agent_i.strategy != agent_j.strategy: - # Step (2.1) - if np.random.random() < agent_i.rewiring_prob: - self.reconnect(agent_i, agent_j) - # Step (2.2) - else: - self.change_strategy(agent_i, agent_j) - # Step (3) - self.set_new_update_time(agent_i) - - if self.check_for_consensus(): - print('Consensus! time ', t) - - def reconnect(self, agent_i, agent_j): - """Reconnect agent_i from agent_j and connect it to k. - - Disconnect agent_i from agent_j and connect agent_i - to a randomly chosen agent_k with the same strategy, - agent_i.strategy == agent_k.strategy. - - Parameters - ---------- - agent_i : Agent (Individual or SocialSystem) - agent_j : Agent (Individual or SocialSystem) - - Returns - ------- - - """ - # Find a random stranger agent_k with same strategy as agent_i - all_non_neighbors = \ - list(set(self.acquaintance_network.nodes()) - - set(self.acquaintance_network.neighbors(agent_i))) - strategy_i = agent_i.strategy - for stranger in all_non_neighbors: - if stranger.strategy != strategy_i: - all_non_neighbors.remove(stranger) - if not all_non_neighbors: - print('No possible neighbors with different strategy.') - else: - # Disconnect agent_i and agent_j - self.acquaintance_network.remove_edge(agent_i, agent_j) - # Connect agent_i and agent_k - agent_k = np.random.choice(all_non_neighbors) - self.acquaintance_network.add_edge(agent_i, agent_k) - - def change_strategy(self, agent_i, agent_j): - """Change strategy of agent_i to agent_j's. - - Change the strategy of agent_i to the strategy of agent_j - depending on their respective harvest rates and the imitation tendency - according to a sigmoidal function. - - Parameters - ---------- - agent_i : Agent (Individual or SocialSystem) - Agent i whose strategy is to be changed to agent j's strategy - agent_j : Agent (Individual or SocialSystem) - Agent j whose strategy is imitated - Returns - ------- - - """ - probability = 0.5 * np.tanh(agent_i.imitation_tendency * - (agent_j.get_harvest_rate() - - agent_i.get_harvest_rate()) + 1) - if np.random.random() < probability: - agent_i.strategy = agent_j.strategy - - def get_update_agent(self): - """Return the agent with the closest waiting time. - - Choose from all agents the one with the smallest update_time. - Returns - ------- - - """ - next_agent = list(self.acquaintance_network.nodes())[0] - for agent in self.acquaintance_network: - if agent.update_time < next_agent.update_time: - next_agent = agent - return next_agent - - def set_new_update_time(self, agent): - """Set next time step when agent is to be called again. - - Set the attribute update_time of agent to - old_update_time + new_update_time, where new_update_time is again - drawn from an exponential distribution. - - Parameters - ---------- - agent : Agent (Individual or SocialSystem) - The agent whose new update_time should be drawn and set. - - Returns - ------- - - """ - # print('old_update_time: ',individual.update_time) - new_update_time = np.random.exponential(agent.average_waiting_time) - agent.update_time += new_update_time - - def check_for_consensus(self): - """Check if the model has run into a consensus state. - - The model is in a consensus state if in each connected component - all agents use the same strategy. In this case, there will be no more - change of strategies since the agents are only connected to agents - with the same strategy. - - Returns - ------- - consensus : bool - True if model is into consensus state, otherwise False - """ - cc = nx.connected_components(self.acquaintance_network) - # iterate through all connected components - for component in cc: - # iterate through all agents in this component - stratlist = [] - for j in component: - # check if all agents of component have the same strategy - stratlist.append(j.strategy) - if stratlist.count(stratlist[0]) != len(stratlist): - self.consensus = False - return self.consensus - - # If in each component, all agents have the same strategy, then a - # consensus state is reached - self.consensus = True - return self.consensus - - def step_timing(self, - t): - """Return the next time step is to be called. - - This function is used to get to know when the step function is - to be called. - Parameters - ---------- - t : float - time - - Returns - ------- - - """ - if isinstance(self.last_execution_time, type(None)): - self.last_execution_time = 0 - if t < self.last_execution_time: - print('last execution time after t!') - - next_time = list(self.acquaintance_network.nodes())[0].update_time - for agent in self.acquaintance_network: - if agent.update_time < next_time: - next_time = agent.update_time - if t > next_time: - print('next update time before t!') - return next_time - - processes = [Step('Social Update is a step function', - [I.Culture.acquaintance_network, - B.Culture.worlds.individuals.strategy, B.Culture.worlds.individuals.update_time, - I.Culture.consensus], - [step_timing, social_update])] diff --git a/pycopancore/model_components/exploit_social_learning/implementation/individual.py b/pycopancore/model_components/exploit_social_learning/implementation/individual.py deleted file mode 100644 index 54ff2f60..00000000 --- a/pycopancore/model_components/exploit_social_learning/implementation/individual.py +++ /dev/null @@ -1,65 +0,0 @@ -"""Individual entity type of the component exploit_social_learning.""" - -# This file is part of pycopancore. -# -# Copyright (C) 2016-2017 by COPAN team at Potsdam Institute for Climate -# Impact Research -# -# URL: -# Contact: core@pik-potsdam.de -# License: BSD 2-clause license - -from .. import interface as I -import numpy as np - - -class Individual(I.Individual): - """Define properties of exploit_social_learning individual.""" - - # standard methods: - - def __init__(self, - *, - strategy=0, - imitation_tendency=1, - rewiring_prob=0, - average_waiting_time=1, - **kwargs - ): - """Initialize an instance of Individual.""" - super().__init__(**kwargs) # must be the first line - self.strategy = strategy - self.imitation_tendency = imitation_tendency - self.rewiring_prob = rewiring_prob - self.average_waiting_time = average_waiting_time - self.update_time = np.random.exponential(self.average_waiting_time) - - pass - - def __lt__(self, other): - """Make objects sortable.""" - return self._uid < other._uid - - def deactivate(self): - """Deactivate an individual.""" - # TODO: add custom code here: - pass - super().deactivate() # must be the last line - - def reactivate(self): - """Reactivate an individual.""" - super().reactivate() # must be the first line - # TODO: add custom code here: - pass - - # process-related methods: - - def get_harvest_rate(self): - """Compute a random harvest rate of individual. - - This method should be overwritten with a method of the class - simple_extraction.individual. - """ - return np.random.rand() - - processes = [] diff --git a/pycopancore/model_components/exploit_social_learning/implementation/world.py b/pycopancore/model_components/exploit_social_learning/implementation/world.py deleted file mode 100644 index 2b19b9bf..00000000 --- a/pycopancore/model_components/exploit_social_learning/implementation/world.py +++ /dev/null @@ -1,131 +0,0 @@ -"""The exploit_social_learning.world class. - -In this module the exploit_social_learning World mixing class inherits from -World_ in that basic variables and parameters are defined. -""" - -# This file is part of pycopancore. -# -# Copyright (C) 2016-2017 by COPAN team at Potsdam Institute for Climate -# Impact Research -# -# URL: -# Contact: core@pik-potsdam.de -# License: BSD 2-clause license - -import numpy as np -from pycopancore.model_components import abstract -from pycopancore.model_components.exploit_social_learning import interface as I - - -class World (I.World, abstract.World): - """Define properties of exploit_social_learning.world. - - Inherits from I.World as the interface with all necessary variables - and parameters. - """ - - def __init__(self, - *, - contact_network=None, - agent_list=[], - **kwargs - ): - """Initialize an instance of World. - - Parameters - ---------- - agent_list - """ - super(World, self).__init__(**kwargs) - - self.contact_network = contact_network - self.agent_list = agent_list - # assert isinstance(self.contact_network, np.ndarray),\ - # 'Given network is not an numpy.ndarray.' - # assert (len(self.agent_list) == len(self.contact_network[:, 0]) and - # len(self.agent_list) == len(self.contact_network[0, :])),\ - # 'agent_list and contact_network do not have suitable dimensions.' - # # Make sure that all diagonal entries are zero. - # np.fill_diagonal(self.contact_network, 0) - - processes = [] - - def has_neighbor(self, agent): - """Return True if agent has a neighbor and False if not. - - Parameters - ---------- - agent Agent: Individual or SocialSystem - - Return - ------ - boolean - """ - assert agent in self.agent_list, 'agent is not in agent_list' - index = self.agent_list.index(agent) - isolated = True - i = 0 - n = self.contact_network[0].size - - while isolated and i < n: - if self.contact_network[index, i] != 0: - isolated = False - i += 1 - return not isolated - - def get_random_neighbor(self, agent): - """Return a random neighbor of agent. - - Parameters - ---------- - agent Agent: Individual or SocialSystem - - Return - ------ - neighbor Agent - """ - assert agent in self.agent_list, 'agent is not in agent_list' - neighbors = self.get_neighbors(agent) - neighbor = np.random.choice(neighbors) - return neighbor - - def get_neighbors(self, agent): - """Return a list of the neighbors of agent. - - Parameters - ---------- - agent Agent: Individual or SocialSystem - - Returns - ------- - neighbors: A list of all neighbors of agent - """ - assert agent in self.agent_list, 'agent is not in agent_list' - index = self.agent_list.index(agent) - n = self.contact_network[0].size - neighbors = [] - for i in range(n): - if self.contact_network[index, i] != 0: - neighbors.append(self.agent_list[i]) - return neighbors - - def get_non_neighbors(self, agent): - """Return a list of all agents that are not connected to agent. - - Parameters - ---------- - agent Agent: Individual or SocialSystem - - Returns - ------- - non_neighbors: A list of all agents that are no neighbors of agent - """ - assert agent in self.agent_list, 'agent is not in agent_list' - index = self.agent_list.index(agent) - n = self.contact_network[0].size - non_neighbors = [] - for i in range(n): - if index != i and self.contact_network[index, i] == 0: - non_neighbors.append(self.agent_list[i]) - return non_neighbors diff --git a/pycopancore/model_components/exploit_social_learning/interface.py b/pycopancore/model_components/exploit_social_learning/interface.py deleted file mode 100644 index 1f7f28fe..00000000 --- a/pycopancore/model_components/exploit_social_learning/interface.py +++ /dev/null @@ -1,67 +0,0 @@ -"""model component Interface exploit_social_learning.""" - -# This file is part of pycopancore. -# -# Copyright (C) 2016-2017 by COPAN team at Potsdam Institute for Climate -# Impact Research -# -# URL: -# Contact: core@pik-potsdam.de -# License: BSD 2-clause license - -# TODO: use variables from the master data model wherever possible: -from ... import master_data_model as D -# TODO: uncomment and adjust of you need further variables from another -# model component: -# import ..BBB.interface as BBB -# TODO: uncomment and adjust only if you really need other variables: -from ... import Variable - - -class Model(object): - """Interface for Model mixin.""" - - # metadata: - name = "..." - """Exploit Social Learning""" - description = "..." - """The Exploit social learning dynamics including reward based imitation - behaviour""" - requires = [] - """list of other model components required for this model component to - make sense""" - - -# entity types: -class World(object): - """Define Interface for World.""" - - agent_list = Variable('list of all agents', 'all agents in network') - - -class Individual(object): - """Interface for Individual.""" - - strategy = Variable('harvesting strategy', 'harvesting strategy indiv.') - imitation_tendency = Variable('imitation tendency', 'former rationality') - rewiring_prob = Variable('rewiring probability', 'rew. prob.') - average_waiting_time = Variable('estimated waiting time tau', 'tau') - update_time = Variable('next update time', 'next time for update') - - -class Cell(object): - """Interface for Cell.""" - - stock = Variable('current stock', 'current stock of resource') - growth_rate = Variable('growth rate', 'growth rate of resource') - - -class Culture(object): - """Define Interface for Culture.""" - - acquaintance_network = D.CUL.acquaintance_network - last_execution_time = Variable('last exec.time', - 'last time a step was executed', - default=-1) - consensus = Variable('consensus state', 'indicating if consensus is there', - default=False) diff --git a/pycopancore/model_components/exploit_social_learning/model.py b/pycopancore/model_components/exploit_social_learning/model.py deleted file mode 100644 index ab4fcaa5..00000000 --- a/pycopancore/model_components/exploit_social_learning/model.py +++ /dev/null @@ -1,30 +0,0 @@ -"""Model mixing class exploit_social_learning. - -It includes reward based imitation behaviour. -""" - -# This file is part of pycopancore. -# -# Copyright (C) 2016-2017 by COPAN team at Potsdam Institute for Climate -# Impact Research -# -# URL: -# Contact: core@pik-potsdam.de -# License: BSD 2-clause license - -from . import interface as I -# import all needed entity type implementation classes: -from .implementation import World, Individual, Culture -# import all needed process taxon implementation classes: -# none needed - - -class Model (I.Model): - """Model mixin class.""" - - # mixins provided by this model component: - - entity_types = [World, Individual] - """list of entity types augmented by this component""" - process_taxa = [Culture] - """list of process taxa augmented by this component""" diff --git a/pycopancore/model_components/majority_decision/__init__.py b/pycopancore/model_components/majority_decision/__init__.py deleted file mode 100644 index 6852092c..00000000 --- a/pycopancore/model_components/majority_decision/__init__.py +++ /dev/null @@ -1,26 +0,0 @@ -""" -Model component package template. - -TODO: -Copy this folder, rename it to the name of your model component, -then adjust or fill in code and documentation in all modules wherever marked by "TODO:", -finally remove these instructions. -See the model component development tutorial for details. -""" - -# This file is part of pycopancore. -# -# Copyright (C) 2016-2017 by COPAN team at Potsdam Institute for Climate -# Impact Research -# -# URL: -# Contact: core@pik-potsdam.de -# License: BSD 2-clause license - -from . import interface - -# export all implementation classes: -from .implementation import * - -# export model component mixin class: -from .model import Model diff --git a/pycopancore/model_components/majority_decision/implementation/__init__.py b/pycopancore/model_components/majority_decision/implementation/__init__.py deleted file mode 100644 index 89786d7c..00000000 --- a/pycopancore/model_components/majority_decision/implementation/__init__.py +++ /dev/null @@ -1,20 +0,0 @@ -""" -Model component implementation subpackage template. -""" - -# This file is part of pycopancore. -# -# Copyright (C) 2016-2017 by COPAN team at Potsdam Institute for Climate -# Impact Research -# -# URL: -# Contact: core@pik-potsdam.de -# License: BSD 2-clause license - -# TODO: adjust the following lists to your needs: - -# export all provided entity type implementation mixin classes: -from .social_system import SocialSystem -from .individual import Individual - -from .culture import Culture diff --git a/pycopancore/model_components/majority_decision/implementation/culture.py b/pycopancore/model_components/majority_decision/implementation/culture.py deleted file mode 100644 index b4981741..00000000 --- a/pycopancore/model_components/majority_decision/implementation/culture.py +++ /dev/null @@ -1,37 +0,0 @@ -"""Culture process taxon mixing class template. - -TODO: adjust or fill in code and documentation wherever marked by "TODO:", -then remove these instructions -""" - -# This file is part of pycopancore. -# -# Copyright (C) 2016-2017 by COPAN team at Potsdam Institute for Climate -# Impact Research -# -# URL: -# Contact: core@pik-potsdam.de -# License: BSD 2-clause license - -from .. import interface as I -# from .... import master_data_model as D - - -class Culture (I.Culture): - """Culture process taxon mixin implementation class.""" - - # standard methods: - - def __init__(self, - # *, # TODO: uncomment when adding named args behind here - **kwargs): - """Initialize the unique instance of Culture.""" - super().__init__(**kwargs) # must be the first line - # TODO: add custom code here: - pass - - # process-related methods: - - # TODO: add some if needed... - - processes = [] # TODO: instantiate and list process objects here diff --git a/pycopancore/model_components/majority_decision/implementation/individual.py b/pycopancore/model_components/majority_decision/implementation/individual.py deleted file mode 100644 index b5e385a9..00000000 --- a/pycopancore/model_components/majority_decision/implementation/individual.py +++ /dev/null @@ -1,49 +0,0 @@ -"""Individual entity type class template. - -TODO: adjust or fill in code and documentation wherever marked by "TODO:", -then remove these instructions -""" - -# This file is part of pycopancore. -# -# Copyright (C) 2016-2017 by COPAN team at Potsdam Institute for Climate -# Impact Research -# -# URL: -# Contact: core@pik-potsdam.de -# License: BSD 2-clause license - -from .. import interface as I -# from .... import master_data_model as D - - -class Individual (I.Individual): - """Individual entity type mixin implementation class.""" - - # standard methods: - - def __init__(self, - # *, # TODO: uncomment when adding named args behind here - **kwargs): - """Initialize an instance of Individual.""" - super().__init__(**kwargs) # must be the first line - # TODO: add custom code here: - pass - - def deactivate(self): - """Deactivate an individual.""" - # TODO: add custom code here: - pass - super().deactivate() # must be the last line - - def reactivate(self): - """Reactivate an individual.""" - super().reactivate() # must be the first line - # TODO: add custom code here: - pass - - # process-related methods: - - # TODO: add some if needed... - - processes = [] # TODO: instantiate and list process objects here diff --git a/pycopancore/model_components/majority_decision/implementation/social_system.py b/pycopancore/model_components/majority_decision/implementation/social_system.py deleted file mode 100644 index 35ee0aef..00000000 --- a/pycopancore/model_components/majority_decision/implementation/social_system.py +++ /dev/null @@ -1,66 +0,0 @@ -"""SocialSystem entity type mixing class template. - -TODO: adjust or fill in code and documentation wherever marked by "TODO:", -then remove these instructions -""" - -# This file is part of pycopancore. -# -# Copyright (C) 2016-2017 by COPAN team at Potsdam Institute for Climate -# Impact Research -# -# URL: -# Contact: core@pik-potsdam.de -# License: BSD 2-clause license - -from .. import interface as I -# from .... import master_data_model as D - -from .... import Explicit - -import operator - - -class SocialSystem (I.SocialSystem): - """SocialSystem entity type mixin implementation class.""" - - # standard methods: - - def __init__(self, - # *, # TODO: uncomment when adding named args behind here - **kwargs): - """Initialize an instance of SocialSystem.""" - super().__init__(**kwargs) # must be the first line - # TODO: add custom code here: - pass - - def deactivate(self): - """Deactivate a social_system.""" - # TODO: add custom code here: - pass - super().deactivate() # must be the last line - - def reactivate(self): - """Reactivate a social_system.""" - super().reactivate() # must be the first line - # TODO: add custom code here: - pass - - # process-related methods: - - def get_majority_opinion(self, t): - opinion_count = {} - for op in self.culture.possible_opinions: - opinion_count[op] = sum(1 for _ in filter( - lambda ind: ind.opinion == op, self.individuals)) - - self.opinion = max(opinion_count.items(), - key=operator.itemgetter(1))[0] - - processes = [ - Explicit( - "identification of majority opinion", - [I.SocialSystem.opinion], - get_majority_opinion - ) - ] diff --git a/pycopancore/model_components/majority_decision/interface.py b/pycopancore/model_components/majority_decision/interface.py deleted file mode 100644 index d295f6c5..00000000 --- a/pycopancore/model_components/majority_decision/interface.py +++ /dev/null @@ -1,73 +0,0 @@ -"""model component Interface template. - -TODO: adjust or fill in code and documentation wherever marked by "TODO:", then -remove these instructions. -""" - -# This file is part of pycopancore. -# -# Copyright (C) 2016-2017 by COPAN team at Potsdam Institute for Climate -# Impact Research -# -# URL: -# Contact: core@pik-potsdam.de -# License: BSD 2-clause license - -# TODO: use variables from the master data model wherever possible: -from ... import master_data_model as D -# TODO: uncomment and adjust of you need further variables from another -# model component: -# import ..BBB.interface as BBB -from .. import adaptive_voter_opinion_formation as avof -# TODO: uncomment and adjust only if you really need other variables: -from ... import Variable - - -class Model (object): - """Interface for Model mixin.""" - - # metadata: - name = "majority decision" - """a unique name for the model component""" - description = "find the opinion the most represented in a social_system" - """some longer description""" - requires = [avof] - """list of other model components required for this model component to - make sense""" - - # Notes: - # - Model does NOT define variables or parameters, only entity types - # and process taxons do! - # - implementation.Model lists these entity-types and process taxons - - -# entity types: - - -class SocialSystem (object): - """Interface for SocialSystem entity type mixin.""" - - # endogenous variables: - - opinion = avof.Individual.opinion.copy() - - # exogenous variables / parameters: - - -class Individual (object): - """Interface for Individual entity type mixin.""" - - # endogenous variables: - - opinion = avof.Individual.opinion - - # exogenous variables / parameters: - - -class Culture (object): - """Interface for Culture process taxon mixin.""" - - # endogenous variables: - acquaintance_network = D.CUL.acquaintance_network - - # exogenous variables / parameters: diff --git a/pycopancore/model_components/majority_decision/model.py b/pycopancore/model_components/majority_decision/model.py deleted file mode 100644 index ed844312..00000000 --- a/pycopancore/model_components/majority_decision/model.py +++ /dev/null @@ -1,31 +0,0 @@ -"""Model mixing class template. - -TODO: adjust or fill in code and documentation wherever marked by "TODO:", -then remove these instructions -""" - -# This file is part of pycopancore. -# -# Copyright (C) 2016-2017 by COPAN team at Potsdam Institute for Climate -# Impact Research -# -# URL: -# Contact: core@pik-potsdam.de -# License: BSD 2-clause license - -from . import interface as I -# import all needed entity type implementation classes: -from .implementation import SocialSystem, Individual -# import all needed process taxon implementation classes: -from .implementation import Culture - - -class Model (I.Model): - """Model mixin class.""" - - # mixins provided by this model component: - - entity_types = [SocialSystem, Individual] - """list of entity types augmented by this component""" - process_taxa = [Culture] - """list of process taxa augmented by this component""" diff --git a/pycopancore/model_components/maxploit_individual_layer/__init__.py b/pycopancore/model_components/maxploit_individual_layer/__init__.py deleted file mode 100644 index 1e1226a7..00000000 --- a/pycopancore/model_components/maxploit_individual_layer/__init__.py +++ /dev/null @@ -1,18 +0,0 @@ -"""Model component package simple_extraction.""" - -# This file is part of pycopancore. -# -# Copyright (C) 2016-2017 by COPAN team at Potsdam Institute for Climate -# Impact Research -# -# URL: -# Contact: core@pik-potsdam.de -# License: BSD 2-clause license - -from . import interface - -# export all implementation classes: -from .implementation import * - -# export model component mixin class: -from .model import Model diff --git a/pycopancore/model_components/maxploit_individual_layer/implementation/__init__.py b/pycopancore/model_components/maxploit_individual_layer/implementation/__init__.py deleted file mode 100644 index f990b981..00000000 --- a/pycopancore/model_components/maxploit_individual_layer/implementation/__init__.py +++ /dev/null @@ -1,22 +0,0 @@ -""" -Model component implementation subpackage exploit_social_learning. -""" - -# This file is part of pycopancore. -# -# Copyright (C) 2016-2017 by COPAN team at Potsdam Institute for Climate -# Impact Research -# -# URL: -# Contact: core@pik-potsdam.de -# License: BSD 2-clause license - -# TODO: adjust the following lists to your needs: - -# export all provided entity type implementation mixin classes: -from .world import World -from .individual import Individual - -# export all provided process taxon implementation mixin classes: - -from .culture import Culture diff --git a/pycopancore/model_components/maxploit_social_norms/__init__.py b/pycopancore/model_components/maxploit_social_norms/__init__.py deleted file mode 100644 index 1e1226a7..00000000 --- a/pycopancore/model_components/maxploit_social_norms/__init__.py +++ /dev/null @@ -1,18 +0,0 @@ -"""Model component package simple_extraction.""" - -# This file is part of pycopancore. -# -# Copyright (C) 2016-2017 by COPAN team at Potsdam Institute for Climate -# Impact Research -# -# URL: -# Contact: core@pik-potsdam.de -# License: BSD 2-clause license - -from . import interface - -# export all implementation classes: -from .implementation import * - -# export model component mixin class: -from .model import Model diff --git a/pycopancore/model_components/maxploit_social_norms/implementation/__init__.py b/pycopancore/model_components/maxploit_social_norms/implementation/__init__.py deleted file mode 100644 index 3c7f3304..00000000 --- a/pycopancore/model_components/maxploit_social_norms/implementation/__init__.py +++ /dev/null @@ -1,22 +0,0 @@ -""" -Model component implementation subpackage exploit_social_learning. -""" - -# This file is part of pycopancore. -# -# Copyright (C) 2016-2017 by COPAN team at Potsdam Institute for Climate -# Impact Research -# -# URL: -# Contact: core@pik-potsdam.de -# License: BSD 2-clause license - -# TODO: adjust the following lists to your needs: - -# export all provided entity type implementation mixin classes: -from .individual import Individual -from .group import Group - -# export all provided process taxon implementation mixin classes: - -from .culture import Culture diff --git a/pycopancore/model_components/most_simple_vegetation/__init__.py b/pycopancore/model_components/most_simple_vegetation/__init__.py deleted file mode 100644 index 20c2fade..00000000 --- a/pycopancore/model_components/most_simple_vegetation/__init__.py +++ /dev/null @@ -1,18 +0,0 @@ -"""Model component package most_simple_vegetation.""" - -# This file is part of pycopancore. -# -# Copyright (C) 2016-2017 by COPAN team at Potsdam Institute for Climate -# Impact Research -# -# URL: -# Contact: core@pik-potsdam.de -# License: BSD 2-clause license - -from . import interface - -# export all implementation classes: -from .implementation import * - -# export model component mixin class: -from .model import Model diff --git a/pycopancore/model_components/most_simple_vegetation/implementation/__init__.py b/pycopancore/model_components/most_simple_vegetation/implementation/__init__.py deleted file mode 100644 index 542f6aa4..00000000 --- a/pycopancore/model_components/most_simple_vegetation/implementation/__init__.py +++ /dev/null @@ -1,19 +0,0 @@ -""" -Model component implementation subpackage most_simple_vegetation. -""" - -# This file is part of pycopancore. -# -# Copyright (C) 2016-2017 by COPAN team at Potsdam Institute for Climate -# Impact Research -# -# URL: -# Contact: core@pik-potsdam.de -# License: BSD 2-clause license - -# TODO: adjust the following lists to your needs: - -# export all provided entity type implementation mixin classes: -from .cell import Cell - -# export all provided process taxon implementation mixin classes: diff --git a/pycopancore/model_components/most_simple_vegetation/implementation/cell.py b/pycopancore/model_components/most_simple_vegetation/implementation/cell.py deleted file mode 100644 index 5b8a538a..00000000 --- a/pycopancore/model_components/most_simple_vegetation/implementation/cell.py +++ /dev/null @@ -1,74 +0,0 @@ -"""Cell entity type mixing of class most_simple_vegetation.""" - -# This file is part of pycopancore. -# -# Copyright (C) 2016-2017 by COPAN team at Potsdam Institute for Climate -# Impact Research -# -# URL: -# Contact: core@pik-potsdam.de -# License: BSD 2-clause license - -from pycopancore import ODE -from pycopancore.model_components.simple_extraction import interface as I - - -class Cell(I.Cell): - """Cell entity type mixin implementation class.""" - - # standard methods: - - def __init__(self, - *, - stock=1, - capacity=1, - growth_rate=1, - **kwargs - ): - """Initialize an instance of Cell.""" - super().__init__(**kwargs) - - self.stock = stock - self.capacity = capacity - self.growth_rate = growth_rate - - pass - - def deactivate(self): - """Deactivate a cell.""" - # TODO: add custom code here: - pass - super().deactivate() # must be the last line - - def reactivate(self): - """Reactivate a cell.""" - super().reactivate() # must be the first line - # TODO: add custom code here: - pass - - # process-related methods: - - def logistic_growth(self, t): - """Compute the biophysical logistic growth function of cell's stock. - - Parameters - ---------- - t : float - time - - Returns - ------- - - """ - g = self.growth_rate - s = self.stock - smax = self.capacity - self.d_stock += g * (1 - s / smax) * s - - # processes: - - processes = [ - ODE('logistic_growth_function', - [I.Cell.stock], - logistic_growth) - ] diff --git a/pycopancore/model_components/most_simple_vegetation/interface.py b/pycopancore/model_components/most_simple_vegetation/interface.py deleted file mode 100644 index 74269869..00000000 --- a/pycopancore/model_components/most_simple_vegetation/interface.py +++ /dev/null @@ -1,41 +0,0 @@ -"""model component Interface most_simple_vegetation.""" - -# This file is part of pycopancore. -# -# Copyright (C) 2016-2017 by COPAN team at Potsdam Institute for Climate -# Impact Research -# -# URL: -# Contact: core@pik-potsdam.de -# License: BSD 2-clause license - -# TODO: use variables from the master data model wherever possible: -# from ... import master_data_model as D -# TODO: uncomment and adjust of you need further variables from another -# model component: -# import ..BBB.interface as BBB -# TODO: uncomment and adjust only if you really need other variables: -from ... import Variable - - -class Model(object): - """Interface for Model mixin.""" - - # metadata: - name = "..." - """most simple vegetation""" - description = "..." - """A most simple vegetation growth model""" - requires = [] - """list of other model components required for this model component to - make sense""" - - -# entity types: - -class Cell(object): - """Interface for Cell.""" - - stock = Variable('current stock', 'current stock of resource') - capacity = Variable('capacity', 'capacity of resource') - growth_rate = Variable('growth rate', 'growth rate of resource') diff --git a/pycopancore/model_components/most_simple_vegetation/model.py b/pycopancore/model_components/most_simple_vegetation/model.py deleted file mode 100644 index eaa3b0e6..00000000 --- a/pycopancore/model_components/most_simple_vegetation/model.py +++ /dev/null @@ -1,27 +0,0 @@ -"""Model mixing class most_simple_vegetation.""" - -# This file is part of pycopancore. -# -# Copyright (C) 2016-2017 by COPAN team at Potsdam Institute for Climate -# Impact Research -# -# URL: -# Contact: core@pik-potsdam.de -# License: BSD 2-clause license - -from . import interface as I -# import all needed entity type implementation classes: -from .implementation import Cell -# import all needed process taxon implementation classes: -# none needed - - -class Model (I.Model): - """Model mixin class.""" - - # mixins provided by this model component: - - entity_types = [Cell] - """list of entity types augmented by this component""" - process_taxa = [] - """list of process taxa augmented by this component""" diff --git a/pycopancore/model_components/seven_dwarfs/implementation/cell.py b/pycopancore/model_components/seven_dwarfs/implementation/cell.py index 1372c6c2..a15e74d1 100644 --- a/pycopancore/model_components/seven_dwarfs/implementation/cell.py +++ b/pycopancore/model_components/seven_dwarfs/implementation/cell.py @@ -14,7 +14,7 @@ # License: BSD 2-clause license from .. import interface as I -from pycopancore import Event +from pycopancore.process_types import Event import numpy as np # from .... import master_data_model as D diff --git a/pycopancore/model_components/seven_dwarfs/implementation/group.py b/pycopancore/model_components/seven_dwarfs/implementation/group.py index 4da3f6b7..7217a51b 100644 --- a/pycopancore/model_components/seven_dwarfs/implementation/group.py +++ b/pycopancore/model_components/seven_dwarfs/implementation/group.py @@ -13,14 +13,11 @@ # Contact: core@pik-potsdam.de # License: BSD 2-clause license -from .. import interface as I -# from .... import master_data_model as D +# TODO: import those process types you need: +from pycopancore.process_types import Explicit -# TODO: uncomment this if you need ref. variables such as B.Individual.cell: -from ...base import interface as B +from .. import interface as I -# TODO: import those process types you need: -from .... import Explicit class Group (I.Group): """Group entity type mixin implementation class.""" diff --git a/pycopancore/model_components/seven_dwarfs/implementation/individual.py b/pycopancore/model_components/seven_dwarfs/implementation/individual.py index c48d947c..11415c8a 100644 --- a/pycopancore/model_components/seven_dwarfs/implementation/individual.py +++ b/pycopancore/model_components/seven_dwarfs/implementation/individual.py @@ -16,7 +16,7 @@ from .. import interface as I from pycopancore.model_components.base import interface as B # from .... import master_data_model as D -from pycopancore import ODE, Step, Explicit, Event +from pycopancore.process_types import ODE, Step, Explicit, Event import numpy as np diff --git a/pycopancore/model_components/seven_dwarfs/implementation/social_system.py b/pycopancore/model_components/seven_dwarfs/implementation/social_system.py index b0762c5e..97810bde 100644 --- a/pycopancore/model_components/seven_dwarfs/implementation/social_system.py +++ b/pycopancore/model_components/seven_dwarfs/implementation/social_system.py @@ -15,7 +15,7 @@ from .. import interface as I from pycopancore.model_components.base import interface as B # from .... import master_data_model as D -from pycopancore import ODE, Step, Explicit, Event +from pycopancore.process_types import ODE, Step, Explicit, Event import numpy as np diff --git a/pycopancore/model_components/seven_dwarfs/interface.py b/pycopancore/model_components/seven_dwarfs/interface.py index 7176b1a8..f39da64f 100644 --- a/pycopancore/model_components/seven_dwarfs/interface.py +++ b/pycopancore/model_components/seven_dwarfs/interface.py @@ -19,10 +19,9 @@ # model component: # import ..BBB.interface as BBB # TODO: uncomment and adjust only if you really need other variables: -from ... import Variable -from ... import master_data_model as D -from ...data_model.master_data_model import CUL - +from pycopancore.data_model import Variable +from pycopancore.data_model import master_data_model as D +from pycopancore.data_model.master_data_model import CUL class Model (object): diff --git a/pycopancore/model_components/simple_extraction/__init__.py b/pycopancore/model_components/simple_extraction/__init__.py deleted file mode 100644 index 1e1226a7..00000000 --- a/pycopancore/model_components/simple_extraction/__init__.py +++ /dev/null @@ -1,18 +0,0 @@ -"""Model component package simple_extraction.""" - -# This file is part of pycopancore. -# -# Copyright (C) 2016-2017 by COPAN team at Potsdam Institute for Climate -# Impact Research -# -# URL: -# Contact: core@pik-potsdam.de -# License: BSD 2-clause license - -from . import interface - -# export all implementation classes: -from .implementation import * - -# export model component mixin class: -from .model import Model diff --git a/pycopancore/model_components/simple_extraction/implementation/__init__.py b/pycopancore/model_components/simple_extraction/implementation/__init__.py deleted file mode 100644 index bdf1b499..00000000 --- a/pycopancore/model_components/simple_extraction/implementation/__init__.py +++ /dev/null @@ -1,20 +0,0 @@ -""" -Model component implementation subpackage simple_extraction. -""" - -# This file is part of pycopancore. -# -# Copyright (C) 2016-2017 by COPAN team at Potsdam Institute for Climate -# Impact Research -# -# URL: -# Contact: core@pik-potsdam.de -# License: BSD 2-clause license - -# TODO: adjust the following lists to your needs: - -# export all provided entity type implementation mixin classes: -from .cell import Cell -from .individual import Individual - -# export all provided process taxon implementation mixin classes: diff --git a/pycopancore/model_components/simple_extraction/implementation/cell.py b/pycopancore/model_components/simple_extraction/implementation/cell.py deleted file mode 100644 index 9ad1f45e..00000000 --- a/pycopancore/model_components/simple_extraction/implementation/cell.py +++ /dev/null @@ -1,61 +0,0 @@ -"""Cell entity type mixing of class simple_extraction.""" - -# This file is part of pycopancore. -# -# Copyright (C) 2016-2017 by COPAN team at Potsdam Institute for Climate -# Impact Research -# -# URL: -# Contact: core@pik-potsdam.de -# License: BSD 2-clause license - -from pycopancore import ODE -from pycopancore.model_components.simple_extraction import interface as I - - -class Cell(I.Cell): - """Cell entity type mixin implementation class.""" - - # standard methods: - - def __init__(self, - *, - stock=1, - growth_rate=1, - **kwargs - ): - """Initialize an instance of Cell.""" - super().__init__(**kwargs) - - self.stock = stock - self.growth_rate = growth_rate - - - def deactivate(self): - """Deactivate a cell.""" - # TODO: add custom code here: - - super().deactivate() # must be the last line - - def reactivate(self): - """Reactivate a cell.""" - super().reactivate() # must be the first line - # TODO: add custom code here: - - # process-related methods: - - def harvest(self, t): - """Compute the harvesting dynamics. - - Parameters - ---------- - t : float - time - - Returns - ------- - - """ - self.d_stock -= self.individual.get_harvest_rate() - - processes = [ODE('harvesting function', [I.Cell.stock], harvest)] diff --git a/pycopancore/model_components/simple_extraction/implementation/individual.py b/pycopancore/model_components/simple_extraction/implementation/individual.py deleted file mode 100644 index b66b4822..00000000 --- a/pycopancore/model_components/simple_extraction/implementation/individual.py +++ /dev/null @@ -1,59 +0,0 @@ -"""Individual entity type of the component simple_extraction.""" - -# This file is part of pycopancore. -# -# Copyright (C) 2016-2017 by COPAN team at Potsdam Institute for Climate -# Impact Research -# -# URL: -# Contact: core@pik-potsdam.de -# License: BSD 2-clause license - -from .. import interface as I - - -class Individual(I.Individual): - """Define properties of simple_extraction individual.""" - - # standard methods: - - def __init__(self, - *, - strategy=0, - **kwargs - ): - """Initialize an instance of Individual.""" - super().__init__(**kwargs) # must be the first line - self.strategy = strategy - - - def __lt__(self, other): - """Make objects sortable.""" - return self._uid < other._uid - - def deactivate(self): - """Deactivate an individual.""" - # TODO: add custom code here: - - super().deactivate() # must be the last line - - def reactivate(self): - """Reactivate an individual.""" - super().reactivate() # must be the first line - # TODO: add custom code here: - - - # process-related methods: - - def get_harvest_rate(self): - """Compute the harvest rate of the individual on its cell. - - Returns - ------- - harvest : float - """ - effort = 0.5 * self.cell.growth_rate * (3 - 2 * self.strategy) - harvest = effort * self.cell.stock - return harvest - - processes = [] diff --git a/pycopancore/model_components/simple_extraction/interface.py b/pycopancore/model_components/simple_extraction/interface.py deleted file mode 100644 index ffb8d3c3..00000000 --- a/pycopancore/model_components/simple_extraction/interface.py +++ /dev/null @@ -1,46 +0,0 @@ -"""model component Interface simple_extraction.""" - -# This file is part of pycopancore. -# -# Copyright (C) 2016-2017 by COPAN team at Potsdam Institute for Climate -# Impact Research -# -# URL: -# Contact: core@pik-potsdam.de -# License: BSD 2-clause license - -# TODO: use variables from the master data model wherever possible: -# from ... import master_data_model as D -# TODO: uncomment and adjust of you need further variables from another -# model component: -from ..exploit_social_learning import Individual as ESLIndividual -# TODO: uncomment and adjust only if you really need other variables: -from ... import Variable - - -class Model(object): - """Interface for Model mixin.""" - - # metadata: - name = "..." - """simple extraction""" - description = "..." - """A simple extraction model""" - requires = [] - """list of other model components required for this model component to - make sense""" - - -# entity types: - -class Individual(object): - """Interface for Individual.""" - - strategy = ESLIndividual.strategy - - -class Cell(object): - """Interface for Cell.""" - - stock = Variable('current stock', 'current stock of resource') - growth_rate = Variable('growth rate', 'growth rate of resource') diff --git a/pycopancore/model_components/simple_extraction/model.py b/pycopancore/model_components/simple_extraction/model.py deleted file mode 100644 index b6a77118..00000000 --- a/pycopancore/model_components/simple_extraction/model.py +++ /dev/null @@ -1,27 +0,0 @@ -"""Model mixing class simple_extraction.""" - -# This file is part of pycopancore. -# -# Copyright (C) 2016-2017 by COPAN team at Potsdam Institute for Climate -# Impact Research -# -# URL: -# Contact: core@pik-potsdam.de -# License: BSD 2-clause license - -from . import interface as I -# import all needed entity type implementation classes: -from .implementation import Cell, Individual -# import all needed process taxon implementation classes: -# none needed - - -class Model(I.Model): - """Model mixin class.""" - - # mixins provided by this model component: - - entity_types = [Cell, Individual] - """list of entity types augmented by this component""" - process_taxa = [] - """list of process taxa augmented by this component""" diff --git a/pycopancore/model_components/snowwhite/__init__.py b/pycopancore/model_components/snowwhite/__init__.py deleted file mode 100644 index ffe9fe83..00000000 --- a/pycopancore/model_components/snowwhite/__init__.py +++ /dev/null @@ -1,24 +0,0 @@ -""" -Model component package template. - -TODO: -Copy this folder, rename it to the name of your model component, -then adjust or fill in code and documentation in all modules wherever marked by "TODO:", -finally remove these instructions. -See the model component development tutorial for details. -""" -# This file is part of pycopancore. -# -# Copyright (C) 2017 by COPAN team at Potsdam Institute for Climate Impact -# Research -# -# URL: -# License: MIT license - -from . import interface - -# export all implementation classes: -from .implementation import * - -# export model component mixin class: -from .model import Model diff --git a/pycopancore/model_components/snowwhite/implementation/__init__.py b/pycopancore/model_components/snowwhite/implementation/__init__.py deleted file mode 100644 index 8cce37d2..00000000 --- a/pycopancore/model_components/snowwhite/implementation/__init__.py +++ /dev/null @@ -1,13 +0,0 @@ -""" -Model component implementation subpackage template. -""" -# This file is part of pycopancore. -# -# Copyright (C) 2016 by COPAN team at Potsdam Institute for Climate Impact -# Research -# -# URL: -# License: MIT license - -# export all provided entity type implementation mixin classes: -from .cell import Cell diff --git a/pycopancore/model_components/snowwhite/implementation/cell.py b/pycopancore/model_components/snowwhite/implementation/cell.py deleted file mode 100644 index 8ed5cb94..00000000 --- a/pycopancore/model_components/snowwhite/implementation/cell.py +++ /dev/null @@ -1,40 +0,0 @@ -"""Cell entity type mixing class template. - -TODO: adjust or fill in code and documentation wherever marked by "TODO:", -then remove these instructions -""" -# This file is part of pycopancore. -# -# Copyright (C) 2017 by COPAN team at Potsdam Institute for Climate -# Impact Research -# -# URL: -# License: MIT license - -from .. import interface as I -from pycopancore import Event -import numpy as np - -# from .... import master_data_model as D - - -class Cell (I.Cell): - """Cell entity type mixin implementation class.""" - - # standard methods: - - def snow_white_arrival(self, t): - """Calculate snow white's arrival.""" - return t + np.random.exponential(14.) - - def snow_white_eating(self, unused_t): - """Party hard.""" - print('Snow white arrives and has the munchies.') - self.eating_stock = self.eating_stock / 2. - - processes = [ - Event("snow_white", - [I.Cell.eating_stock], - ["time", snow_white_arrival, snow_white_eating] - ) - ] diff --git a/pycopancore/model_components/snowwhite/interface.py b/pycopancore/model_components/snowwhite/interface.py deleted file mode 100644 index c1de8ddd..00000000 --- a/pycopancore/model_components/snowwhite/interface.py +++ /dev/null @@ -1,48 +0,0 @@ -"""model component Interface template. - -TODO: adjust or fill in code and documentation wherever marked by "TODO:", then -remove these instructions. -""" - -# This file is part of pycopancore. -# -# Copyright (C) 2017 by COPAN team at Potsdam Institute for Climate -# Impact Research -# -# URL: -# License: MIT license - -# TODO: use variables from the master data model wherever possible: -# from ... import master_data_model as D -# TODO: uncomment and adjust of you need further variables from another -# model component: -# import ..BBB.interface as BBB -# TODO: uncomment and adjust only if you really need other variables: -from ... import Variable -from ... import master_data_model as D -from ..seven_dwarfs.interface import Cell as C - - -class Model (object): - """Interface for Model mixin.""" - - # metadata: - name = "Snwow White Component" - description = "Snow White arrives at the Dwarf's cave." - requires = [] - """list of other model components required for this model component to - make sense""" - - # Notes: - # - Model does NOT define variables or parameters, only entity types - # and process taxons do! - # - implementation.Model lists these entity-types and process taxons - - -# entity types: - -class Cell (object): - """Interface for Cell entity type mixin.""" - - # endogenous variables: - eating_stock = C.eating_stock # exogenous variables / parameters: diff --git a/pycopancore/model_components/snowwhite/model.py b/pycopancore/model_components/snowwhite/model.py deleted file mode 100644 index 85ba683d..00000000 --- a/pycopancore/model_components/snowwhite/model.py +++ /dev/null @@ -1,30 +0,0 @@ -"""Model mixing class template. - -TODO: adjust or fill in code and documentation wherever marked by "TODO:", -then remove these instructions -""" - -# This file is part of pycopancore. -# -# Copyright (C) 2017 by COPAN team at Potsdam Institute for Climate -# Impact Research -# -# URL: -# License: MIT license - -from . import interface as I -# import all needed entity type implementation classes: -from .implementation import Cell # TODO: adjust! -# import all needed process taxon implementation classes: -#from .implementation import Environment, Metabolism, Culture # TODO: adjust! - - -class Model(I.Model): - """Model mixin class.""" - - # mixins provided by this model component: - - entity_types = [Cell] # TODO: adjust! - """list of entity types augmented by this component""" - process_taxa = [] # TODO: adjust! - """list of process taxa augmented by this component""" diff --git a/pycopancore/model_components/social_learning_of_environmental_friendliness/__init__.py b/pycopancore/model_components/social_learning_of_environmental_friendliness/__init__.py deleted file mode 100644 index 6852092c..00000000 --- a/pycopancore/model_components/social_learning_of_environmental_friendliness/__init__.py +++ /dev/null @@ -1,26 +0,0 @@ -""" -Model component package template. - -TODO: -Copy this folder, rename it to the name of your model component, -then adjust or fill in code and documentation in all modules wherever marked by "TODO:", -finally remove these instructions. -See the model component development tutorial for details. -""" - -# This file is part of pycopancore. -# -# Copyright (C) 2016-2017 by COPAN team at Potsdam Institute for Climate -# Impact Research -# -# URL: -# Contact: core@pik-potsdam.de -# License: BSD 2-clause license - -from . import interface - -# export all implementation classes: -from .implementation import * - -# export model component mixin class: -from .model import Model diff --git a/pycopancore/model_components/social_learning_of_environmental_friendliness/implementation/__init__.py b/pycopancore/model_components/social_learning_of_environmental_friendliness/implementation/__init__.py deleted file mode 100644 index 91998faf..00000000 --- a/pycopancore/model_components/social_learning_of_environmental_friendliness/implementation/__init__.py +++ /dev/null @@ -1,18 +0,0 @@ -""" -Model component implementation subpackage template. -""" - -# This file is part of pycopancore. -# -# Copyright (C) 2016-2017 by COPAN team at Potsdam Institute for Climate -# Impact Research -# -# URL: -# Contact: core@pik-potsdam.de -# License: BSD 2-clause license - -# export all provided entity type implementation mixin classes: -from .individual import Individual - -# export all provided process taxon implementation mixin classes: -from .culture import Culture diff --git a/pycopancore/model_components/social_learning_of_environmental_friendliness/implementation/culture.py b/pycopancore/model_components/social_learning_of_environmental_friendliness/implementation/culture.py deleted file mode 100644 index d294d5fa..00000000 --- a/pycopancore/model_components/social_learning_of_environmental_friendliness/implementation/culture.py +++ /dev/null @@ -1,43 +0,0 @@ -"""Culture process taxon mixing class template. -""" - -# This file is part of pycopancore. -# -# Copyright (C) 2016-2017 by COPAN team at Potsdam Institute for Climate -# Impact Research -# -# URL: -# Contact: core@pik-potsdam.de -# License: BSD 2-clause license - -from .... import Event -from .. import interface as I -from ...base import interface as B -from numpy import inf -from numpy.random import exponential, uniform - - -class Culture (I.Culture): - """Culture process taxon mixin implementation class.""" - - # process-related methods: - - def next_learning_time(self, t): - """time of next awareness update""" - return (inf if self.environmental_friendliness_learning_rate == 0 - else t + exponential(1. / self.environmental_friendliness_learning_rate)) - - def let_individuals_learn(self, t): - """let some individuals learn environmental (un)friendliness""" - for w in self.worlds: - for i in w.individuals: - if uniform() < self.environmental_friendliness_learning_fraction: - i.learn_environmental_friendliness(t) - - processes = [ - Event("learn environmental (un)friendliness", - [B.Culture.worlds.individuals.is_environmentally_friendly], - ["time", - next_learning_time, - let_individuals_learn]) - ] diff --git a/pycopancore/model_components/social_learning_of_environmental_friendliness/implementation/individual.py b/pycopancore/model_components/social_learning_of_environmental_friendliness/implementation/individual.py deleted file mode 100644 index df7a7fed..00000000 --- a/pycopancore/model_components/social_learning_of_environmental_friendliness/implementation/individual.py +++ /dev/null @@ -1,47 +0,0 @@ -"""Individual entity type class template. -""" - -# This file is part of pycopancore. -# -# Copyright (C) 2016-2017 by COPAN team at Potsdam Institute for Climate -# Impact Research -# -# URL: -# Contact: core@pik-potsdam.de -# License: BSD 2-clause license - -from .. import interface as I -from numpy import arctan, log, pi, random - -class Individual (I.Individual): - """Individual entity type mixin implementation class.""" - - def learn_environmental_friendliness(self, unused_t): - """stochastically change environmental friendliness status depending on - acquaintances' environmental friendliness. - - This method is called by Culture's learning process - """ - # choose random acquaintance if there are any: - neighbors = list(self.culture.acquaintance_network.neighbors(self)) - if len(neighbors) == 0: - return - other = random.choice(neighbors) - # consider imitating her if your traits differ: - othertrait = other.is_environmentally_friendly - if othertrait == self.is_environmentally_friendly: - return - # compute quotient of respective terrestrial carbon densities: - here = self.cell - there = other.cell - cul = self.culture - slope = cul.environmental_friendliness_learning_probability_characteristic_slope - offset = cul.environmental_friendliness_learning_density_quotient_offset - quotient = ((there.terrestrial_carbon / there.land_area) / - (here.terrestrial_carbon / here.land_area)) - # imitate other with probability = sigmoid-shaped function of quotient: - if random.uniform() < (1/2 - + 1/pi * arctan(pi * slope * log(quotient / offset))): - self.is_environmentally_friendly = othertrait - - processes = [] diff --git a/pycopancore/model_components/social_learning_of_environmental_friendliness/interface.py b/pycopancore/model_components/social_learning_of_environmental_friendliness/interface.py deleted file mode 100644 index e34fd35c..00000000 --- a/pycopancore/model_components/social_learning_of_environmental_friendliness/interface.py +++ /dev/null @@ -1,71 +0,0 @@ -"""model component Interface template. - -TODO: adjust or fill in code and documentation wherever marked by "TODO:", then -remove these instructions. -""" - -# This file is part of pycopancore. -# -# Copyright (C) 2016-2017 by COPAN team at Potsdam Institute for Climate -# Impact Research -# -# URL: -# Contact: core@pik-potsdam.de -# License: BSD 2-clause license - -from ... import master_data_model as D -from ...data_model.master_data_model import CUL, I -from ... import Variable - - -class Model (object): - """Interface for Model mixin.""" - - # metadata: - name = "social learning of environmental friendliness" - """a unique name for the model component""" - description = "a certain fraction of individuals imitates a random " \ - "acquaintance's env. friendliness with a probability depending on " \ - "their surrounding terrestrial carbon density " - """some longer description""" - requires = [] - """list of other model components required for this model component to - make sense""" - - -# entity types: - - -class Individual (object): - """Interface for Individual entity type mixin.""" - - # endogenous variables: - is_environmentally_friendly = I.is_environmentally_friendly - - -# process taxa: - - -class Culture (object): - """Interface for Culture process taxon mixin.""" - - # exogenous variables / parameters: - environmental_friendliness_learning_rate = \ - Variable("environmental friendliness learning rate", - "rate at which a fraction of individuals learn " \ - "environmental (un)friendliness from neighbours", - unit=D.years**-1, lower_bound=0, default=1) - environmental_friendliness_learning_fraction = \ - Variable("awareness update fraction", - "fraction of individuals learning environmental " \ - "(un)friendliness simultaneously", - unit=D.unity, lower_bound=0, upper_bound=1, default=0.1) - environmental_friendliness_learning_density_quotient_offset = Variable( - "environmental friendliness learning density quotient offset", - "terrestrial carbon density quotient at which imitation probability " - "has its point of inflection", - unit=D.unity, is_intensive=True, default=1) - environmental_friendliness_learning_probability_characteristic_slope = Variable( - "environmental friendliness imitation probability's characteristic slope", - "slope of the normalized sigmoid function at its point of inflection", - unit=D.unity, is_intensive=True, default=1) diff --git a/pycopancore/model_components/social_learning_of_environmental_friendliness/model.py b/pycopancore/model_components/social_learning_of_environmental_friendliness/model.py deleted file mode 100644 index 66509619..00000000 --- a/pycopancore/model_components/social_learning_of_environmental_friendliness/model.py +++ /dev/null @@ -1,29 +0,0 @@ -"""Model mixing class template. -""" - -# This file is part of pycopancore. -# This file is part of pycopancore. -# -# Copyright (C) 2016-2017 by COPAN team at Potsdam Institute for Climate -# Impact Research -# -# URL: -# Contact: core@pik-potsdam.de -# License: BSD 2-clause license - -from . import interface as I -# import all needed entity type implementation classes: -from .implementation import Individual -# import all needed process taxon implementation classes: -from .implementation import Culture - - -class Model (I.Model): - """Model mixin class.""" - - # mixins provided by this model component: - - entity_types = [Individual] - """list of entity types augmented by this component""" - process_taxa = [Culture] - """list of process taxa augmented by this component""" diff --git a/pycopancore/model_components/voting_on_climate_policy/__init__.py b/pycopancore/model_components/voting_on_climate_policy/__init__.py deleted file mode 100644 index 6852092c..00000000 --- a/pycopancore/model_components/voting_on_climate_policy/__init__.py +++ /dev/null @@ -1,26 +0,0 @@ -""" -Model component package template. - -TODO: -Copy this folder, rename it to the name of your model component, -then adjust or fill in code and documentation in all modules wherever marked by "TODO:", -finally remove these instructions. -See the model component development tutorial for details. -""" - -# This file is part of pycopancore. -# -# Copyright (C) 2016-2017 by COPAN team at Potsdam Institute for Climate -# Impact Research -# -# URL: -# Contact: core@pik-potsdam.de -# License: BSD 2-clause license - -from . import interface - -# export all implementation classes: -from .implementation import * - -# export model component mixin class: -from .model import Model diff --git a/pycopancore/model_components/voting_on_climate_policy/implementation/__init__.py b/pycopancore/model_components/voting_on_climate_policy/implementation/__init__.py deleted file mode 100644 index 4927cda2..00000000 --- a/pycopancore/model_components/voting_on_climate_policy/implementation/__init__.py +++ /dev/null @@ -1,17 +0,0 @@ -""" -Model component implementation subpackage template. -""" - -# This file is part of pycopancore. -# -# Copyright (C) 2016-2017 by COPAN team at Potsdam Institute for Climate -# Impact Research -# -# URL: -# Contact: core@pik-potsdam.de -# License: BSD 2-clause license - -# export all provided entity type implementation mixin classes: -from .social_system import SocialSystem - -# export all provided process taxon implementation mixin classes: diff --git a/pycopancore/model_components/voting_on_climate_policy/implementation/social_system.py b/pycopancore/model_components/voting_on_climate_policy/implementation/social_system.py deleted file mode 100644 index 24086b00..00000000 --- a/pycopancore/model_components/voting_on_climate_policy/implementation/social_system.py +++ /dev/null @@ -1,57 +0,0 @@ -"""SocialSystem entity type mixing class template. - -TODO: adjust or fill in code and documentation wherever marked by "TODO:", -then remove these instructions -""" - -# This file is part of pycopancore. -# -# Copyright (C) 2016-2017 by COPAN team at Potsdam Institute for Climate -# Impact Research -# -# URL: -# Contact: core@pik-potsdam.de -# License: BSD 2-clause license - -from .. import interface as I -# from .... import master_data_model as D -from .... import Event -from numpy import array -from numpy.random import uniform - -class SocialSystem (I.SocialSystem): - """SocialSystem entity type mixin implementation class.""" - - voting_time_offset = None - - def next_voting_time(self, t): - if not self.voting_time_offset: - self.voting_time_offset = uniform() * self.time_between_votes - return (self.voting_time_offset - + self.time_between_votes - * ((t - self.voting_time_offset + 1e-10) // self.time_between_votes - + 1)) - - def take_a_vote(self, unused_t): - share = sum([i.population_share for i in self.individuals - if i.is_environmentally_friendly]) - self.has_renewable_subsidy = ( - (share > self.renewable_subsidy_intro_threshold) - if not self.has_renewable_subsidy - else (share > self.renewable_subsidy_keeping_threshold)) - self.has_emissions_tax = ( - (share > self.emissions_tax_intro_threshold) - if not self.has_emissions_tax - else (share > self.emissions_tax_keeping_threshold)) - self.has_fossil_ban = ( - (share > self.fossil_ban_intro_threshold) - if not self.has_fossil_ban - else (share > self.fossil_ban_keeping_threshold)) - - processes = [ - Event("voting", - [I.SocialSystem.has_renewable_subsidy, - I.SocialSystem.has_emissions_tax, - I.SocialSystem.has_fossil_ban], - ["time", next_voting_time, take_a_vote]) - ] diff --git a/pycopancore/model_components/voting_on_climate_policy/interface.py b/pycopancore/model_components/voting_on_climate_policy/interface.py deleted file mode 100644 index cba5775a..00000000 --- a/pycopancore/model_components/voting_on_climate_policy/interface.py +++ /dev/null @@ -1,96 +0,0 @@ -"""model component Interface template. - -TODO: adjust or fill in code and documentation wherever marked by "TODO:", then -remove these instructions. -""" - -# This file is part of pycopancore. -# -# Copyright (C) 2016-2017 by COPAN team at Potsdam Institute for Climate -# Impact Research -# -# URL: -# Contact: core@pik-potsdam.de -# License: BSD 2-clause license - -# TODO: use variables from the master data model wherever possible: -from ... import master_data_model as D -from ...data_model.master_data_model import S -# TODO: uncomment and adjust of you need further variables from another -# model component: -# import ..BBB.interface as BBB -# TODO: uncomment and adjust only if you really need other variables: -from ... import Variable - - -class Model (object): - """Interface for Model mixin.""" - - # metadata: - name = "voting on climate policy" - """a unique name for the model component""" - description = "individuals vote on different climate policy measures" \ - "based on their environmental friendliness" - """some longer description""" - requires = [] - """list of other model components required for this model component to - make sense""" - - -# entity types: - - -class SocialSystem (object): - """Interface for SocialSystem entity type mixin.""" - - # endogenous variables: - - has_renewable_subsidy = S.has_renewable_subsidy - has_emissions_tax = S.has_emissions_tax - has_fossil_ban = S.has_fossil_ban - - # exogenous variables / parameters: - - emissions_tax_level = S.emissions_tax_level - renewable_subsidy_level = S.renewable_subsidy_level - - time_between_votes = \ - Variable("time between votes", - "every how many years votes are taken", - unit=D.years, strict_lower_bound=0, default=4) - - renewable_subsidy_intro_threshold = \ - Variable("renewable subsidy introduction threshold", - "share of environmentally friendly voters needed to introduce" - "a subsidy for renewables", - unit=D.unity, lower_bound=0, upper_bound=1, default=1/2) - - emissions_tax_intro_threshold = \ - Variable("emissions tax introduction threshold", - "share of environmentally friendly voters needed to introduce" - "an emissions tax", - unit=D.unity, lower_bound=0, upper_bound=1, default=2/3) - - fossil_ban_intro_threshold = \ - Variable("fossil ban introduction threshold", - "share of environmentally friendly voters needed to ban" - "fossil fuels", - unit=D.unity, lower_bound=0, upper_bound=1, default=3/4) - - renewable_subsidy_keeping_threshold = \ - Variable("renewable subsidy keeping threshold", - "share of environmentally friendly voters needed to keep " - "a subsidy for renewables", - unit=D.unity, lower_bound=0, upper_bound=1, default=1/3) - - emissions_tax_keeping_threshold = \ - Variable("emissions tax keeping threshold", - "share of environmentally friendly voters needed to keep " - "an emissions tax", - unit=D.unity, lower_bound=0, upper_bound=1, default=1/2) - - fossil_ban_keeping_threshold = \ - Variable("fossil ban keeping threshold", - "share of environmentally friendly voters needed to keep " - "a ban on fossil fuels", - unit=D.unity, lower_bound=0, upper_bound=1, default=2/3) diff --git a/pycopancore/model_components/voting_on_climate_policy/model.py b/pycopancore/model_components/voting_on_climate_policy/model.py deleted file mode 100644 index 8c21529e..00000000 --- a/pycopancore/model_components/voting_on_climate_policy/model.py +++ /dev/null @@ -1,31 +0,0 @@ -"""Model mixing class template. - -TODO: adjust or fill in code and documentation wherever marked by "TODO:", -then remove these instructions -""" - -# This file is part of pycopancore. -# -# Copyright (C) 2016-2017 by COPAN team at Potsdam Institute for Climate -# Impact Research -# -# URL: -# Contact: core@pik-potsdam.de -# License: BSD 2-clause license - -from . import interface as I -# import all needed entity type implementation classes: -from .implementation import SocialSystem -# import all needed process taxon implementation classes: -#from .implementation import ... - - -class Model (I.Model): - """Model mixin class.""" - - # mixins provided by this model component: - - entity_types = [SocialSystem] - """list of entity types augmented by this component""" - process_taxa = [] - """list of process taxa augmented by this component""" diff --git a/pycopancore/model_components/wellbeing_driven_migration/__init__.py b/pycopancore/model_components/wellbeing_driven_migration/__init__.py deleted file mode 100644 index 6852092c..00000000 --- a/pycopancore/model_components/wellbeing_driven_migration/__init__.py +++ /dev/null @@ -1,26 +0,0 @@ -""" -Model component package template. - -TODO: -Copy this folder, rename it to the name of your model component, -then adjust or fill in code and documentation in all modules wherever marked by "TODO:", -finally remove these instructions. -See the model component development tutorial for details. -""" - -# This file is part of pycopancore. -# -# Copyright (C) 2016-2017 by COPAN team at Potsdam Institute for Climate -# Impact Research -# -# URL: -# Contact: core@pik-potsdam.de -# License: BSD 2-clause license - -from . import interface - -# export all implementation classes: -from .implementation import * - -# export model component mixin class: -from .model import Model diff --git a/pycopancore/model_components/wellbeing_driven_migration/implementation/__init__.py b/pycopancore/model_components/wellbeing_driven_migration/implementation/__init__.py deleted file mode 100644 index b7d4aa4c..00000000 --- a/pycopancore/model_components/wellbeing_driven_migration/implementation/__init__.py +++ /dev/null @@ -1,20 +0,0 @@ -""" -Model component implementation subpackage template. -""" - -# This file is part of pycopancore. -# -# Copyright (C) 2016-2017 by COPAN team at Potsdam Institute for Climate -# Impact Research -# -# URL: -# Contact: core@pik-potsdam.de -# License: BSD 2-clause license - -# TODO: adjust the following lists to your needs: - -# export all provided entity type implementation mixin classes: -from .social_system import SocialSystem - -# export all provided process taxon implementation mixin classes: -from .metabolism import Metabolism diff --git a/pycopancore/model_components/wellbeing_driven_migration/implementation/metabolism.py b/pycopancore/model_components/wellbeing_driven_migration/implementation/metabolism.py deleted file mode 100644 index de4443f3..00000000 --- a/pycopancore/model_components/wellbeing_driven_migration/implementation/metabolism.py +++ /dev/null @@ -1,18 +0,0 @@ -"""provides this model component' Metabolism mixin class""" - -# This file is part of pycopancore. -# -# Copyright (C) 2016-2017 by COPAN team at Potsdam Institute for Climate -# Impact Research -# -# URL: -# Contact: core@pik-potsdam.de -# License: BSD 2-clause license - -from .. import interface as I - - -class Metabolism (I.Metabolism): - """Metabolism process taxon mixin implementation class.""" - - processes = [] diff --git a/pycopancore/model_components/wellbeing_driven_migration/implementation/social_system.py b/pycopancore/model_components/wellbeing_driven_migration/implementation/social_system.py deleted file mode 100644 index cb246b0f..00000000 --- a/pycopancore/model_components/wellbeing_driven_migration/implementation/social_system.py +++ /dev/null @@ -1,78 +0,0 @@ -"""SocialSystem entity type mixing class template. -""" -# This file is part of pycopancore. -# -# Copyright (C) 2016-2017 by COPAN team at Potsdam Institute for Climate -# Impact Research -# -# URL: -# Contact: core@pik-potsdam.de -# License: BSD 2-clause license - -from .... import Explicit, ODE -from ...base import interface as B - -from .. import interface as I - -import sympy as sp # to be able to use symbolic constants and functions - - -class SocialSystem (I.SocialSystem): - """SocialSystem entity type mixin implementation class.""" - - # abbreviations: - basic_rate = B.SocialSystem.metabolism.basic_emigration_probability_rate - slope = B.SocialSystem.metabolism.emigration_probability_characteristic_slope - offset = B.SocialSystem.metabolism.emigration_wellbeing_quotient_offset - - # for pairwise migration formula: - this_social_system = I.SocialSystem - other_social_system = B.SocialSystem.world.social_systems # we will sum about all those! - - processes = [ - - Explicit("emigration", - [this_social_system.emigration], - [basic_rate - * this_social_system.population - * B.SocialSystem.world.sum( # here is the summation - other_social_system.population - * (1/2 + 1/sp.pi * sp.atan( - sp.pi - * slope - * sp.log(other_social_system.wellbeing - / this_social_system.wellbeing - / offset) - ) - ) - ) - ]), - - Explicit("immigration", - [this_social_system.immigration], - [basic_rate - * this_social_system.population - * B.SocialSystem.world.sum( # here is the summation again - other_social_system.population - * (1/2 + 1/sp.pi * sp.atan( - sp.pi - * slope - * sp.log(this_social_system.wellbeing - / other_social_system.wellbeing - / offset) - ) - ) - ) - ]), - - ODE("effect of migration", - [I.SocialSystem.population, - I.SocialSystem.migrant_population], - [I.SocialSystem.immigration - - I.SocialSystem.emigration, - I.SocialSystem.immigration - # assuming an equal emigration probability among migrants: - - I.SocialSystem.emigration * I.SocialSystem.migrant_population - / I.SocialSystem.population]) - - ] diff --git a/pycopancore/model_components/wellbeing_driven_migration/interface.py b/pycopancore/model_components/wellbeing_driven_migration/interface.py deleted file mode 100644 index bab50399..00000000 --- a/pycopancore/model_components/wellbeing_driven_migration/interface.py +++ /dev/null @@ -1,80 +0,0 @@ -"""model component Interface template. -""" - -# This file is part of pycopancore. -# -# Copyright (C) 2016-2017 by COPAN team at Potsdam Institute for Climate -# Impact Research -# -# URL: -# Contact: core@pik-potsdam.de -# License: BSD 2-clause license - -# TODO: use variables from the master data model wherever possible: -from ... import master_data_model as D -from ...data_model.master_data_model import MET, S -from ... import Variable - - -class Model (object): - """Interface for Model mixin.""" - - # metadata: - name = "wellbeing-driven migration" - """a unique name for the model component""" - description = "migration flow between social_systems is proportional to a " \ - "sigmoid function of wellbeing difference and product of populations" - """some longer description""" - requires = [] - """list of other model components required for this model component to - make sense""" - - -# entity types: - - -class SocialSystem (object): - """Interface for SocialSystem entity type mixin.""" - - # endogenous variables: - - immigration = S.immigration - emigration = S.emigration - - migrant_population = S.migrant_population - - # exogenous variables / parameters: - - population = S.population - wellbeing = S.wellbeing - - -# process taxa: - - -class Metabolism (object): - """Interface for Metabolism process taxon mixin.""" - - # endogenous variables: - - # exogenous variables / parameters: - emigration_wellbeing_quotient_offset = Variable( - "emigration wellbeing quotient offset", - "wellbeing quotient at which emigration probability has its point " - "of inflection", - unit = D.unity, - is_intensive=True, - default=3) # 1 - emigration_probability_characteristic_slope = Variable( - "emigration probability's characteristic slope", - "slope of the normalized sigmoid function at its point of inflection", - unit = D.unity, - is_intensive=True, - default=1) - basic_emigration_probability_rate = Variable( - "basic emigration probability rate", - "absolute value of emigration probability rate at its point of inflection", - unit = D.years**-1 / D.people**2, - lower_bound=0, is_intensive=True, - default = 8e-13) # 3e-13 - \ No newline at end of file diff --git a/pycopancore/model_components/wellbeing_driven_migration/model.py b/pycopancore/model_components/wellbeing_driven_migration/model.py deleted file mode 100644 index add78cd2..00000000 --- a/pycopancore/model_components/wellbeing_driven_migration/model.py +++ /dev/null @@ -1,28 +0,0 @@ -"""Model mixing class template. -""" - -# This file is part of pycopancore. -# -# Copyright (C) 2016-2017 by COPAN team at Potsdam Institute for Climate -# Impact Research -# -# URL: -# Contact: core@pik-potsdam.de -# License: BSD 2-clause license - -from . import interface as I -# import all needed entity type implementation classes: -from .implementation import SocialSystem -# import all needed process taxon implementation classes: -from .implementation import Metabolism - - -class Model (I.Model): - """Model mixin class.""" - - # mixins provided by this model component: - - entity_types = [SocialSystem] - """list of entity types augmented by this component""" - process_taxa = [Metabolism] - """list of process taxa augmented by this component""" diff --git a/pycopancore/models/_testing/__init__.py b/pycopancore/models/_testing/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/pycopancore/models/_testing/generic_imitation/like_example1.py b/pycopancore/models/_testing/generic_imitation/like_example1.py new file mode 100644 index 00000000..1f894c7f --- /dev/null +++ b/pycopancore/models/_testing/generic_imitation/like_example1.py @@ -0,0 +1,139 @@ +"""jobsts_prototype_1 model adapted to test generic_imitation component.""" + +# This file is part of pycopancore. +# +# Copyright (C) 2016-2021 by COPAN team at Potsdam Institute for Climate +# Impact Research +# +# URL: +# Contact: core@pik-potsdam.de +# License: BSD 2-clause license + +# +# Imports +# + +import numpy as np + +from .... import base # all models must use the base component + +from ....model_components import copan_global_like_carbon_cycle \ + as cc +from ....model_components import copan_global_like_production \ + as prod +from ....model_components import copan_global_like_economic_growth \ + as growth +from ....model_components import copan_global_like_population_growth \ + as pop +from ....model_components import wellbeing_driven_migration \ + as mig +from ....model_components import environmental_awareness \ + as aware +#from ...model_components import social_learning_of_environmental_friendliness \ +# as learn +from ....model_components import voting_on_climate_policy \ + as vote + +from ....model_components import config +config.generic_imitation = {'variables': [base.interface.Culture.individuals.is_environmentally_friendly, + base.interface.Culture.social_systems.has_emissions_tax, + base.interface.Culture.social_systems.emissions_tax_level]} + +from ....model_components import generic_imitation as imi + + +# entity types: + +class World(cc.World, + prod.World, + growth.World, + base.World): + """World entity type.""" + pass + + +class SocialSystem(prod.SocialSystem, + growth.SocialSystem, + pop.SocialSystem, + mig.SocialSystem, + aware.SocialSystem, + vote.SocialSystem, + base.SocialSystem): + """SocialSystem entity type.""" + pass + + +class Cell(cc.Cell, + prod.Cell, + aware.Cell, + base.Cell): + """Cell entity type.""" + pass + + +class Individual(aware.Individual, +# learn.Individual, + base.Individual): + """Individual entity type.""" + + def imi_p_imitate_env(self, own_trait=None, other_trait=None): + return 1 / (1 + np.exp(self.relative_weight)) + + def imi_imitate_env(self, variables=None, values=None): + for index, var in enumerate(variables): + var.set_value(self, values[index]) + +# process taxa: + + +class Environment(cc.Environment, + base.Environment): + """Environment process taxon.""" + pass + + +class Metabolism(prod.Metabolism, + growth.Metabolism, + pop.Metabolism, + mig.Metabolism, + base.Metabolism): + """Metabolism process taxon.""" + pass + + +class Culture (aware.Culture, +# learn.Culture, + imi.Culture, + base.Culture): + """Culture process taxon""" + + imi.Culture.imi_traits.default = { + 'env': (aware.Individual.is_environmentally_friendly,), + 'tax': (prod.SocialSystem.has_emissions_tax, prod.SocialSystem.emissions_tax_level) + } + + +# Model class: + + +class Model(cc.Model, + prod.Model, + growth.Model, + pop.Model, + mig.Model, + aware.Model, +# learn.Model, + imi.Model, + vote.Model, + base.Model): + """Class representing the whole model.""" + + name = "Jobst's prototype 1" + """Name of the model""" + description = "(as presented internally at PIK in fall 2016)" + """Longer description""" + + entity_types = [World, SocialSystem, Cell, Individual] + """List of entity types used in the model""" + process_taxa = [Environment, Metabolism, Culture] + """List of process taxa used in the model""" diff --git a/pycopancore/models/_testing/generic_imitation/other_component.py b/pycopancore/models/_testing/generic_imitation/other_component.py new file mode 100644 index 00000000..b83a59ce --- /dev/null +++ b/pycopancore/models/_testing/generic_imitation/other_component.py @@ -0,0 +1,48 @@ +from .... import master_data_model as D +from .... import Variable + +# INTERFACE: + +class ISocialSystem (object): + is_active = Variable( + "a boolean variable", "", scale='nominal', datatype=bool) + +class ICell (object): + an_ordinal_var = Variable( + "an ordinal variable", "e.g., a Likert scale", scale='ordinal', datatype=int, + levels=[1, 2, 3, 4, 5]) + +class IIndividual (object): + a_nominal_var = Variable( + "a nominal (categorical) variable", "", scale='nominal', datatype=str, + levels=['a', 'b', 'c']) + a_dimensional_var = Variable( + "a dimensional variable", "", unit=D.dollars) + a_criterion = Variable( + "a fitness criterion", "e.g. income") + +class IModel (object): + name = "other component" + description = "only for testing generic_imitation" + requires = [] + +class interface: + SocialSystem = ISocialSystem + Cell = ICell + Individual = IIndividual + Model = IModel + +# IMPLEMENTATION: + +class SocialSystem (ISocialSystem): + processes = [] + +class Cell (ICell): + processes = [] + +class Individual (IIndividual): + processes = [] + +class Model (IModel): + entity_types = [SocialSystem, Cell, Individual] + process_taxa = [] diff --git a/pycopancore/models/_testing/generic_imitation/simple.py b/pycopancore/models/_testing/generic_imitation/simple.py new file mode 100755 index 00000000..8643e4fb --- /dev/null +++ b/pycopancore/models/_testing/generic_imitation/simple.py @@ -0,0 +1,44 @@ +import numpy as np + +from .... import base # all models must use the base component + +from . import other_component as other + +from ....model_components import config +config.generic_imitation = {'variables': [base.interface.Culture.social_systems.is_active, + base.interface.Culture.social_systems.cells.an_ordinal_var, + base.interface.Culture.individuals.a_nominal_var, + base.interface.Culture.individuals.a_dimensional_var]} + +from ....model_components import generic_imitation as imi + + +class World(base.World): + pass + +class SocialSystem(other.SocialSystem, base.SocialSystem): + pass + +class Cell(other.Cell, base.Cell): + def imi_p_imitate_ord(self, own_trait=None, other_trait=None): + return 1.0 if np.abs(other_trait[0] - own_trait[0]) <= 2 else 0.0 + +class Individual(other.Individual, base.Individual): + def imi_evaluate_pair(self, other=None): + return other.a_criterion + + +class Culture (imi.Culture, base.Culture): + + imi.Culture.imi_traits.default = { + 'bool': (other.SocialSystem.is_active,), + 'ord': (other.Cell.an_ordinal_var,), + 'pair': (other.Individual.a_nominal_var, other.Individual.a_dimensional_var) + } + + +class Model(other.Model, imi.Model, base.Model): + name = "Simple test of generic_imitation component" + description = "uses only one other component" + entity_types = [World, SocialSystem, Cell, Individual] + process_taxa = [Culture] diff --git a/pycopancore/models/adaptive_voter_model.py b/pycopancore/models/adaptive_voter_model.py deleted file mode 100644 index 3af4ed68..00000000 --- a/pycopancore/models/adaptive_voter_model.py +++ /dev/null @@ -1,108 +0,0 @@ -""" -Model class adaptive_voter_model. -""" - -# This file is part of pycopancore. -# -# Copyright (C) 2016-2017 by COPAN team at Potsdam Institute for Climate -# Impact Research -# -# URL: -# Contact: core@pik-potsdam.de -# License: BSD 2-clause license - -# -# Imports -# - -from .. import base # all models must use the base component - -from ..model_components import adaptive_voter_opinion_formation as avof -from ..model_components import majority_decision as md - - -# entity types: - -# NEED TO: compose all needed entity type implementation classes -# by mixing the above model components' mixin classes of the same name. -# Only compose those entity types and process taxons that the model needs, -# delete the templates for the unneeded ones, and add those for missing ones: - -# NEED TO: list all mixin classes needed: -class World(base.World): - """World entity type.""" - - pass - - -# NEED TO: list all mixin classes needed: -class SocialSystem(md.SocialSystem, - base.SocialSystem): - """SocialSystem entity type.""" - - pass - - -# NEED TO: list all mixin classes needed: -class Cell(base.Cell): - """Cell entity type.""" - - pass - - -# NEED TO: list all mixin classes needed: -class Individual(avof.Individual, - md.Individual, - base.Individual): - """Individual entity type.""" - - pass - - -# process taxa: - -# NEED TO: do the same for process taxa: - - -# NEED TO: list all mixin classes needed: -# class Environment ( -# base.Environment): -# """Environment process taxon.""" -# -# pass - - -# NEED TO: list all mixin classes needed: -# class Metabolism ( -# base.Metabolism): -# """Metabolism process taxon.""" -# -# pass - - -# NEED TO: list all mixin classes needed: -class Culture(avof.Culture, md.Culture, - base.Culture): - """Culture process taxon.""" - - pass - - -# Model class: - -# NEED TO: list all used model components: -class Model(avof.Model, md.Model, - base.Model): - """Class representing the whole model.""" - - name = "..." - """Name of the model""" - description = "..." - """Longer description""" - - # NEED TO: list all entity types you composed above: - entity_types = [World, SocialSystem, Individual] - """List of entity types used in the model""" - # NEED TO: list all entity types you composed above: - process_taxa = [Culture] - """List of process taxa used in the model""" diff --git a/pycopancore/models/base_and_dummy.py b/pycopancore/models/base_and_dummy.py deleted file mode 100644 index 466f09f7..00000000 --- a/pycopancore/models/base_and_dummy.py +++ /dev/null @@ -1,80 +0,0 @@ -"""Dummy model to create model modules.""" - -# This file is part of pycopancore. -# -# Copyright (C) 2016-2017 by COPAN team at Potsdam Institute for Climate -# Impact Research -# -# URL: -# Contact: core@pik-potsdam.de -# License: BSD 2-clause license - -# -# Imports -# - -import pycopancore.model_components.base as base -import pycopancore.model_components.dummy as dummy - -# -# Entity Types -# - - -class World(base.World): - """Class to mix all World_mixins to create World clas.""" - - pass - - -class Cell(dummy.Cell, base.Cell): - """Class to mix all Cell_mixins to create Cell class.""" - - pass - - -class Individual(base.Individual): - """Class to mix all Individual_mixins to create Individual class.""" - - pass - - -class SocialSystem(base.SocialSystem): - """Class to mix all SocialSystem_mixins to create SocialSystem class.""" - - pass - -# -# Dynamics -# - - -class Culture(base.Culture): - """Class to mix all Culture_mixins to create Culture class.""" - - pass - - -class Metabolism(base.Metabolism): - """Class to mix all Metabolism_mixins to create Metabolism class.""" - - pass - - -class Environment(base.Environment): - """Class to mix all Environment_mixins to create Environment class.""" - - pass - -# -# Models -# - - -class Model(dummy.Model, base.Model): - """Class to mix all Model_mixins to create Model class.""" - - name = "This model's name" - description = "Description of the model" - entity_types = [Cell, Individual, SocialSystem, World] - process_taxa = [Culture, Metabolism, Environment] diff --git a/pycopancore/models/carbon_voters_anderies_model.py b/pycopancore/models/carbon_voters_anderies_model.py deleted file mode 100644 index ba27f6ad..00000000 --- a/pycopancore/models/carbon_voters_anderies_model.py +++ /dev/null @@ -1,114 +0,0 @@ -"""Model class carbon_voters_anderies_model.""" - -# This file is part of pycopancore. -# -# Copyright (C) 2016-2017 by COPAN team at Potsdam Institute for Climate -# Impact Research -# -# URL: -# Contact: core@pik-potsdam.de -# License: BSD 2-clause license - -# -# Imports -# - -from .. import base # all models must use the base component - -from ..model_components import adaptive_voter_opinion_formation as avof -from ..model_components import majority_decision as md -from ..model_components import anderies_carbon_cycle as cc -from ..model_components import carbon_voters as cv - - -# entity types: - -# NEED TO: compose all needed entity type implementation classes -# by mixing the above model components' mixin classes of the same name. -# Only compose those entity types and process taxons that the model needs, -# delete the templates for the unneeded ones, and add those for missing ones: - -# NEED TO: list all mixin classes needed: -class World(cc.World, - cv.World, - base.World): - """World entity type.""" - - pass - - -# NEED TO: list all mixin classes needed: -class SocialSystem(md.SocialSystem, - cv.SocialSystem, - cc.SocialSystem, - base.SocialSystem): - """SocialSystem entity type.""" - - pass - - -# NEED TO: list all mixin classes needed: -class Cell(cc.Cell, - base.Cell): - """Cell entity type.""" - - pass - - -# NEED TO: list all mixin classes needed: -class Individual(avof.Individual, - md.Individual, - base.Individual): - """Individual entity type.""" - - pass - - -# process taxa: - -# NEED TO: do the same for process taxa: - - -# NEED TO: list all mixin classes needed: -class Environment(cc.Environment, - base.Environment): - """Environment process taxon.""" - - -# NEED TO: list all mixin classes needed: -class Metabolism(base.Metabolism): - """Metabolism process taxon.""" - - pass - - -# NEED TO: list all mixin classes needed: -class Culture(avof.Culture, - cv.Culture, - base.Culture): - """Culture process taxon.""" - - pass - - -# Model class: - -# NEED TO: list all used model components: -class Model(avof.Model, - md.Model, - cc.Model, - cv.Model, - base.Model): - """Class representing the whole model.""" - - name = "..." - """Name of the model""" - description = "..." - """Longer description""" - - # NEED TO: list all entity types you composed above: - entity_types = [World, SocialSystem, Individual, Cell] - """List of entity types used in the model""" - # NEED TO: list all entity types you composed above: - process_taxa = [Culture, Environment] - """List of process taxa used in the model""" diff --git a/pycopancore/models/coccon/carboncycle.py b/pycopancore/models/coccon/carboncycle.py deleted file mode 100644 index ba9ff796..00000000 --- a/pycopancore/models/coccon/carboncycle.py +++ /dev/null @@ -1,80 +0,0 @@ -# This file is part of pycopancore. -# -# Copyright (C) 2016-2017 by COPAN team at Potsdam Institute for Climate -# Impact Research -# -# URL: -# Contact: core@pik-potsdam.de -# License: BSD 2-clause license - -from ... import base # all models must use the base component - -from ...model_components import copan_global_like_carbon_cycle \ - as cc - - -# entity types: - - -class World(cc.World, - base.World): - """World entity type.""" - - pass - - -class SocialSystem(base.SocialSystem): - """SocialSystem entity type.""" - - pass - - -class Cell(cc.Cell, - base.Cell): - """Cell entity type.""" - - pass - - -class Individual(base.Individual): - """Individual entity type.""" - pass - - -# process taxa: - - -class Environment(cc.Environment, - base.Environment): - """Environment process taxon.""" - - pass - - -class Metabolism(base.Metabolism): - """Metabolism process taxon.""" - - pass - - -class Culture (base.Culture): - """Culture process taxon""" - pass - - -# Model class: - - -class Model(cc.Model, - base.Model): - """Class representing the whole model.""" - - name = "CoCCoN tutorial model, only carbon cycle" - """Name of the model""" - description = "(as presented at PIK in fall 2017)" - """Longer description""" - - entity_types = [World, SocialSystem, Cell, Individual] - """List of entity types used in the model""" - process_taxa = [Environment, Metabolism, Culture] - """List of process taxa used in the model""" diff --git a/pycopancore/models/coccon/full.py b/pycopancore/models/coccon/full.py deleted file mode 100644 index e2e3db6f..00000000 --- a/pycopancore/models/coccon/full.py +++ /dev/null @@ -1,122 +0,0 @@ -# This file is part of pycopancore. -# -# Copyright (C) 2016-2017 by COPAN team at Potsdam Institute for Climate -# Impact Research -# -# URL: -# Contact: core@pik-potsdam.de -# License: BSD 2-clause license - -from ... import base # all models must use the base component - -from ...model_components import copan_global_like_carbon_cycle \ - as cc -from ...model_components import copan_global_like_production \ - as prod -from ...model_components import copan_global_like_economic_growth \ - as growth -from ...model_components import copan_global_like_population_growth \ - as pop -from ...model_components import wellbeing_driven_migration \ - as mig -from ...model_components import environmental_awareness \ - as aware -from ...model_components import social_learning_of_environmental_friendliness \ - as learn -from ...model_components import voting_on_climate_policy \ - as vote - - -# entity types: - - -class World(cc.World, - prod.World, - growth.World, - base.World): - """World entity type.""" - - pass - - -class SocialSystem( - prod.SocialSystem, - growth.SocialSystem, - pop.SocialSystem, - mig.SocialSystem, - aware.SocialSystem, - vote.SocialSystem, - base.SocialSystem): - """SocialSystem entity type.""" - - pass - - -class Cell(cc.Cell, - prod.Cell, - base.Cell): - """Cell entity type.""" - - pass - - -class Individual( - aware.Individual, - learn.Individual, - base.Individual): - """Individual entity type.""" - pass - - -# process taxa: - - -class Environment(cc.Environment, - base.Environment): - """Environment process taxon.""" - - pass - - -class Metabolism( - prod.Metabolism, - growth.Metabolism, - pop.Metabolism, - mig.Metabolism, - base.Metabolism): - """Metabolism process taxon.""" - - pass - - -class Culture ( - aware.Culture, - learn.Culture, - base.Culture): - """Culture process taxon""" - pass - - -# Model class: - - -class Model(cc.Model, - prod.Model, - growth.Model, - pop.Model, - mig.Model, - aware.Model, - learn.Model, - vote.Model, - base.Model): - """Class representing the whole model.""" - - name = "CoCCoN tutorial model" - """Name of the model""" - description = "(as presented at PIK in fall 2017)" - """Longer description""" - - entity_types = [World, SocialSystem, Cell, Individual] - """List of entity types used in the model""" - process_taxa = [Environment, Metabolism, Culture] - """List of process taxa used in the model""" diff --git a/pycopancore/models/example1.py b/pycopancore/models/example1.py deleted file mode 100644 index eba53869..00000000 --- a/pycopancore/models/example1.py +++ /dev/null @@ -1,126 +0,0 @@ -"""jobsts_prototype_1 model.""" - -# This file is part of pycopancore. -# -# Copyright (C) 2016-2017 by COPAN team at Potsdam Institute for Climate -# Impact Research -# -# URL: -# Contact: core@pik-potsdam.de -# License: BSD 2-clause license - -# -# Imports -# - -from .. import base # all models must use the base component - -from ..model_components import copan_global_like_carbon_cycle \ - as cc -from ..model_components import copan_global_like_production \ - as prod -from ..model_components import copan_global_like_economic_growth \ - as growth -from ..model_components import copan_global_like_population_growth \ - as pop -from ..model_components import wellbeing_driven_migration \ - as mig -from ..model_components import environmental_awareness \ - as aware -from ..model_components import social_learning_of_environmental_friendliness \ - as learn -from ..model_components import voting_on_climate_policy \ - as vote - -# entity types: - - -class World(cc.World, - prod.World, - growth.World, - base.World): - """World entity type.""" - - pass - - -class SocialSystem( - prod.SocialSystem, - growth.SocialSystem, - pop.SocialSystem, - mig.SocialSystem, - aware.SocialSystem, - vote.SocialSystem, - base.SocialSystem): - """SocialSystem entity type.""" - - pass - - -class Cell(cc.Cell, - prod.Cell, - aware.Cell, - base.Cell): - """Cell entity type.""" - - pass - - -class Individual(aware.Individual, - learn.Individual, - base.Individual): - """Individual entity type.""" - pass - - -# process taxa: - - -class Environment(cc.Environment, - base.Environment): - """Environment process taxon.""" - - pass - - -class Metabolism( - prod.Metabolism, - growth.Metabolism, - pop.Metabolism, - mig.Metabolism, - base.Metabolism): - """Metabolism process taxon.""" - - pass - - -class Culture (aware.Culture, - learn.Culture, - base.Culture): - """Culture process taxon""" - pass - - -# Model class: - - -class Model(cc.Model, - prod.Model, - growth.Model, - pop.Model, - mig.Model, - aware.Model, - learn.Model, - vote.Model, - base.Model): - """Class representing the whole model.""" - - name = "Jobst's prototype 1" - """Name of the model""" - description = "(as presented internally at PIK in fall 2016)" - """Longer description""" - - entity_types = [World, SocialSystem, Cell, Individual] - """List of entity types used in the model""" - process_taxa = [Environment, Metabolism, Culture] - """List of process taxa used in the model""" diff --git a/pycopancore/models/example2.py b/pycopancore/models/example2.py deleted file mode 100644 index 61cf6850..00000000 --- a/pycopancore/models/example2.py +++ /dev/null @@ -1,114 +0,0 @@ -"""jobsts_prototype_2 model.""" - -# This file is part of pycopancore. -# -# Copyright (C) 2016-2017 by COPAN team at Potsdam Institute for Climate -# Impact Research -# -# URL: -# Contact: core@pik-potsdam.de -# License: BSD 2-clause license - -# -# Imports -# - -from .. import base # all models must use the base component - -from ..model_components import copan_global_like_carbon_cycle \ - as cc -from ..model_components import copan_global_like_production \ - as prod -from ..model_components import copan_global_like_economic_growth \ - as growth -from ..model_components import environmental_awareness \ - as aware -from ..model_components import social_learning_of_environmental_friendliness \ - as learn -from ..model_components import voting_on_climate_policy \ - as vote - - -# entity types: - -class World(cc.World, - prod.World, - growth.World, - base.World): - """World entity type.""" - - pass - - -class SocialSystem(prod.SocialSystem, - growth.SocialSystem, - aware.SocialSystem, - vote.SocialSystem, - base.SocialSystem): - """SocialSystem entity type.""" - - pass - - -class Cell(cc.Cell, - prod.Cell, - aware.Cell, - base.Cell): - """Cell entity type.""" - - pass - - -class Individual(aware.Individual, - learn.Individual, - base.Individual): - """Individual entity type.""" - pass - - -# process taxa: - - -class Environment(cc.Environment, - base.Environment): - """Environment process taxon.""" - - pass - - -class Metabolism(prod.Metabolism, - growth.Metabolism, - base.Metabolism): - """Metabolism process taxon.""" - - pass - - -class Culture (aware.Culture, - learn.Culture, - base.Culture): - """Culture process taxon""" - pass - - -# Model class: - - -class Model(cc.Model, - prod.Model, - growth.Model, - aware.Model, - learn.Model, - vote.Model, - base.Model): - """Class representing the whole model.""" - - name = "Jobst's prototype 2" - """Name of the model""" - description = "(as suggested in the paper revision plan)" - """Longer description""" - - entity_types = [World, SocialSystem, Cell, Individual] - """List of entity types used in the model""" - process_taxa = [Environment, Metabolism, Culture] - """List of process taxa used in the model""" diff --git a/pycopancore/models/exodus.py b/pycopancore/models/exodus.py deleted file mode 100644 index 29486b7d..00000000 --- a/pycopancore/models/exodus.py +++ /dev/null @@ -1,72 +0,0 @@ -"""Model class of model Exodus.""" - -# This file is part of pycopancore. -# -# Copyright (C) 2016-2017 by COPAN team at Potsdam Institute for Climate -# Impact Research -# -# URL: -# Contact: core@pik-potsdam.de -# License: BSD 2-clause license - -from .. import base # all models must use the base component -from ..model_components import exodus as ex - - -class World(ex.World, - base.World): - """World entity type.""" - - pass - - -class SocialSystem(ex.SocialSystem, - base.SocialSystem): - """SocialSystem entity type.""" - - pass - - -class Cell(ex.Cell, - base.Cell): - """Cell entity type.""" - - pass - - -class Individual(ex.Individual, - base.Individual): - """Individual entity type.""" - - pass - - -# process taxa: -class Metabolism(ex.Metabolism, - base.Metabolism): - """Metabolism process taxon.""" - - pass - - -class Culture(ex.Culture, - base.Culture): - """Culture process taxon.""" - - pass - - -# Model class: - -# NEED TO: list all used model components: -class Model(ex.Model, - base.Model): - """Class representing the whole model.""" - - name = "Exodus" - description = "Model describing rural-urban migration." - - entity_types = [World, SocialSystem, Cell, Individual] - """List of entity types used in the model""" - process_taxa = [Metabolism, Culture] - """List of process taxa used in the model""" diff --git a/pycopancore/models/exploit.py b/pycopancore/models/exploit.py deleted file mode 100644 index 118b641f..00000000 --- a/pycopancore/models/exploit.py +++ /dev/null @@ -1,90 +0,0 @@ -""" -Exploit model. - -The exploit model is including the modules base, -most_simple_vegetation, simple_extraction -and exploit_simple_learning. -It is based on the cython implementation cyexploit -(see https://github.com/wbarfuss/cyexploit ) -""" - -# This file is part of pycopancore. -# -# Copyright (C) 2016-2017 by COPAN team at Potsdam Institute for Climate -# Impact Research -# -# URL: -# Contact: core@pik-potsdam.de -# License: BSD 2-clause license - -# -# Imports -# - -import pycopancore.model_components.base as base -import pycopancore.model_components.most_simple_vegetation as vegetation -import pycopancore.model_components.simple_extraction as extraction -import pycopancore.model_components.exploit_social_learning as social_learning - -# -# Entity Types -# - - -class World(social_learning.World, - base.World): - """Class to mix all World_mixins to create World class.""" - - pass - - -class SocialSystem(base.SocialSystem): - """Class to mix all SocialSystem_mixins to create SocialSystem class.""" - - pass - - -class Cell(vegetation.Cell, - extraction.Cell, - base.Cell): - """Class to mix all Cell_mixins to create Cell class.""" - - pass - - -# Order is important: extraction.Individual before social_learning.Individual -# because of the get_harvest_rate() method that should be overwritten. -class Individual(extraction.Individual, - social_learning.Individual, - base.Individual): - """Class to mix all Individual_mixins to create Individual class.""" - - pass - -# -# Dynamics -# - - -class Culture(social_learning.Culture, - base.Culture): - """Class to mix all Culture_mixins to create Culture class.""" - - pass - -# -# Models -# - - -class Model(vegetation.Model, - extraction.Model, - social_learning.Model, - base.Model): - """Class to mix all Model_mixins to create Model class.""" - - name = "Exploit model" - description = "COPAN:Exploit model" - - entity_types = [World, SocialSystem, Cell, Individual] - process_taxa = [Culture] diff --git a/pycopancore/models/groups_seven_dwarfs.py b/pycopancore/models/groups_seven_dwarfs.py deleted file mode 100644 index 6c823150..00000000 --- a/pycopancore/models/groups_seven_dwarfs.py +++ /dev/null @@ -1,90 +0,0 @@ -"""Model class seven_dwarfs.""" - -# This file is part of pycopancore. -# -# Copyright (C) 2016-2017 by COPAN team at Potsdam Institute for Climate -# Impact Research -# -# URL: -# Contact: core@pik-potsdam.de -# License: BSD 2-clause license - -# -# Imports -# - -from .. import base # all models must use the base component - -from ..model_components import seven_dwarfs as sd -from ..model_components import snowwhite as sw - -# entity types: - -# by mixing the above model components' mixin classes of the same name. -# Only compose those entity types and process taxons that the model needs, -# delete the templates for the unneeded ones, and add those for missing ones: - - -class World(sd.World, - base.World): - """World entity type.""" - - pass - - -class SocialSystem(base.SocialSystem): - """SocialSystem entity type.""" - - pass - - -class Cell(sd.Cell, - sw.Cell, - base.Cell): - """Cell entity type.""" - - pass - - -class Individual(sd.Individual, - base.Individual): - """Individual entity type.""" - - pass - - -class SocialSystem(sd.SocialSystem, - base.SocialSystem): - """SocialSystem entity type.""" - - pass - -class Group(sd.Group, - base.Group): - """Groups entity type""" - -# process taxa: - -class Culture(sd.Culture, - base.Culture): - """Culture process taxon.""" - - pass - - -# Model class: - -class Model(sd.Model, - sw.Model, - base.Model): - """Class representing the whole model.""" - - name = "Seven dwarfs" - """Name of the model""" - description = "Tutorial model" - """Longer description""" - - entity_types = [World, SocialSystem, Cell, Individual, Group] - """List of entity types used in the model""" - process_taxa = [Culture] - """List of process taxa used in the model""" diff --git a/pycopancore/models/only_copan_global_like_carbon_cycle.py b/pycopancore/models/only_copan_global_like_carbon_cycle.py deleted file mode 100644 index cd7dcfb0..00000000 --- a/pycopancore/models/only_copan_global_like_carbon_cycle.py +++ /dev/null @@ -1,102 +0,0 @@ -"""jobsts_prototype_1 model, reduced to carbon cycle only.""" - -# This file is part of pycopancore. -# -# Copyright (C) 2016-2017 by COPAN team at Potsdam Institute for Climate -# Impact Research -# -# URL: -# Contact: core@pik-potsdam.de -# License: BSD 2-clause license - -# -# Imports -# - -from .. import base # all models must use the base component - -from ..model_components import copan_global_like_carbon_cycle \ - as cc -# from ..model_components import copan_global_like_production \ -# as prod -# from ..model_components import copan_global_like_economic_growth \ -# as growth -# from ..model_components import copan_global_like_population_growth \ -# as population -# from ..model_components import ...migration \ -# as migration - - -# entity types: - - -class World(cc.World, - # prod.World, - base.World): - """World entity type.""" - - pass - - -class SocialSystem(base.SocialSystem): - # prod.SocialSystem, - # growth.SocialSystem): - """SocialSystem entity type.""" - - pass - - -class Cell(cc.Cell, - # prod.Cell, - base.Cell): - """Cell entity type.""" - - pass - -# class Individual (ABBR1.Individual, ABBR2.Individual, -# base.Individual): -# """Individual entity type.""" -# pass - - -# process taxa: - - -class Environment(cc.Environment, - base.Environment): - """Environment process taxon.""" - - pass - - -class Metabolism(base.Metabolism): - # , prod.Metabolism): - """Metabolism process taxon.""" - - pass - -# class Culture (ABBR1.Culture, ABBR2.Culture, -# base.Culture): -# """Culture process taxon.""" - -# pass - - -# Model class: - - -class Model(cc.Model, - # prod.Model, - # growth.Model, - base.Model): - """Class representing the whole model.""" - - name = "Jobst's prototype 1, only CC" - """Name of the model""" - description = "(as presented internally at PIK in fall 2016)" - """Longer description""" - - entity_types = [World, SocialSystem, Cell] - """List of entity types used in the model""" - process_taxa = [Environment, Metabolism] - """List of process taxa used in the model""" diff --git a/pycopancore/models/our_model.py b/pycopancore/models/our_model.py deleted file mode 100644 index 72bea62b..00000000 --- a/pycopancore/models/our_model.py +++ /dev/null @@ -1,105 +0,0 @@ -"""Model class our_model.""" - -# This file is part of pycopancore. -# -# Copyright (C) 2016-2017 by COPAN team at Potsdam Institute for Climate -# Impact Research -# -# URL: -# Contact: core@pik-potsdam.de -# License: BSD 2-clause license - -# -# Imports -# - -from .. import base # all models must use the base component -# from ..model_components import copan_global_like_carbon_cycle \ -# as cc -from ..model_components import anderies_carbon_cycle \ - as cc - -# from ..model_components import COMPONENT1 as ABBR1 - - -# entity types: - -# by mixing the above model components' mixin classes of the same name. -# Only compose those entity types and process taxons that the model needs, -# delete the templates for the unneeded ones, and add those for missing ones: - - -class World(cc.World, - base.World): - """World entity type.""" - - pass - - -class SocialSystem(cc.SocialSystem, - base.SocialSystem): - """SocialSystem entity type.""" - - pass - - -class Cell(cc.Cell, - base.Cell): - """Cell entity type.""" - - pass - - -class Individual(base.Individual): - """Individual entity type.""" - - pass - - -# process taxa: - -class Environment(cc.Environment, - base.Environment): - """Environment process taxon.""" - - pass - - -class Metabolism(base.Metabolism): - """Metabolism process taxon.""" - - pass - - -class Culture(base.Culture): - """Culture process taxon.""" - - pass - - -# Model class: - -class Model(cc.Model, - base.Model): - """Class representing the whole model.""" - - name = "..." - """our model""" - - description = "..." - """Longer description""" - - entity_types = [ - World, - SocialSystem, - Cell, - # Individual, - ] - """List of entity types used in the model""" - - process_taxa = [ - Environment, - # Metabolism, - # Culture, - ] - """List of process taxa used in the model""" diff --git a/pycopancore/models/seven_dwarfs.py b/pycopancore/models/seven_dwarfs.py index fd7bacc6..c96989b1 100644 --- a/pycopancore/models/seven_dwarfs.py +++ b/pycopancore/models/seven_dwarfs.py @@ -13,10 +13,11 @@ # Imports # -from .. import base # all models must use the base component +# all models must use the base component +from pycopancore.model_components import base -from ..model_components import seven_dwarfs as sd -from ..model_components import snowwhite as sw +from pycopancore.model_components import seven_dwarfs as sd +from pycopancore.model_components import snowwhite as sw # entity types: diff --git a/pycopancore/private/__init__.py b/pycopancore/private/__init__.py index 677cd94b..31595449 100644 --- a/pycopancore/private/__init__.py +++ b/pycopancore/private/__init__.py @@ -9,10 +9,11 @@ """ """ -from ._mixin import _Mixin, _MixinType -from ._abstract_process import _AbstractProcess -from ._abstract_process_taxon_mixin import _AbstractProcessTaxonMixin -from ._abstract_entity_mixin import _AbstractEntityMixin -from ._abstract_runner import _AbstractRunner -from ._expressions import _DotConstruct, eval, unknown, unset -from ._trajectory_dictionary import _TrajectoryDictionary +# from ._mixin import _Mixin, _MixinType +# from ._abstract_process import _AbstractProcess +# from ._abstract_process_taxon_mixin import _AbstractProcessTaxonMixin +# from ._abstract_entity_mixin import _AbstractEntityMixin +# from ._abstract_runner import _AbstractRunner +# from ._expressions import _DotConstruct, eval +# from ._simple_expressions import unset, unknown +# from ._trajectory_dictionary import _TrajectoryDictionary diff --git a/pycopancore/private/_abstract_entity_mixin.py b/pycopancore/private/_abstract_entity_mixin.py index de8b3cf4..657c39b4 100644 --- a/pycopancore/private/_abstract_entity_mixin.py +++ b/pycopancore/private/_abstract_entity_mixin.py @@ -18,7 +18,7 @@ # - in __init__, add logics that sets all variables to either their specified # values or their default values as given in Variable. -from . import _Mixin +from pycopancore.private._mixin import _Mixin class _AbstractEntityMixin(_Mixin): diff --git a/pycopancore/private/_abstract_process_taxon_mixin.py b/pycopancore/private/_abstract_process_taxon_mixin.py index 2b7dd3eb..c2ff3d10 100644 --- a/pycopancore/private/_abstract_process_taxon_mixin.py +++ b/pycopancore/private/_abstract_process_taxon_mixin.py @@ -13,7 +13,7 @@ # License: BSD 2-clause license -from . import _Mixin +from pycopancore.private._mixin import _Mixin class _AbstractProcessTaxonMixin(_Mixin): diff --git a/pycopancore/private/_expressions.py b/pycopancore/private/_expressions.py index c5b5a63f..a8912cea 100644 --- a/pycopancore/private/_expressions.py +++ b/pycopancore/private/_expressions.py @@ -19,27 +19,8 @@ from sympy.functions.elementary.piecewise import ExprCondPair import scipy.special -from .. import data_model as D -from .. import private - -from numba import njit - - -class _Unknown(object): - def __str__(self): - return "unknown" - def update(self, *args): - return self - -unknown = _Unknown() - -class _Unset(object): - def __str__(self): - return "unset" - def update(self, *args): - return self - -unset = _Unset() +from ._simple_expressions import unknown +from pycopancore import data_model as D # hierarchical aggregation functions: @@ -49,7 +30,6 @@ def aggregation(npfunc): # TODO: add docstring to function - @njit def func(values, lens): """Dummy docstring""" @@ -65,6 +45,7 @@ def func(values, lens): return func + name2numpy = { "all": np.all, "any": np.any, @@ -83,7 +64,6 @@ def func(values, lens): # hierarchical broadcasting: -@njit def _broadcast(values, lens): """Dummy docstring""" # TODO: add docstring to function diff --git a/pycopancore/private/_mixin.py b/pycopancore/private/_mixin.py index 7cd22e9d..bec055bd 100644 --- a/pycopancore/private/_mixin.py +++ b/pycopancore/private/_mixin.py @@ -18,9 +18,8 @@ # - in __init__, add logics that sets all variables to either their specified # values or their default values as given in Variable. -from ..data_model import variable -from ..private._expressions import _DotConstruct, aggregation_names -from ..data_model import OrderedSet +from pycopancore.data_model.variable import Variable +from pycopancore.private._expressions import _DotConstruct, aggregation_names import inspect @@ -58,7 +57,7 @@ def __getattribute__(cls, name): for c in inspect.getmro(cls)[1:]: try: res = c.__getattribute__(c, name) - if isinstance(res, variable.Variable): + if isinstance(res, Variable): return res except BaseException: pass @@ -121,22 +120,23 @@ def __init__(self, **kwargs): for key, val in kwargs.items(): if hasattr(self.__class__, key): clsattr = getattr(self.__class__, key) - if isinstance(clsattr, variable.Variable): + if isinstance(clsattr, Variable): varvals[clsattr] = val continue - print("unexpected (misspelled?) keyword argument",key,"=",val) + nonvarkwargs[key] = val + # pass other kwargs to super: super().__init__(**nonvarkwargs) # assign Variable values: for var, val in varvals.items(): var.set_value(self, val) - + def complete_values(self): """assign default values to all unset Variables""" for var in self.variables: if (not hasattr(self, var.codename) # this happens for unset properties - or isinstance(getattr(self, var.codename), variable.Variable)): + or isinstance(getattr(self, var.codename), Variable)): # class attribute was returned by getattr, # hence object attribute has not been assigned a value yet. try: @@ -151,7 +151,7 @@ def complete_values(self): def set_value(self, var, value): """Dummy docstring""" # TODO: add docstring to method - assert isinstance(var, variable.Variable), \ + assert isinstance(var, Variable), \ "variable must be a Variable object" var.set_value(self, value) diff --git a/pycopancore/private/_simple_expressions.py b/pycopancore/private/_simple_expressions.py new file mode 100644 index 00000000..e318f220 --- /dev/null +++ b/pycopancore/private/_simple_expressions.py @@ -0,0 +1,39 @@ +"""Created on Mar 20, 2017. + +@author: heitzig +""" + +# This file is part of pycopancore. +# +# Copyright (C) 2016-2017 by COPAN team at Potsdam Institute for Climate +# Impact Research +# +# URL: +# Contact: core@pik-potsdam.de +# License: BSD 2-clause license + +# defines logics to deal with symbolic expressions and their evaluation + + +class _Unknown(object): + + def __str__(self): + return "unknown" + + def update(self, *args): + return self + + +unknown = _Unknown() + + +class _Unset(object): + + def __str__(self): + return "unset" + + def update(self, *args): + return self + + +unset = _Unset() diff --git a/pycopancore/private/_trajectory_dictionary.py b/pycopancore/private/_trajectory_dictionary.py index bef03f44..e624f02d 100644 --- a/pycopancore/private/_trajectory_dictionary.py +++ b/pycopancore/private/_trajectory_dictionary.py @@ -16,7 +16,8 @@ import pickle, json import networkx as nx -from . import _AbstractEntityMixin, _AbstractProcessTaxonMixin +from ._abstract_entity_mixin import _AbstractEntityMixin +from ._abstract_process_taxon_mixin import _AbstractProcessTaxonMixin class _TrajectoryDictionary(dict): diff --git a/pycopancore/process_types/ODE.py b/pycopancore/process_types/ODE.py index c777a68a..97f5039a 100644 --- a/pycopancore/process_types/ODE.py +++ b/pycopancore/process_types/ODE.py @@ -23,7 +23,7 @@ # Definition of class ODE # -from ..private import _AbstractProcess +from pycopancore.private._abstract_process import _AbstractProcess class ODE(_AbstractProcess): diff --git a/pycopancore/process_types/event.py b/pycopancore/process_types/event.py index 99b5b1cf..bb773534 100644 --- a/pycopancore/process_types/event.py +++ b/pycopancore/process_types/event.py @@ -22,7 +22,7 @@ # Definition of class Event # -from ..private import _AbstractProcess +from pycopancore.private._abstract_process import _AbstractProcess class Event(_AbstractProcess): diff --git a/pycopancore/process_types/explicit.py b/pycopancore/process_types/explicit.py index 27a15ef7..e565e388 100644 --- a/pycopancore/process_types/explicit.py +++ b/pycopancore/process_types/explicit.py @@ -22,7 +22,7 @@ # Definition of class Event # -from ..private import _AbstractProcess +from pycopancore.private._abstract_process import _AbstractProcess class Explicit(_AbstractProcess): diff --git a/pycopancore/process_types/implicit.py b/pycopancore/process_types/implicit.py index 73ff57cc..810f77d7 100644 --- a/pycopancore/process_types/implicit.py +++ b/pycopancore/process_types/implicit.py @@ -21,7 +21,7 @@ # Definition of class Event # -from ..private import _AbstractProcess +from pycopancore.private._abstract_process import _AbstractProcess class Implicit(_AbstractProcess): diff --git a/pycopancore/process_types/step.py b/pycopancore/process_types/step.py index ffedd703..41e075f2 100644 --- a/pycopancore/process_types/step.py +++ b/pycopancore/process_types/step.py @@ -23,7 +23,7 @@ # Definition of class Event # -from ..private import _AbstractProcess +from pycopancore.private._abstract_process import _AbstractProcess class Step(_AbstractProcess): diff --git a/pycopancore/runners/runner.py b/pycopancore/runners/runner.py index 1da1f055..799e736d 100644 --- a/pycopancore/runners/runner.py +++ b/pycopancore/runners/runner.py @@ -14,11 +14,15 @@ # - rename to ScipyODERunner # - enable verbosity level, use proper logger -from .. import Event, Step, Variable -from ..private import _AbstractRunner, _DotConstruct, eval, unknown, \ - _AbstractEntityMixin, _TrajectoryDictionary, _AbstractProcessTaxonMixin +from pycopancore.process_types import Event, Step +from pycopancore.data_model import Variable +from pycopancore.private._abstract_runner import _AbstractRunner +from pycopancore.private._expressions import eval +from pycopancore.private._simple_expressions import unknown +from pycopancore.private._abstract_entity_mixin import _AbstractEntityMixin +from pycopancore.private._trajectory_dictionary import _TrajectoryDictionary # TODO: discuss whether this makes sense or leads to problems: -from .hooks import Hooks +from pycopancore.runners.hooks import Hooks from scipy import integrate import numpy as np diff --git a/pycopancore/util/__init__.py b/pycopancore/util/__init__.py index e9fe8eb7..869d2a54 100644 --- a/pycopancore/util/__init__.py +++ b/pycopancore/util/__init__.py @@ -1,2 +1,26 @@ +from .. import config + from .functions import * -from .seeding import * \ No newline at end of file +from .seeding import * + +# profiling: + +try: + from line_profiler import LineProfiler + class _Profile (object): + def __init__(self): + self.profile = LineProfiler() + def __call__(self, f): + return self.profile(f) if config.profile else f + def __getattr__(self, key): + return getattr(self.profile, key) +except: + class _Profile (object): + def __call__(self, f): + if config.profile: + print("INFO: line_profiler not available") + return f + def __getattr__(self, key): + print("INFO: line_profiler not available") + return None +profile = _Profile() diff --git a/setup.py b/setup.py index 94d7930c..af4dae23 100644 --- a/setup.py +++ b/setup.py @@ -16,7 +16,7 @@ # This creates a link insteaed of copying the files, so modifications in this directory are modifications in the installed package. setup(name="pycopancore", - version="0.7.1", + version="0.8.0", description="Reference implementation of the copan:CORE World-Earth modelling framework", url="https://github.com/pik-copan/pycopancore", author="COPAN team @ PIK", @@ -27,10 +27,10 @@ "numpy>=1.11.0", "scipy>=0.17.0", "sympy>=1.0", - "blist>=1.3.6", + # "blist>=1.3.6", "python-louvain>=0.9", "profilehooks", - "pytest", + "pytest>=4.6", "pylama", "pylint", "pytest-cov>=2.5.1", diff --git a/studies/.gitignore b/studies/.gitignore deleted file mode 100755 index bb4dfe9d..00000000 --- a/studies/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -/fort.1 -/*.html -/*.png diff --git a/studies/coccon_tutorial.py b/studies/coccon_tutorial.py deleted file mode 100755 index 7fcf0d9a..00000000 --- a/studies/coccon_tutorial.py +++ /dev/null @@ -1,180 +0,0 @@ -"""Run script for CoCCoN tutorial model.""" - -# This file is part of pycopancore. -# -# Copyright (C) 2016-2017 by COPAN team at Potsdam Institute for Climate -# Impact Research -# -# URL: -# Contact: core@pik-potsdam.de -# License: BSD 2-clause license - -from time import time -from numpy import random, array, average, exp -from pylab import show, subplots - -from pycopancore import master_data_model as D -from pycopancore.runners import Runner - -import pycopancore.models.coccon.full as M - -# first thing: set seed so that each execution must return same thing: - -random.seed(1) - -# parameters: - -nworlds = 1 # no. worlds -nsocs = 5 #2 # no. social_systems -ncells = 50 #20 # no. cells -ninds = 500 #200 # no. individuals -years = 100 # time to simulate - -# instantiate model and process taxa: - -model = M.Model() -environment = M.Environment() -metabolism = M.Metabolism( - renewable_energy_knowledge_spillover_fraction = 0, -# renewable_energy_knowledge_spillover_fraction = .5, - basic_emigration_probability_rate = 0, -# basic_emigration_probability_rate = 1e-13, - ) -culture = M.Culture( - awareness_lower_carbon_density=1e-4, - awareness_upper_carbon_density=2e-4, - awareness_update_rate=0, -# awareness_update_rate=.5, - environmental_friendliness_learning_rate=0, -# environmental_friendliness_learning_rate=1, - ) - -# generate entities and plug them together at random: - -world = M.World(environment=environment, metabolism=metabolism, culture=culture, - atmospheric_carbon = 830 * D.gigatonnes_carbon, - upper_ocean_carbon = (5500 - 830 - 2480 - 1125) * D.gigatonnes_carbon - ) -social_systems = [M.SocialSystem(world=world, - has_renewable_subsidy = random.choice([False, True], p=[3/4, 1/4]), - has_emissions_tax = random.choice([False, True], p=[4/5, 1/5]), - has_fossil_ban = False, - time_between_votes = 1e100, -# time_between_votes = 4, - ) - for s in range(nsocs)] -cells = [M.Cell(social_system=random.choice(social_systems), - renewable_sector_productivity = 2 * random.rand() * M.Cell.renewable_sector_productivity.default - ) - for c in range(ncells)] -individuals = [M.Individual(cell=random.choice(cells), - is_environmentally_friendly = random.choice([False, True], p=[.7, .3]), - ) - for i in range(ninds)] - -# initialize block model acquaintance network: - -target_degree = 20 -target_degree_samecell = 0.5 * target_degree -target_degree_samesoc = 0.35 * target_degree -target_degree_other = 0.15 * target_degree -p_samecell = target_degree_samecell / (ninds/ncells - 1) -p_samesoc = target_degree_samesoc / (ninds/nsocs - ninds/ncells - 1) -p_other = target_degree_other / (ninds - ninds/nsocs - 1) -for index, i in enumerate(individuals): - for j in individuals[:index]: - if random.uniform() < ( - p_samecell if i.cell == j.cell - else p_samesoc if i.social_system == j.social_system \ - else p_other): - culture.acquaintance_network.add_edge(i, j) - -# distribute global aggregate quantities to cells and social_systems: - -r = random.uniform(size=ncells) -Sigma0 = 1.5e8 * D.square_kilometers * r / sum(r) -M.Cell.land_area.set_values(cells, Sigma0) - -r += random.uniform(size=ncells) -L0 = 2480 * D.gigatonnes_carbon * r / sum(r) # 2480 is yr 2000 -M.Cell.terrestrial_carbon.set_values(cells, L0) - -r = exp(random.normal(size=ncells)) -G0 = 1125 * D.gigatonnes_carbon * r / sum(r) # 1125 is yr 2000 -M.Cell.fossil_carbon.set_values(cells, G0) - -r = random.uniform(size=nsocs) -P0 = 6e9 * D.people * r / sum(r) # 500e9 is middle ages, 6e9 would be yr 2000 -M.SocialSystem.population.set_values(social_systems, P0) -M.SocialSystem.migrant_population.set_values(social_systems, P0 * 250e6/6e9) -for s in social_systems: - s.max_protected_terrestrial_carbon = 0.90 * sum(c.terrestrial_carbon for c in s.cells) - -r = random.uniform(size=nsocs) -K0 = sum(P0) * 1e4 * D.dollars/D.people * r / sum(r) -M.SocialSystem.physical_capital.set_values(social_systems, K0) - -r = random.uniform(size=nsocs) -S0 = 1e12 * D.gigajoules * r / r.mean() -M.SocialSystem.renewable_energy_knowledge.set_values(social_systems, S0) - -# print initial global state: - -for v in culture.variables: - if v.unit: print(v, v.get_quantity(culture)) -for v in environment.variables: - if v.unit: print(v, v.get_quantity(environment)) -for v in metabolism.variables: - if v.unit: print(v, v.get_quantity(metabolism)) -for v in world.variables: - if v.unit: print(v, v.get_quantity(world)) - -# run simulation: - -runner = Runner(model=model) -starttime = time() -traj = runner.run(t_0=2000, t_1=2000+years, dt=1, - add_to_output=[M.Individual.represented_population]) - -# plots: - -t = array(traj['t']) - -fig, (ax1,ax2,ax3) = subplots(3, sharex=True) - -ax1.plot(t[3:], 100*average(array([traj[M.Individual.is_environmentally_friendly][i][3:] for i in individuals]), - weights=[traj[M.Individual.represented_population][i][0] for i in individuals], - axis=0), - "--", color="green", lw=1, label="env. friendly individuals") -ax1.plot(t[3:], 100*average(array([traj[M.SocialSystem.has_renewable_subsidy][s][3:] for s in social_systems]), axis=0), - color="orange", lw=2, label="social_systems with renewable subsidy") -ax1.plot(t[3:], 100*average(array([traj[M.SocialSystem.has_emissions_tax][s][3:] for s in social_systems]), axis=0), - color="blue", lw=2, label="social_systems with emissions tax") -ax1.plot(t[3:], 100*average(array([traj[M.SocialSystem.has_fossil_ban][s][3:] for s in social_systems]), axis=0), - color="black", lw=2, label="social_systems with fossil ban") -ax1.set_ylabel('percent') -ax1.legend() - -for i, s in enumerate(social_systems): - ax2.semilogy(t[3:], traj[M.SocialSystem.population][s][3:], color="yellow", lw=2, label="population [humans]" if i==0 else None) - ax2.semilogy(t[3:], traj[M.SocialSystem.physical_capital][s][3:], color="black", lw=2, label="physical capital [$]" if i==0 else None) - ax2.semilogy(t[3:], traj[M.SocialSystem.renewable_energy_knowledge][s][3:], color="orange", lw=2, label="renewable energy knowledge [GJ]" if i==0 else None) -ax2.set_ylabel('(mixed units)') -ax2.legend() - -ax3.plot(t[3:], traj[M.World.atmospheric_carbon][world][3:], color="cyan", lw=3, label="atmospheric carbon") -ax3.plot(t[3:], traj[M.World.upper_ocean_carbon][world][3:], color="blue", lw=3, label="upper ocean carbon") -ax3.plot(t[3:], traj[M.World.terrestrial_carbon][world][3:], color="green", lw=3, label="terrestrial carbon") -ax3.plot(t[3:], traj[M.World.fossil_carbon][world][3:], color="gray", lw=3, label="fossil carbon") -ax3.set_ylabel('global GtC') -ax3.legend() -ax3b = ax3.twinx() -for c in cells: - ax3b.plot(t[3:], traj[M.Cell.terrestrial_carbon][c][3:], color="green", lw=1, alpha=0.2) -ax3b.set_ylabel("cells' GtC") - -print(time()-starttime, " seconds") - -show() - - diff --git a/studies/esd_description_paper_example/README.md b/studies/esd_description_paper_example/README.md index f0d9f8f8..01be1ef0 100755 --- a/studies/esd_description_paper_example/README.md +++ b/studies/esd_description_paper_example/README.md @@ -10,53 +10,4 @@ Run the following code: python run_esd_example.py -p 0.25 -s 0 python run_esd_example.py -p 0.4 -s 0 -u 12 --with-social python plot_figure5.py -``` - -# Plot figure 6 -As of now this only works properly on the High Performance Cluster at the -Potsdam Institute for Climate Impact Research. - -Follow these steps to reproduce the figure: -1. Create a temporary output directory for the results of the model - simulations. On PIK's high performace cluster this should be somewhere under - `/p/tmp/YOURUSERNAME/`. We call this directory `OUTPUTPATH` from here on. - -2. Set the correct path `OUTPUTPATH` in line 9 of - `submit_jobarray.sh`. - -3. Make sure the `pycopancore` repository is located in your home folder such - that `$HOME/pycopancore/studies/esd_description_paper_example/` is a - valid path. If `pycopancore` is located elsewhere make sure to set the - correct paths in `submit_single_runs.py` and `submit_jobarray.sh`. - -4. Use `sbatch submit_jobarray.sh` to submit the simulations to the cluster. - -5. Use `collect_results.py -t OUTPUTPATH` to collect the simulation data and - store them in a single file called `results_ensemble.p` for later - processing. - -6. Use `plot_figure6.py` to plot the results of the bifurcation analysis. The - scripts loads `results_ensemble.p` and the simulation data without social - processes that was created using `python run_esd_example.py -p 0.25 -s 0` - above. - -# Some further information on the files in this directory - -## run_esd_example.py -Runs one simulation for a specified learning rate. As this script is intended -to run on a cluster it must be called with a `task-id` (that corresponds to the -id of the job array entry) which is then translated into a corresponding -learning rate. Secondly a seed must be specified as input argument. This script -produces large output, so it should only be used on a cluster with large -storage capacity. Use `collect_results.py` after running this script to get -data of manageable size. - -## submit_jobarray.sh -Submit the simulation to the cluster. Adjust as needed. - -## submit_single_runs.py -Helper scripts that calls `run_esd_example.py` 50 times in a row for the same -task id, i.e., learning rate, and different seeds. This is needed to circumvent -the limit of a maximum of 3600 single jobs per job array on PIKs high -performance cluster and the fact that a model can only be instantiated once -when using `pycopancore`. +``` \ No newline at end of file diff --git a/studies/esd_description_paper_example/collect_results.py b/studies/esd_description_paper_example/collect_results.py deleted file mode 100755 index 37092aa2..00000000 --- a/studies/esd_description_paper_example/collect_results.py +++ /dev/null @@ -1,60 +0,0 @@ -import os -import argparse -import pickle -import glob -import numpy as np - -def main(): - - parser = argparse.ArgumentParser() - parser.add_argument('-t', '--tmp-dir', required=True) - parser.add_argument('--overwrite', action='store_const', const=True, - default=False) - args = vars(parser.parse_args()) - - load(input_dir=args["tmp_dir"], overwrite=args["overwrite"]) - - -def load(input_dir, overwrite): - - if input_dir[-1] != "/": - input_dir += "/" - - files = glob.glob(input_dir+"*.p") - - if os.path.exists("results_ensemble.p") and not overwrite: - results = np.load("results_ensemble.p") - print("Loading results from disk") - else: - results = {"succesful_files": []} - print("Creating new results file") - - files = [f for f in files if f not in results["succesful_files"]] - print(len(files)) - for i, datafile in enumerate(files): - - print(i, datafile, end="\r") - - updaterate = float(datafile.split("_")[6]) - - if updaterate not in results.keys(): - results[updaterate] = {"terr": [], "atmo": [], "foss": [], "ocea": [], - "gmt": [], "econ": []} - - data = np.load(datafile) - - world = list(data["World.surface_air_temperature"].keys())[0] - - results[updaterate]["terr"].append(data["World.terrestrial_carbon"][world][-1]) - results[updaterate]["atmo"].append(data["World.atmospheric_carbon"][world][-1]) - results[updaterate]["foss"].append(data["World.fossil_carbon"][world][-1]) - results[updaterate]["ocea"].append(data["World.upper_ocean_carbon"][world][-1]) - results[updaterate]["gmt"].append(data["World.surface_air_temperature"][world][-1]) - - social_systems = list(data["SocialSystem.has_emissions_tax"].keys()) - econ = [data["SocialSystem.economic_output_flow"][s][-1] for s in social_systems] - results[updaterate]["econ"].append(econ) - - results["succesful_files"].append(datafile) - - pickle.dump(results, open("results_ensemble.p", "wb")) diff --git a/studies/esd_description_paper_example/esd_example_without_social_seed_0.p b/studies/esd_description_paper_example/esd_example_without_social_seed_0.p deleted file mode 100644 index 3942b7ae..00000000 Binary files a/studies/esd_description_paper_example/esd_example_without_social_seed_0.p and /dev/null differ diff --git a/studies/esd_description_paper_example/plot_figure6.py b/studies/esd_description_paper_example/plot_figure6.py deleted file mode 100755 index 6b8f69cc..00000000 --- a/studies/esd_description_paper_example/plot_figure6.py +++ /dev/null @@ -1,89 +0,0 @@ -#!/usr/bin/env python -# coding: utf-8 -import numpy as np -from matplotlib import pyplot as plt - -AX1_PLOTS = (("terr", "g", "Terrestrial carbon"), - ("atmo", "c", "Atmospheric carbon"), - ("ocea", "b", "Ocean carbon")) - -def main(): - - _, (ax1, ax2) = plt.subplots(2, 1, sharex=True, figsize=(6, 8)) - ax3 = ax2.twinx() - - results = np.load("results_ensemble.p", allow_pickle=True) - baseline = np.load("esd_example_without_social_seed_0.p", allow_pickle=True) - - keys = [k for k in results.keys() if isinstance(k, float)] - keys.sort() - - for shortlabel, color, label in AX1_PLOTS: - _y = np.zeros((len(keys), 2)) - for i, key in enumerate(keys): - _y[i, 0] = np.mean(results[key][shortlabel]) - _y[i, 1] = np.std(results[key][shortlabel]) - ax1.errorbar(keys, _y[:, 0], yerr=_y[:, 1], fmt='o', c=color, - alpha=0.5, label=label) - - - gmt = np.zeros((len(keys), 2)) - econ = np.zeros((len(keys), 4)) - for i, key in enumerate(keys): - gmt[i, 0] = np.mean(results[key]["gmt"]) - gmt[i, 1] = np.std(results[key]["gmt"]) - econ[i, 0:2] = np.mean(results[key]["econ"], axis=0) - econ[i, 2:] = np.std(results[key]["econ"], axis=0) - - econ[:, 0::2] /= 0.25 * 6e9 - econ[:, 1::2] /= 0.75 * 6e9 - - ax2.errorbar(keys, econ[:, 0], yerr=econ[:, 2], fmt='o', c="r", - alpha=0.5, label="North") - ax2.errorbar(keys, econ[:, 1], yerr=econ[:, 3], fmt='d', c="r", - alpha=0.5, label="South") - - ax3.errorbar(keys, gmt[:, 0], yerr=gmt[:, 1], fmt='o', c="k", - alpha=0.5, label="Global Mean Temperature") - - world = list(baseline["World.surface_air_temperature"].keys())[0] - - _y = baseline["World.terrestrial_carbon"][world][-1] - ax1.axhline(_y, c="g", ls="--", lw=2) - - _y = baseline["World.atmospheric_carbon"][world][-1] - ax1.axhline(_y, c="c", ls="--", lw=2) - - _y = baseline["World.upper_ocean_carbon"][world][-1] - ax1.axhline(_y, c="b", ls="--", lw=2) - - social_systems = list(baseline["SocialSystem.has_emissions_tax"].keys()) - _y = [baseline["SocialSystem.economic_output_flow"][s][-1] for s in social_systems] - ax2.axhline(_y[0] / 0.25 / 6e9, ls="--", lw=2, c="r") - ax2.axhline(_y[1] / 0.75 / 6e9, ls="--", lw=2, c="r") - - _y = baseline["World.surface_air_temperature"][world][-1] - ax3.axhline(_y, c="k", ls="--", lw=2) - - ax1.legend() - ax2.legend(loc="center left") - ax3.legend(loc="upper left") - - ax2.set_xlabel("Learning rate [$yr^{-1}$]") - - ax1.set_ylabel("Gigatonnes Carbon in 2120") - ax2.set_ylabel("GDP/capita in 2120 [$/yr]") - ax3.set_ylabel("Global mean temperature in 2120 [K]") - - ax2.semilogx() - ax2.semilogy() - ax2.set_xlim(min(keys), max(keys)) - - ax3.set_ylim(287.5, 290) - - plt.tight_layout() - plt.savefig("figure6.pdf") - - -if __name__ == "__main__": - main() diff --git a/studies/esd_description_paper_example/submit_jobarray.sh b/studies/esd_description_paper_example/submit_jobarray.sh deleted file mode 100755 index 7569fa05..00000000 --- a/studies/esd_description_paper_example/submit_jobarray.sh +++ /dev/null @@ -1,11 +0,0 @@ -#!/bin/bash - -#SBATCH --qos=short -#SBATCH --job-name=core_mult_runs -#SBATCH --array=0-49 -#SBATCH --output=core-%A_%a.out -#SBATCH --error=core-%A_%a.err -#SBATCH --account=copan -#SBATCH --workdir= - -python3 $HOME/pycopancore/studies/esd_description_paper_example/submit_single_runs.py diff --git a/studies/esd_description_paper_example/submit_single_runs.py b/studies/esd_description_paper_example/submit_single_runs.py deleted file mode 100755 index ee21232c..00000000 --- a/studies/esd_description_paper_example/submit_single_runs.py +++ /dev/null @@ -1,15 +0,0 @@ -import os - -try: - TASK = os.environ['SLURM_ARRAY_TASK_ID'] -except KeyError: - print("Not running with SLURM job arrays") - TASK = 0 - -HOME = os.path.expanduser("~") -PATH = HOME + "/pycopancore/studies/esd_description_paper_example/"\ - "run_esd_example.py" - -for seed in range(50): - cmd = f"python {PATH} -s {seed} -i {TASK} -p 0.25 --with-social" - os.system(cmd) diff --git a/studies/heitzig_sandbox/fit_parameters_example1.py b/studies/heitzig_sandbox/fit_parameters_example1.py deleted file mode 100755 index 7673b8f2..00000000 --- a/studies/heitzig_sandbox/fit_parameters_example1.py +++ /dev/null @@ -1,283 +0,0 @@ -"""Script to run example1 model.""" - -from time import time -from numpy import random, array -import numpy as np - -import pycopancore.models.example1 as M -from pycopancore import master_data_model as D -from pycopancore.runners import Runner - -from pylab import plot, gca, show, figure, subplot, gca, semilogy, legend - -from numba.errors import NumbaDeprecationWarning, NumbaPendingDeprecationWarning -import warnings -warnings.simplefilter('ignore', category=NumbaDeprecationWarning) -warnings.simplefilter('ignore', category=NumbaPendingDeprecationWarning) - -# first thing: set seed so that each execution must return same thing: -random.seed(10) - -# parameters: - -nworlds = 1 # no. worlds -nsocs = 5 # no. social_systems -ncells = 100 # no. cells -ninds = 1000 # no. individuals - -t_1 = 2000.01 - -# choose one of two scenarios: -with_social = 0 # 0 or 1 - -# directory to store results: -dir = "/tmp/"; - -if with_social: - filename = dir + "with_social.pickle" - with_migration = 0 - with_awareness = 1 - with_learning = 1 - with_voting = 1 -else: - filename = dir + "without_social.pickle" - with_migration = 0 - with_awareness = 0 - with_learning = 0 - with_voting = 0 -with_spillovers = 1 - -print("Using model as defined in file", M.__file__) -model = M.Model() -runner = Runner(model=model) - -# instantiate process taxa: -environment = M.Environment() -metabolism = M.Metabolism( - renewable_energy_knowledge_spillover_fraction = - .1 if with_spillovers else 0, - basic_emigration_probability_rate = - 16e-13 if with_migration else 0, # leads to ca. 5mio. at 5 socs, (real) - ) -culture = M.Culture( - awareness_lower_carbon_density=1e-4, - awareness_upper_carbon_density=2e-4, - awareness_update_rate = 10 if with_awareness else 0, - environmental_friendliness_learning_rate = 1 if with_learning else 0, - max_protected_terrestrial_carbon_share=0, - terrestrial_carbon_averaging_time=10, - ) - -# generate entities and plug them together at random: -worlds = [M.World(environment=environment, - metabolism=metabolism, - culture=culture, - atmospheric_carbon = 830 * D.gigatonnes_carbon, - upper_ocean_carbon = (5500 - 830 - 2480 - 1125) * D.GtC - ) for w in range(nworlds)] -social_systems = [M.SocialSystem( - world=random.choice(worlds), - has_renewable_subsidy = random.choice([False, True], - p=[3/4, 1/4]), - has_emissions_tax = random.choice([False, True], - p=[4/5, 1/5]), - has_fossil_ban = False, - time_between_votes = 4 if with_voting else 1e100, - ) for s in range(nsocs)] -cells = [M.Cell(social_system=random.choice(social_systems)) - for c in range(ncells)] -individuals = [M.Individual( - cell=random.choice(cells), - is_environmentally_friendly = - random.choice([False, True], p=[.7, .3]), - ) - for i in range(ninds)] - -# initialize block model acquaintance network: -target_degree = 150 -target_degree_samecell = 0.5 * target_degree -target_degree_samesoc = 0.35 * target_degree -target_degree_other = 0.15 * target_degree -p_samecell = target_degree_samecell / (ninds/ncells - 1) -p_samesoc = target_degree_samesoc / (ninds/nsocs - ninds/ncells - 1) -p_other = target_degree_other / (ninds - ninds/nsocs - 1) -for index, i in enumerate(individuals): - for j in individuals[:index]: - if random.uniform() < ( - p_samecell if i.cell == j.cell - else p_samesoc if i.social_system == j.social_system \ - else p_other): - culture.acquaintance_network.add_edge(i, j) - -# set renewable sector productivities randomly: -rel_prod = 2 * random.uniform(size=ncells) -M.Cell.renewable_sector_productivity.set_values(cells, rel_prod * M.Cell.renewable_sector_productivity.default) - -# distribute area and vegetation randomly but correlatedly: -r = random.uniform(size=ncells) -Sigma0 = 1.5e8 * D.square_kilometers * r / sum(r) -M.Cell.land_area.set_values(cells, Sigma0) - -r += random.uniform(size=ncells) -L0 = 2480 * D.gigatonnes_carbon * r / sum(r) # 2480 is yr 2000 -M.Cell.terrestrial_carbon.set_values(cells, L0) -M.Cell.mean_past_terrestrial_carbon.set_values(cells, L0) - -r = np.exp(random.normal(size=ncells)) -G0 = 1125 * D.gigatonnes_carbon * r / sum(r) # 1125 is yr 2000 -M.Cell.fossil_carbon.set_values(cells, G0) - -r = random.uniform(size=nsocs) -P0 = 6e9 * D.people * r / sum(r) # 6e9 is yr 2000 -M.SocialSystem.population.set_values(social_systems, P0) -M.SocialSystem.migrant_population.set_values(social_systems, P0 * 250e6 / 6e9) -for s in social_systems: - s.max_protected_terrestrial_carbon = \ - 0.90 * sum(c.terrestrial_carbon for c in s.cells) - -r = random.uniform(size=nsocs) -K0 = sum(P0) * 1e4 * D.dollars/D.people * r / sum(r) # ? -M.SocialSystem.physical_capital.set_values(social_systems, K0) - -# for renewables, do NOT divide by number of socs: -r = random.uniform(size=nsocs) -S0 = 1e12 * D.gigajoules * r / r.mean() -M.SocialSystem.renewable_energy_knowledge.set_values(social_systems, S0) - -w = worlds[0] -s = social_systems[0] -c = cells[0] -for v in environment.variables: print(v,v.get_value(environment)) -for v in metabolism.variables: print(v,v.get_value(metabolism)) -for v in w.variables: print(v,v.get_value(w)) -for v in s.variables: print(v,v.get_value(s)) -for v in c.variables: print(v,v.get_value(c)) - - -def get_initial_state(): - return { - etpt: { - v: { - i: v.get_value(i) - for i in etpt.instances } - for v in etpt.variables } - for etpt in [M.Cell, M.Culture, M.Environment, M.Individual, M.Metabolism, M.SocialSystem, M.World] } - -def set_initial_state(x0): - for etpt, vardict in x0.items(): - for v, instancedict in vardict.items(): - if not v.readonly: - v.set_values(list(instancedict.keys()), list(instancedict.values())) - -x0 = get_initial_state() - - -from scipy.optimize import fmin - - -# set sector productivities that roughly match real-world energy production: - -print("\n\n\nFITTING SECTOR PRODUCTIVITIES...") - -Rtarget = 100 * D.gigawatts / (D.gigajoules / D.years) - -def target(productivities): - print("\n\nTRYING PRODUCTIVITIES",productivities,":\n") - set_initial_state(x0) - M.Cell.biomass_sector_productivity.set_values(cells, np.ones(ncells) * productivities[0]) - M.Cell.fossil_sector_productivity.set_values(cells, np.ones(ncells) * productivities[1]) - M.Cell.renewable_sector_productivity.set_values(cells, rel_prod * productivities[2]) - traj = runner.run(t_0=2000, t_1=2000.001, dt=1) - Bglobal = sum(traj[M.SocialSystem.biomass_input_flow][s][1] for s in social_systems) - Fglobal = sum(traj[M.SocialSystem.fossil_fuel_input_flow][s][1] for s in social_systems) - Rglobal = sum(traj[M.SocialSystem.renewable_energy_input_flow][s][1] for s in social_systems) # D.gigajoules / D.years - err = ((Bglobal - 3)/3)**2 + ((Fglobal - 11)/11)**2 + ((Rglobal - Rtarget)/Rtarget)**2 - print("\nERROR:", err) - return err - -productivities0 = np.array([3e5, 5e6, 7e-18]) -print("START:",productivities0) -productivities = fmin(target, productivities0) -print("OPTIMAL:",productivities) -set_initial_state(x0) -M.Cell.biomass_sector_productivity.set_values(cells, np.ones(ncells) * productivities[0]) -M.Cell.fossil_sector_productivity.set_values(cells, np.ones(ncells) * productivities[1]) -M.Cell.renewable_sector_productivity.set_values(cells, rel_prod * productivities[2]) - - -# set initial capital values that roughly match a certain GDP distribution: - -print("\n\n\nFITTING INITIAL CAPITAL...") - -GWP_2000 = 33.57e12 # gross world product in 2000 in USD - -# for illustration, use a random GDP distribution (later use real-world data): -r = random.uniform(size=nsocs) -Ytargets = GWP_2000 * r / r.sum() -weights = Ytargets**(5/2) / P0 -capitals0 = sum(P0) * 1e4 * weights/sum(weights) - -def target2(logcapitals): - capitals = np.exp(logcapitals) - print("\n\nTRYING CAPITALS",capitals,":\n") - set_initial_state(x0) - M.SocialSystem.physical_capital.set_values(social_systems, capitals) - traj = runner.run(t_0=2000, t_1=2000.001, dt=1) - err = ((np.array(M.SocialSystem.economic_output_flow.get_values(social_systems)) - Ytargets)**2).sum() - print("\nERROR:", err) - return err - -#capitals0 = np.array(M.SocialSystem.physical_capital.get_values(social_systems)) -capitals = np.exp(fmin(target2, np.log(capitals0))) -print("START:",capitals0) -print("OPTIMAL:",capitals) -set_initial_state(x0) -M.SocialSystem.physical_capital.set_values(social_systems, capitals) - - -exit() - -# do simulation: -start = time() -traj = runner.run(t_0=2000, t_1=t_1, dt=1, - add_to_output=[M.Individual.represented_population, - M.Cell.mean_past_terrestrial_carbon]) - -for v in environment.variables: print(v,v.get_value(environment)) -for v in metabolism.variables: print(v,v.get_value(metabolism)) -for v in w.variables: print(v,v.get_value(w)) -for v in s.variables: print(v,v.get_value(s)) -for v in c.variables: print(v,v.get_value(c)) - - -from pickle import dump -tosave = { - v.owning_class.__name__ + "." - + v.codename: {str(e): traj[v][e] - for e in traj[v].keys() - } - for v in traj.keys() if v is not "t" - } -tosave["t"] = traj["t"] -dump(tosave, open(filename,"wb")) -print(time()-start, " seconds") - -t = np.array(traj['t']) -print("max. time step", (t[1:]-t[:-1]).max()) - - - -exit() - -# POSSIBLY TRY FITTING THESE VALUES AS WELL: - -print("\nYr 2000 values (real):") -print("emigration (5e6):",sum(traj[M.SocialSystem.emigration][s][5] - for s in social_systems)) # TODO: fit via changing basic_emigration_probability_rate -print("photo (123):",sum(traj[M.Cell.photosynthesis_carbon_flow][c][5] - for c in cells)) # TODO: fit via changing cell's basic photosynthesis rate -print("resp (118):",sum(traj[M.Cell.terrestrial_respiration_carbon_flow][c][5] - for c in cells)) # TODO: fit via changing cell's basic respiration rate -print("temp. at begin:", traj[M.World.surface_air_temperature][worlds[0]][5]) - - diff --git a/studies/jobst2leander.py b/studies/jobst2leander.py deleted file mode 100644 index 7ebf5d60..00000000 --- a/studies/jobst2leander.py +++ /dev/null @@ -1,215 +0,0 @@ -"""Script to run example2 model, plus comments for possible use by Leander.""" - -# @Leander: siehe Kommentare mit TODO - -from time import time -from numpy import random, array -import numpy as np - -import pycopancore.models.example2 as M -from pycopancore import master_data_model as D -from pycopancore.runners import Runner - -from pylab import plot, gca, show, figure, subplot, gca, semilogy, legend - -# first thing: set seed so that each execution must return same thing: -random.seed(10) - -# parameters: - -nworlds = 1 # no. worlds -nsocs = 2 # no. social_systems # TODO: zunächst Anzahl Länder in Nils' Daten. Später auf Ländercluster aus Sophie Spilles Arbeit reduzieren. -ncells = 4 # no. cells # TODO: zunächst = nsocs, also eine pro Land. Später mit Luana abstimmen wegen LPJ. Alternativ: Zellen aus Sophie Spilles Arbeit verwenden. -ninds = 400 # no. individuals # TODO: 10000 wie bei Nils - -t_1 = 2120 - -filename = "/home/heitzig/work/with.pickle" - -with_awareness = 1 -with_learning = 1 -with_voting = 1 - -model = M.Model() - -# instantiate process taxa: - -environment = M.Environment() - -metabolism = M.Metabolism( - renewable_energy_knowledge_spillover_fraction = 0 - ) - -culture = M.Culture( - awareness_lower_carbon_density=1e-4, - awareness_upper_carbon_density=2e-4, - awareness_update_rate = 1 if with_awareness else 0, - environmental_friendliness_learning_rate = 1 if with_learning else 0, - ) - -# generate entities and plug them together: - -(world, ) = worlds = [M.World( - environment = environment, - metabolism = metabolism, - culture = culture, - atmospheric_carbon = 830 * D.gigatonnes_carbon, - upper_ocean_carbon = (5500 - 830 - 2480 - 1125) * D.GtC - ) for w in range(nworlds)] - -# TODO: statt des folgenden ein SocialSystem pro Land: -(north, south) = social_systems = [M.SocialSystem( - world = world, - has_renewable_subsidy = False, - has_emissions_tax = False, - has_fossil_ban = False, - emissions_tax_intro_threshold = 0.5, # disabled - renewable_subsidy_intro_threshold = 1, # disabled - fossil_ban_intro_threshold = 1, # disabled - emissions_tax_level = 30 * 200e9, # see Wikipedia social cost of carbon. 100e9*3.5, - time_between_votes = 4 if with_voting else 1e100, - ) for s in range(nsocs)] - -# TODO: statt des folgenden eine Zelle pro Land: -(boreal, temperate, subtropical, tropical) = cells = [M.Cell( - social_system = social_systems[c//2], - renewable_sector_productivity = [.7, .9, 1.1, 1.3][c] - * 2000 * M.Cell.renewable_sector_productivity.default, - # represents dependency of solar energy on solar insolation angle - fossil_sector_productivity = M.Cell.fossil_sector_productivity.default * 7, - biomass_sector_productivity = M.Cell.biomass_sector_productivity.default * 5 - # these values result in realistic total energy production for the year 2000, see below # TODO: anpassen, so dass die Gesamtenergieprod. wieder stimmt, s.u. - ) for c in range(ncells)] - -# TODO: hier die Variable is_environmentally_friendly stattdessen gemäß Nils' "certainly active" nodes ersetzen: -individuals = [M.Individual( - cell = cells[i%4], - is_environmentally_friendly = - random.choice([False, True], p=[.8, .2]), # represents the "20% suffice" assumption - ) - for i in range(ninds)] - -# TODO: statt des folgenden das von Nils Skript GenerateNetwork.py erzeugte Netzwerk einlesen und verwenden: -# initialize block model acquaintance network: -target_degree = 10 # = 2.5% of all agents. Dunbar's number would be too large -target_degree_samecell = 0.5 * target_degree -target_degree_samesoc = 0.35 * target_degree -target_degree_other = 0.15 * target_degree -p_samecell = target_degree_samecell / (ninds/ncells - 1) -p_samesoc = target_degree_samesoc / (ninds/nsocs - ninds/ncells - 1) -p_other = target_degree_other / (ninds - ninds/nsocs - 1) -for index, i in enumerate(individuals): - for j in individuals[:index]: - if random.uniform() < ( - p_samecell if i.cell == j.cell - else p_samesoc if i.social_system == j.social_system \ - else p_other): - culture.acquaintance_network.add_edge(i, j) - -# TODO: statt des folgenden die echten Landflächen der Länder verwenden -# und dann die Gesamtvegetation von 2480 GtC und die Fossilen Ressourcen von 1125 GtC proportional zur Landfläche der Länder verteilen: - -# distribute area and vegetation uniformly since it seems there are no real differences between the actual zones: -Sigma0 = 1.5e8 * D.square_kilometers * array([0.25, 0.25, .25, .36]) -M.Cell.land_area.set_values(cells, Sigma0) - -L0 = 2480 * D.gigatonnes_carbon * array([0.25, 0.25, .25, .25]) # 2480 is yr 2000 -M.Cell.terrestrial_carbon.set_values(cells, L0) - -# distribute fossils linearly from north to south: -G0 = 1125 * D.gigatonnes_carbon * array([.4, .3, .2, .1]) # 1125 is yr 2000 -M.Cell.fossil_carbon.set_values(cells, G0) - -# TODO: statt des folgenden die reale Bevölkerung der Länder gemäß Nils' Inputdaten verwenden: -# distribute population 1:3 between north and south, and 2:3 within each: -r = random.uniform(size=nsocs) -P0 = 6e9 * D.people * array([0.1, 0.15, 0.3, 0.45]) # 6e9 is yr 2000 -M.SocialSystem.population.set_values(social_systems, P0) - -# TODO: statt des folgenden zunächst ein Kapital von 1e4 $ * Bevölkerung des Landes annehmen: -# distribute capital 2:1: -K0 = sum(P0) * 1e4 * D.dollars/D.people * array([2/3, 1/3]) -M.SocialSystem.physical_capital.set_values(social_systems, K0) - -# TODO: dies so lassen (alle wissen genau gleich viel zu erneuerbaren Energien): -S0 = 1e12 * D.gigajoules * array([1, 1]) -M.SocialSystem.renewable_energy_knowledge.set_values(social_systems, S0) - -w = worlds[0] -s = social_systems[0] -c = cells[0] -for v in environment.variables: print(v,v.get_value(environment)) -for v in metabolism.variables: print(v,v.get_value(metabolism)) -for v in w.variables: print(v,v.get_value(w)) -for v in s.variables: print(v,v.get_value(s)) -for v in c.variables: print(v,v.get_value(c)) - - -# do simulation: -runner = Runner(model=model) -start = time() -traj = runner.run(t_0=2000, t_1=t_1, dt=1, - add_to_output=[ - M.Individual.represented_population, - M.SocialSystem.population - ]) - - -for v in environment.variables: print(v,v.get_value(environment)) -for v in metabolism.variables: print(v,v.get_value(metabolism)) -for v in w.variables: print(v,v.get_value(w)) -for v in s.variables: print(v,v.get_value(s)) -for v in c.variables: print(v,v.get_value(c)) - - -from pickle import dump -tosave = { - v.owning_class.__name__ + "." - + v.codename: {str(e): traj[v][e] - for e in traj[v].keys() - } - for v in traj.keys() if v is not "t" - } -tosave["t"] = traj["t"] -dump(tosave, open(filename,"wb")) -print(time()-start, " seconds") - -t = np.array(traj['t']) -print("max. time step", (t[1:]-t[:-1]).max()) - -print("\nyr 2000 values (real):") -print("photo (123):",sum(traj[M.Cell.photosynthesis_carbon_flow][c][5] - for c in cells)) -print("resp (118):",sum(traj[M.Cell.terrestrial_respiration_carbon_flow][c][5] - for c in cells)) -print("GWP (4e13):",sum(traj[M.SocialSystem.economic_output_flow][s][5] - for s in social_systems)) -B0 = sum(traj[M.SocialSystem.biomass_input_flow][s][5] - for s in social_systems) -Bglobal = B0 * D.gigatonnes_carbon / D.years -Fglobal = sum(traj[M.SocialSystem.fossil_fuel_input_flow][s][5] - for s in social_systems) * D.gigatonnes_carbon / D.years -Rglobal = sum(traj[M.SocialSystem.renewable_energy_input_flow][s][5] - for s in social_systems) * D.gigajoules / D.years -Eglobal = sum(traj[M.SocialSystem.secondary_energy_flow][s][5] - for s in social_systems) * D.gigajoules / D.years - -# TODO: oben in Z.79/80 die Faktoren so wählen, dass hier ungef. B=3, F=11 und R=100 herauskommt: -print("B, F, R:", - Bglobal, Bglobal.tostr(unit=D.gigatonnes_carbon/D.years), - Fglobal, Fglobal.tostr(unit=D.gigatonnes_carbon/D.years), - Rglobal, Rglobal.tostr(unit=D.gigawatts), - ) -print("cap. deprec. at begin (0.1?):", - np.mean([traj[M.SocialSystem.physical_capital_depreciation_rate][s][5] - for s in social_systems])) -print("cap. deprec. at end (0.1?):", - np.mean([traj[M.SocialSystem.physical_capital_depreciation_rate][s][-1] - for s in social_systems])) -print("temp. at begin:", traj[M.World.surface_air_temperature][worlds[0]][5]) -print("temp. at end:", traj[M.World.surface_air_temperature][worlds[0]][-1]) -print("has emissions tax at begin", traj[M.SocialSystem.has_emissions_tax][north][5]) -print("has emissions tax at end", traj[M.SocialSystem.has_emissions_tax][north][-1]) -print("biomass prod. at begin", traj[M.Cell.biomass_relative_productivity][boreal][5] / traj[M.Cell.terrestrial_carbon][boreal][5]**2) -print("biomass prod. at end", traj[M.Cell.biomass_relative_productivity][boreal][-1] / traj[M.Cell.terrestrial_carbon][boreal][-1]**2) - diff --git a/studies/plot_example1.py b/studies/plot_example1.py deleted file mode 100755 index d5aad72e..00000000 --- a/studies/plot_example1.py +++ /dev/null @@ -1,130 +0,0 @@ -"""Script to plot example1 model results.""" - -#dir = "/home/heitzig/work/pycopancore/"; -dir = "/tmp/"; - -import numpy as np -from numpy import array, average, mean -from pylab import plot, gca, show, figure, subplots, gca, semilogy, legend, \ - tight_layout, NullLocator -from pickle import load - -f, ((ax11, ax12), (ax21, ax22), (ax31, ax32)) = \ - subplots(nrows=3, ncols=2, sharex=True, sharey=False, figsize=(12, 12)) -lws = 1 -al = 0.5 - -# LEFT: without policy - -ax11.title.set_text('example run without socio-cultural processes') - -traj = load(open(dir + "without_social.pickle","rb")) -worlds = list(traj["World.atmospheric_carbon"].keys()) -social_systems = list(traj["SocialSystem.population"].keys()) -cells = list(traj["Cell.fossil_carbon"].keys()) -individuals = list(traj["Individual.is_environmentally_friendly"].keys()) -t = np.array(traj['t']) - -# cultural -ax11.plot(t[3:], 100*average([array(traj["Individual.is_environmentally_friendly"][i][3:]*1) for i in individuals], axis=0, - weights=[array(traj["Individual.represented_population"][i][3:]*1) for i in individuals]), - color="green",lw=2, label="env. friendly individuals") -ax11.plot(t[3:], 100*mean([array(traj["SocialSystem.has_renewable_subsidy"][s][3:]*1) for s in social_systems], axis=0), - color="darkorange",lw=2, label="regions w/ renewable subsidy") -ax11.plot(t[3:], 1 + 100*mean([array(traj["SocialSystem.has_emissions_tax"][s][3:]*1) for s in social_systems], axis=0), - color="cyan",lw=2, label="regions w/ emissions tax") -ax11.plot(t[3:], 100*mean([array(traj["SocialSystem.has_fossil_ban"][s][3:]*1) for s in social_systems], axis=0), - color="gray",lw=2, label="regions w/ fossil ban") -ax11.set_ylabel('CUL:\nglobal opinions & policies\n(percent)') -ax11.set_ylim(-5,105) -# ax11.legend(title='CUL: opinions & policies') -ax11.legend(loc=7) - -# metabolic -for i, s in enumerate(social_systems): - Es = array(traj["SocialSystem.secondary_energy_flow"][s][3:]) - ax21.plot(t[3:], 100*array(traj["SocialSystem.biomass_input_flow"][s][3:]) * 40e9 / Es, - color="green", lw=lws, alpha=al, label=None if i else "biomass (5 regions)") - ax21.plot(t[3:], 100*array(traj["SocialSystem.fossil_fuel_input_flow"][s][3:]) * 47e9 / Es, - color="gray", lw=lws, alpha=al, label=None if i else "fossils (5 regions)") - ax21.plot(t[3:], 100*array(traj["SocialSystem.renewable_energy_input_flow"][s][3:]) / Es, - color="darkorange", lw=lws, alpha=al, label=None if i else "renewables (5 regions)") -ax21.set_ylabel('MET:\nregional energy shares\n(percent)') -ax21.set_ylim(-5,105) -#ax21.legend(title='MET: regional energy shares') -ax21.legend(loc=7) - -# environmental -ax31.plot(t[3:], traj["World.atmospheric_carbon"][worlds[0]][3:], - color="cyan", lw=2, label="atmosphere") -ax31.plot(t[3:], traj["World.upper_ocean_carbon"][worlds[0]][3:], - color="blue", lw=2, label="upper oceans") -ax31.plot(t[3:], sum(array(traj["Cell.terrestrial_carbon"][c][3:]) for c in cells), - color="green", lw=2, label="plants & soils") -ax31.plot(t[3:], sum(array(traj["Cell.fossil_carbon"][c][3:]) for c in cells), - color="gray", lw=2, label="fossils") -ax31.set_ylabel('ENV:\nglobal carbon stocks\n(gigatonnes carbon)') -ax31.set_ylim(-100,3100) -#ax31.legend(title='ENV: global carbon stocks') -ax31.legend(loc=7) - -ax31.set_xlabel('year') -ax31.set_xlim(1990,2110) - -# RIGHT: with policy - -ax12.title.set_text('example run with socio-cultural processes') - -traj = load(open(dir + "with_social.pickle","rb")) -worlds = list(traj["World.atmospheric_carbon"].keys()) -social_systems = list(traj["SocialSystem.population"].keys()) -cells = list(traj["Cell.fossil_carbon"].keys()) -individuals = list(traj["Individual.is_environmentally_friendly"].keys()) -t = np.array(traj['t']) - -# cultural -ax12.plot(t[3:], 100*average([array(traj["Individual.is_environmentally_friendly"][i][3:]*1) for i in individuals], axis=0, - weights=[array(traj["Individual.represented_population"][i][3:]*1) for i in individuals]), - color="green",lw=2, label="env. friendly individuals") -ax12.plot(t[3:], 100*mean([array(traj["SocialSystem.has_renewable_subsidy"][s][3:]*1) for s in social_systems], axis=0), - color="darkorange",lw=2, label="regions w/ renewable subsidy") -ax12.plot(t[3:], 100*mean([array(traj["SocialSystem.has_emissions_tax"][s][3:]*1) for s in social_systems], axis=0), - color="cyan",lw=2, label="regions w/ emissions tax") -ax12.plot(t[3:], 100*mean([array(traj["SocialSystem.has_fossil_ban"][s][3:]*1) for s in social_systems], axis=0), - color="gray",lw=2, label="regions w/ fossil ban") -ax12.set_ylim(-5,105) -ax12.yaxis.set_major_locator(NullLocator()) -ax12.legend(loc=7) - -# metabolic -for i, s in enumerate(social_systems): - Es = array(traj["SocialSystem.secondary_energy_flow"][s][3:]) - ax22.plot(t[3:], 100*array(traj["SocialSystem.biomass_input_flow"][s][3:]) * 40e9 / Es, - color="green", lw=lws, alpha=al, label=None if i else "biomass (5 regions)") - ax22.plot(t[3:], 100*array(traj["SocialSystem.fossil_fuel_input_flow"][s][3:]) * 47e9 / Es, - color="gray", lw=lws, alpha=al, label=None if i else "fossils (5 regions)") - ax22.plot(t[3:], 100*array(traj["SocialSystem.renewable_energy_input_flow"][s][3:]) / Es, - color="darkorange", lw=lws, alpha=al, label=None if i else "renewables (5 regions)") -ax22.set_ylim(-5,105) -ax22.yaxis.set_major_locator(NullLocator()) -ax22.legend(loc=7) - -# environmental -ax32.plot(t[3:], traj["World.atmospheric_carbon"][worlds[0]][3:], - color="cyan", lw=2, label="atmosphere") -ax32.plot(t[3:], traj["World.upper_ocean_carbon"][worlds[0]][3:], - color="blue", lw=2, label="upper oceans") -ax32.plot(t[3:], sum(array(traj["Cell.terrestrial_carbon"][c][3:]) for c in cells), - color="green", lw=2, label="plants & soils") -ax32.plot(t[3:], sum(array(traj["Cell.fossil_carbon"][c][3:]) for c in cells), - color="gray", lw=2, label="fossils") -ax32.yaxis.set_major_locator(NullLocator()) -ax32.set_ylim(-100,3100) - -ax32.set_xlabel('year') -ax32.set_xlim(1990,2110) -ax32.legend(loc=7) - -f.subplots_adjust(hspace=0, wspace=0) -show() - diff --git a/studies/plot_example2.py b/studies/plot_example2.py deleted file mode 100755 index d2cd69ec..00000000 --- a/studies/plot_example2.py +++ /dev/null @@ -1,158 +0,0 @@ -"""Script to plot example2 model results.""" - -import numpy as np -from numpy import array, average, mean -from pylab import plot, gca, show, figure, subplots, gca, semilogy, legend, \ - tight_layout, NullLocator -from pickle import load - -f, ((ax11, ax12), (ax21, ax22), (ax2b1, ax2b2), (ax31, ax32)) = \ - subplots(nrows=4, ncols=2, sharex=True, sharey=False, figsize=(12, 12)) -lws = 1 -al = 0.5 -lss = ['-','--'] - - -# LEFT: without policy - -ax11.title.set_text('example run without socio-cultural processes') - -traj = load(open("/home/jobst/work/without.pickle","rb")) -worlds = list(traj["World.atmospheric_carbon"].keys()) -social_systems = list(traj["SocialSystem.has_emissions_tax"].keys()) -cells = list(traj["Cell.fossil_carbon"].keys()) -individuals = list(traj["Individual.is_environmentally_friendly"].keys()) -t = np.array(traj['t']) - -print(social_systems, cells) - -# cultural -for i, s in enumerate(social_systems): - ax11.plot(t[3:], 100*average([array(traj["Individual.is_environmentally_friendly"][ii][3:]*1) for j, ii in enumerate(individuals) if (j%4)//2 == i], axis=0, - weights=[array(traj["Individual.represented_population"][ii][3:]*1) for j, ii in enumerate(individuals) if (j%4)//2 == i]), - color="green",lw=1, linestyle=lss[i], label=None if i else "env. friendly individuals") -ax11.plot(t[3:], 1 + 100*mean([array(traj["SocialSystem.has_emissions_tax"][s][3:]*1) for s in social_systems], axis=0), - color="cyan",lw=2, label="regions w/ emissions tax") -ax11.set_ylabel('CUL:\nregional opinions & policies\n(percent)') -ax11.set_ylim(-5,105) -# ax11.legend(title='CUL: opinions & policies') -#ax11.legend(loc=7) - -# metabolic -for i, s in enumerate(social_systems): - Es = array(traj["SocialSystem.secondary_energy_flow"][s][3:]) - ax21.plot(t[3:], 100*array(traj["SocialSystem.biomass_input_flow"][s][3:]) * 40e9 / Es, - color="green", lw=lws, alpha=al, linestyle=lss[i], label=None if i else "biomass") - ax21.plot(t[3:], 100*array(traj["SocialSystem.fossil_fuel_input_flow"][s][3:]) * 47e9 / Es, - color="gray", lw=lws, alpha=al, linestyle=lss[i], label=None if i else "fossils") - ax21.plot(t[3:], 100*array(traj["SocialSystem.renewable_energy_input_flow"][s][3:]) / Es, - color="darkorange", lw=lws, linestyle=lss[i], alpha=al, label=None if i else "renewables") - ax2b1.semilogy(t[3:], array(traj["SocialSystem.economic_output_flow"][s][3:]) - / array(traj["SocialSystem.population"][s][3:]), - color="magenta", lw=lws, alpha=al, linestyle=lss[i], label=None if i else "GDP per capita [USD/yr]") - ax2b1.semilogy(t[3:], 1e-9 * array(traj["SocialSystem.physical_capital"][s][3:]), - color="black", lw=lws, alpha=al, linestyle=lss[i], label=None if i else "physical capital [bln. USD]") -ax21.set_ylabel('MET:\nregional energy shares\n(percent)') -ax21.set_ylim(-5,105) -ax2b1.set_ylim(.9e4,1.1e6) -#ax21.legend(title='MET: regional energy shares') -#ax21.legend(loc=7) - -ax2b1.set_ylabel('MET:\neconomic production\n(log-scale)') -#ax2b1.set_ylim(-5,105) -#ax21.legend(title='MET: regional energy shares') -#ax2b1.legend(loc=7) - -# environmental -ax31.plot(t[3:], traj["World.atmospheric_carbon"][worlds[0]][3:], - color="cyan", lw=2, label="atmosphere (global)") -ax31.plot(t[3:], traj["World.upper_ocean_carbon"][worlds[0]][3:], - color="blue", lw=2, label="upper oceans (global)") -#ax31.plot(t[3:], sum(array(traj["Cell.terrestrial_carbon"][c][3:]) for c in cells), -# color="green", lw=2, label="plants & soils") -#ax31.plot(t[3:], sum(array(traj["Cell.fossil_carbon"][c][3:]) for c in cells), -# color="gray", lw=2, label="fossils") -for i, c in enumerate(cells): - ax31.plot(t[3:], array(traj["Cell.terrestrial_carbon"][c][3:]), - color="green", lw=1, linestyle=lss[i//2], label=None if i else "plants & soils (per cell)") - ax31.plot(t[3:], array(traj["Cell.fossil_carbon"][c][3:]), - color="gray", lw=1, linestyle=lss[i//2], label=None if i else "fossils (per cell)") -ax31.set_ylabel('ENV:\ncarbon stocks\n(gigatonnes carbon)') -ax31.set_ylim(-100,1300) #3100) -#ax31.legend(title='ENV: global carbon stocks') -#ax31.legend(loc=7) - -ax31.set_xlabel('year') -ax31.set_xlim(1990,2110) - - -# RIGHT: with policy - -ax12.title.set_text('example run with socio-cultural processes') - -traj = load(open("/home/jobst/work/with.pickle","rb")) -worlds = list(traj["World.atmospheric_carbon"].keys()) -social_systems = list(traj["SocialSystem.has_emissions_tax"].keys()) -cells = list(traj["Cell.fossil_carbon"].keys()) -individuals = list(traj["Individual.is_environmentally_friendly"].keys()) -t = np.array(traj['t']) - -print((s,traj["SocialSystem.has_emissions_tax"][s]) for s in social_systems) - -# cultural -for i, s in enumerate(social_systems): - ax12.plot(t[3:], 100*average([array(traj["Individual.is_environmentally_friendly"][ii][3:]*1) for j, ii in enumerate(individuals) if (j%4)//2 == i], axis=0, - weights=[array(traj["Individual.represented_population"][ii][3:]*1) for j, ii in enumerate(individuals) if (j%4)//2 == i]), - color="green",lw=1, linestyle=lss[i], label=None if i else "env. friendly individuals") -ax12.plot(t[3:], 100*mean([array(traj["SocialSystem.has_emissions_tax"][s][3:]*1) for s in social_systems], axis=0), - color="cyan",lw=2, label="regions w/ emissions tax") -ax12.set_ylim(-5,105) -ax12.yaxis.set_major_locator(NullLocator()) -ax12.legend(loc=7) - -# metabolic -for i, s in enumerate(social_systems): - Es = array(traj["SocialSystem.secondary_energy_flow"][s][3:]) - ax22.plot(t[3:], 100*array(traj["SocialSystem.biomass_input_flow"][s][3:]) * 40e9 / Es, - color="green", lw=lws, alpha=al, linestyle=lss[i], label=None if i else "biomass") - ax22.plot(t[3:], 100*array(traj["SocialSystem.fossil_fuel_input_flow"][s][3:]) * 47e9 / Es, - color="gray", lw=lws, alpha=al, linestyle=lss[i], label=None if i else "fossils") - ax22.plot(t[3:], 100*array(traj["SocialSystem.renewable_energy_input_flow"][s][3:]) / Es, - color="darkorange", lw=lws, alpha=al, linestyle=lss[i], label=None if i else "renewables") - ax2b2.semilogy(t[3:], array(traj["SocialSystem.economic_output_flow"][s][3:]) - / array(traj["SocialSystem.population"][s][3:]), - color="magenta", lw=lws, alpha=al, linestyle=lss[i], label=None if i else "GDP per capita [USD/yr]") - ax2b2.semilogy(t[3:], 1e-9 * array(traj["SocialSystem.physical_capital"][s][3:]), - color="black", lw=lws, alpha=al, linestyle=lss[i], label=None if i else "physical capital [bln. USD]") -ax22.set_ylim(-5,105) -ax2b2.set_ylim(.9e4,1.1e6) -ax22.yaxis.set_major_locator(NullLocator()) -ax2b2.yaxis.set_major_locator(NullLocator()) -ax22.legend(loc=7) -ax2b2.legend(loc=8) - -# environmental -ax32.plot(t[3:], traj["World.atmospheric_carbon"][worlds[0]][3:], - color="cyan", lw=2, label="atmosphere") -ax32.plot(t[3:], traj["World.upper_ocean_carbon"][worlds[0]][3:], - color="blue", lw=2, label="upper oceans") -#ax32.plot(t[3:], sum(array(traj["Cell.terrestrial_carbon"][c][3:]) for c in cells), -# color="green", lw=2, label="plants & soils") -#ax32.plot(t[3:], sum(array(traj["Cell.fossil_carbon"][c][3:]) for c in cells), -# color="gray", lw=2, label="fossils") -for i, c in enumerate(cells): - ax32.plot(t[3:], array(traj["Cell.terrestrial_carbon"][c][3:]), - color="green", lw=1, linestyle=lss[i//2], label=None if i else "plants & soils (per cell)") - ax32.plot(t[3:], array(traj["Cell.fossil_carbon"][c][3:]), - color="gray", lw=1, linestyle=lss[i//2], label=None if i else "fossils (per cell)") - -ax32.yaxis.set_major_locator(NullLocator()) -ax32.set_ylim(-100,1300) #3100) - -ax32.set_xlabel('year') -ax32.set_xlim(1990,2110) -ax32.legend(loc=8) - -f.subplots_adjust(hspace=0, wspace=0) -show() - diff --git a/studies/plot_example2_mw.py b/studies/plot_example2_mw.py deleted file mode 100755 index c5f18765..00000000 --- a/studies/plot_example2_mw.py +++ /dev/null @@ -1,168 +0,0 @@ -"""Script to plot example2 model results.""" -import matplotlib -matplotlib.use("Agg") -import numpy as np -from numpy import array, average, mean -from pylab import plot, gca, show, figure, subplots, gca, semilogy, legend, \ - tight_layout, NullLocator, savefig, setp -from pickle import load - -with_file = "core_with_social_p_0.9.p" -wo_file ="core_without_social_p_0.4.p" - - -f, ((ax11, ax12), (ax21, ax22), (ax31, ax32)) = \ - subplots(nrows=3, ncols=2, sharey=False, figsize=(12, 12)) -lws = 1 -al = 0.5 - -# LEFT: without policy - -ax11.title.set_text('example run without socio-cultural processes') - -traj = load(open(wo_file,"rb")) -worlds = list(traj["World.atmospheric_carbon"].keys()) -social_systems = list(traj["SocialSystem.has_fossil_ban"].keys()) -cells = list(traj["Cell.fossil_carbon"].keys()) -individuals = list(traj["Individual.is_environmentally_friendly"].keys()) -t = np.array(traj['t']) - -print(t) -print(social_systems, cells) - -# cultural -ax11.plot(t[3:], 100*average([array(traj["Individual.is_environmentally_friendly"][i][3:]*1) for i in individuals], axis=0, - weights=[array(traj["Individual.represented_population"][i][3:]*1) for i in individuals]), - color="green",lw=2, label="env. friendly individuals") -ax11.plot(t[3:], 1 + 100*mean([array(traj["SocialSystem.has_fossil_ban"][s][3:]*1) for s in social_systems], axis=0), - color="cyan",lw=2, label="regions w/ subsidy and fossil ban") -ax11.set_ylabel('CUL:\nglobal opinions & policies\n(percent)') -ax11.set_ylim(-5,105) -# ax11.legend(title='CUL: opinions & policies') -ax11.legend(loc=7) - -# metabolic -for i, s in enumerate(social_systems): - Es = array(traj["SocialSystem.secondary_energy_flow"][s][3:]) - ax21.plot(t[3:], 100*array(traj["SocialSystem.biomass_input_flow"][s][3:]) * 40e9 / Es, - color="green", lw=lws, alpha=al, label=None if i else "biomass") - ax21.plot(t[3:], 100*array(traj["SocialSystem.fossil_fuel_input_flow"][s][3:]) * 47e9 / Es, - color="gray", lw=lws, alpha=al, label=None if i else "fossils") - ax21.plot(t[3:], 100*array(traj["SocialSystem.renewable_energy_input_flow"][s][3:]) / Es, - color="darkorange", lw=lws, alpha=al, label=None if i else "renewables") -ax21.set_ylabel('MET:\nregional energy shares\n(percent)') -ax21.set_ylim(-5,105) -#ax21.legend(title='MET: regional energy shares') -ax21.legend(loc=7) - -# environmental -atmos_carb = traj["World.atmospheric_carbon"][worlds[0]][3:] -ocean_carb = traj["World.upper_ocean_carbon"][worlds[0]][3:] -terre_carb = sum(array(traj["Cell.terrestrial_carbon"][c][3:]) for c in cells) -fossi_carb = sum(array(traj["Cell.fossil_carbon"][c][3:]) for c in cells) -photosynth = 10 * sum(array(traj["Cell.photosynthesis_carbon_flow"][c][3:]) for c in cells) - -print((atmos_carb+terre_carb+ocean_carb)[-1]) -ax31.plot(t[3:], atmos_carb, - color="cyan", lw=2, label="atmosphere") -ax31.plot(t[3:], ocean_carb, - color="blue", lw=2, label="upper oceans") -ax31.plot(t[3:], terre_carb, - color="green", lw=2, label="plants & soils") -ax31.plot(t[3:], fossi_carb, - color="gray", lw=2, label="fossils") -ax31.plot(t[3:], photosynth, - color="yellow", lw=2, label="photo") - -ax31.plot(t[3:], (fossi_carb+atmos_carb+ocean_carb+terre_carb)/4, - color="gray", lw=2, ls=":", label="average") - -ax31a = ax31.twinx() -ax31a.plot(t[3:], - np.array(traj["World.surface_air_temperature"][worlds[0]][3:]) - - 273, - color="black", lw=2, label="GMT") -ax31a.legend() -ax31a.set_ylim(13,18) -setp(ax31a.get_yticklabels(), visible=False) - -ax31.set_ylabel('ENV:\nglobal carbon stocks\n(gigatonnes carbon)') -ax31.set_ylim(-100,4100) -#ax31.legend(title='ENV: global carbon stocks') -ax31.legend(loc="upper left") - -ax31.set_xlabel('year') -ax31.set_xlim(1990,2110) - -# RIGHT: with policy - -ax12.title.set_text('example run with socio-cultural processes') - -traj = load(open(with_file,"rb")) -worlds = list(traj["World.atmospheric_carbon"].keys()) -social_systems = list(traj["SocialSystem.has_fossil_ban"].keys()) -cells = list(traj["Cell.fossil_carbon"].keys()) -individuals = list(traj["Individual.is_environmentally_friendly"].keys()) -t = np.array(traj['t']) - -print((s,traj["SocialSystem.has_fossil_ban"][s]) for s in social_systems) - -# cultural -ax12.plot(t[3:], 100*average([array(traj["Individual.is_environmentally_friendly"][i][3:]*1) for i in individuals], axis=0, - weights=[array(traj["Individual.represented_population"][i][3:]*1) for i in individuals]), - color="green",lw=2, label="env. friendly individuals") -ax12.plot(t[3:], 100*mean([array(traj["SocialSystem.has_fossil_ban"][s][3:]*1) for s in social_systems], axis=0), - color="cyan",lw=2, label="regions w/ subsidy and fossil ban") -ax12.set_ylim(-5,105) -ax12.yaxis.set_major_locator(NullLocator()) -ax12.legend(loc=7) - -# metabolic -for i, s in enumerate(social_systems): - Es = array(traj["SocialSystem.secondary_energy_flow"][s][3:]) - ax22.plot(t[3:], 100*array(traj["SocialSystem.biomass_input_flow"][s][3:]) * 40e9 / Es, - color="green", lw=lws, alpha=al, label=None if i else "biomass") - ax22.plot(t[3:], 100*array(traj["SocialSystem.fossil_fuel_input_flow"][s][3:]) * 47e9 / Es, - color="gray", lw=lws, alpha=al, label=None if i else "fossils") - ax22.plot(t[3:], 100*array(traj["SocialSystem.renewable_energy_input_flow"][s][3:]) / Es, - color="darkorange", lw=lws, alpha=al, label=None if i else "renewables") -ax22.set_ylim(-5,105) -ax22.yaxis.set_major_locator(NullLocator()) -ax22.legend(loc=7) - -# environmental -atmos_carb = traj["World.atmospheric_carbon"][worlds[0]][3:] -ocean_carb = traj["World.upper_ocean_carbon"][worlds[0]][3:] -terre_carb = sum(array(traj["Cell.terrestrial_carbon"][c][3:]) for c in cells) -fossi_carb = sum(array(traj["Cell.fossil_carbon"][c][3:]) for c in cells) - -print((atmos_carb+terre_carb+ocean_carb)[-1]) -ax32.plot(t[3:], atmos_carb, - color="cyan", lw=2, label="atmosphere") -ax32.plot(t[3:], ocean_carb, - color="blue", lw=2, label="upper oceans") -ax32.plot(t[3:], terre_carb, - color="green", lw=2, label="plants & soils") -ax32.plot(t[3:], fossi_carb, - color="gray", lw=2, label="fossils") -ax32.plot(t[3:], (fossi_carb+atmos_carb+ocean_carb+terre_carb)/4, - color="gray", lw=2, ls=":", label="average") - - -ax32a = ax32.twinx() -ax32a.set_ylabel("Global mean temperature [Celcius]") -ax32a.plot(t[3:], - np.array(traj["World.surface_air_temperature"][worlds[0]][3:]) - - 273, - color="black", lw=2, label="GMT") -ax32a.set_ylim(13,18) -ax32a.legend() -ax32.yaxis.set_major_locator(NullLocator()) -ax32.set_ylim(-100,4100) - -ax32.set_xlabel('year') -ax32.set_xlim(1990,2110) -ax32.legend(loc="upper left") - -f.subplots_adjust(hspace=0, wspace=0) -savefig(with_file+"df") diff --git a/studies/plot_figure5.py b/studies/plot_figure5.py deleted file mode 100644 index f278489f..00000000 --- a/studies/plot_figure5.py +++ /dev/null @@ -1,163 +0,0 @@ -"""Script to plot example2 model results.""" -import matplotlib -matplotlib.use("Agg") -import numpy as np -from numpy import array, average, mean -from pylab import plot, gca, show, figure, subplots, gca, semilogy, legend, \ - tight_layout, NullLocator, savefig, setp, tight_layout -from pickle import load - -with_file = "with_social_learning_rate_4.p" -wo_file ="without_social.p" - -f, ((ax11, ax12), (ax21, ax22), (ax21a, ax22a), (ax31, ax32)) = \ - subplots(nrows=4, ncols=2, sharex=True, figsize=(12, 14)) -lws = 2 -al = 1. - -# LEFT: without policy - -ax11.title.set_text('example run without socio-cultural processes') - -traj = load(open(wo_file,"rb")) -worlds = list(traj["World.atmospheric_carbon"].keys()) -social_systems = list(traj["SocialSystem.has_fossil_ban"].keys()) -cells = list(traj["Cell.fossil_carbon"].keys()) -individuals = list(traj["Individual.is_environmentally_friendly"].keys()) -t = np.array(traj['t']) - 2000 # to have model years - -print(t) -print(social_systems, cells) - -# cultural -ax11.plot(t[3:], 100*average([array(traj["Individual.is_environmentally_friendly"][i][3:]*1) for i in individuals], axis=0, - weights=[array(traj["Individual.represented_population"][i][3:]*1) for i in individuals]), - color="green",lw=2, label="env. friendly individuals") -ax11.plot(t[3:], 1 + 100*mean([array(traj["SocialSystem.has_fossil_ban"][s][3:]*1) for s in social_systems], axis=0), - color="cyan",lw=2, label="regions w/ subsidy and fossil ban") -ax11.set_ylabel('CUL:\nglobal opinions & policies\n(percent)') -ax11.set_ylim(-5,105) -# ax11.legend(title='CUL: opinions & policies') -ax11.legend(loc=7) - -# metabolic -ls = ["-", ":"] -#ax21a = ax21.twinx() - -for i, s in enumerate(social_systems): - Es = array(traj["SocialSystem.secondary_energy_flow"][s][3:]) - ax21.plot(t[3:], 100*array(traj["SocialSystem.biomass_input_flow"][s][3:]) * 40e9 / Es, - color="green", ls=ls[i], lw=lws, alpha=al, label=None if i else "biomass") - ax21.plot(t[3:], 100*array(traj["SocialSystem.fossil_fuel_input_flow"][s][3:]) * 47e9 / Es, - color="gray", ls=ls[i], lw=lws, alpha=al, label=None if i else "fossils") - ax21.plot(t[3:], 100*array(traj["SocialSystem.renewable_energy_input_flow"][s][3:]) / Es, - color="darkorange", ls=ls[i], lw=lws, alpha=al, label=None if i else "renewables") - ax21a.plot(t[3:], - 100*array(traj["SocialSystem.economic_output_flow"][s][3:]) / - [0.25, 0.75][i] / 6e9, - color="red", ls=ls[i], lw=lws, alpha=al, label=None if i else "GDP") - -ax21a.semilogy() -ax21.set_ylabel('MET:\nregional energy shares\n(percent)') -ax21.set_ylim(-5,105) -#ax21.legend(title='MET: regional energy shares') -ax21.legend() - -ax21a.set_ylabel('MET:\nGDP/capita ($/yr)') - -# environmental -atmos_carb = traj["World.atmospheric_carbon"][worlds[0]][3:] -ocean_carb = traj["World.upper_ocean_carbon"][worlds[0]][3:] -terre_carb = sum(array(traj["Cell.terrestrial_carbon"][c][3:]) for c in cells) -fossi_carb = sum(array(traj["Cell.fossil_carbon"][c][3:]) for c in cells) -photosynth = 10 * sum(array(traj["Cell.photosynthesis_carbon_flow"][c][3:]) for c in cells) - -print((atmos_carb+terre_carb+ocean_carb)[-1]) -ax31.plot(t[3:], atmos_carb, - color="cyan", lw=2, label="atmosphere") -ax31.plot(t[3:], ocean_carb, - color="blue", lw=2, label="upper oceans") -ax31.plot(t[3:], terre_carb, - color="green", lw=2, label="plants & soils") -ax31.plot(t[3:], fossi_carb, - color="gray", lw=2, label="fossils") - -setp(ax12.get_yticklabels(), visible=False) -setp(ax22.get_yticklabels(), visible=False) -setp(ax32.get_yticklabels(), visible=False) -setp(ax22a.get_yticklabels(), visible=False) - -ax31.set_ylabel('ENV:\nglobal carbon stocks\n(gigatonnes carbon)') -ax31.set_ylim(-100,3500) -ax31.legend(loc="upper left") - -ax31.set_xlabel('model year') # if we subtract 2000 above -ax31.set_xlim(0,120) # (1990,2110) - -# RIGHT: with policy - -ax12.title.set_text('example run with socio-cultural processes') - -traj = load(open(with_file,"rb")) -worlds = list(traj["World.atmospheric_carbon"].keys()) -social_systems = list(traj["SocialSystem.has_fossil_ban"].keys()) -cells = list(traj["Cell.fossil_carbon"].keys()) -individuals = list(traj["Individual.is_environmentally_friendly"].keys()) -t = np.array(traj['t']) - 2000 # to have model years - -print((s,traj["SocialSystem.has_fossil_ban"][s]) for s in social_systems) - -# cultural -ax12.plot(t[3:], 100*average([array(traj["Individual.is_environmentally_friendly"][i][3:]*1) for i in individuals], axis=0, - weights=[array(traj["Individual.represented_population"][i][3:]*1) for i in individuals]), - color="green",lw=2, label="env. friendly individuals") -ax12.plot(t[3:], 100*mean([array(traj["SocialSystem.has_fossil_ban"][s][3:]*1) for s in social_systems], axis=0), - color="cyan",lw=2, label="regions w/ subsidy and fossil ban") -ax12.set_ylim(-5,105) -#ax12.yaxis.set_major_locator(NullLocator()) -#ax12.legend(loc=7) - -# metabolic -#ax22a = ax22.twinx() -for i, s in enumerate(social_systems): - Es = array(traj["SocialSystem.secondary_energy_flow"][s][3:]) - ax22.plot(t[3:], 100*array(traj["SocialSystem.biomass_input_flow"][s][3:]) * 40e9 / Es, - color="green", ls=ls[i], lw=lws, alpha=al, label=None if i else "biomass") - ax22.plot(t[3:], 100*array(traj["SocialSystem.fossil_fuel_input_flow"][s][3:]) * 47e9 / Es, - color="gray", ls=ls[i], lw=lws, alpha=al, label=None if i else "fossils") - ax22.plot(t[3:], 100*array(traj["SocialSystem.renewable_energy_input_flow"][s][3:]) / Es, - color="darkorange", ls=ls[i], lw=lws, alpha=al, label=None if i else "renewables") - ax22a.plot(t[3:], - 100*array(traj["SocialSystem.economic_output_flow"][s][3:]) / - [0.25, 0.75][i] / 6e9, - color="red", ls=ls[i], lw=lws, alpha=al, label=None if i else "GDP") - -ax22a.semilogy() -#äax22a.legend() -ax22.set_ylim(-5,105) -#ax22.yaxis.set_major_locator(NullLocator()) -#ax22.legend(loc=7) - -# environmental -atmos_carb = traj["World.atmospheric_carbon"][worlds[0]][3:] -ocean_carb = traj["World.upper_ocean_carbon"][worlds[0]][3:] -terre_carb = sum(array(traj["Cell.terrestrial_carbon"][c][3:]) for c in cells) -fossi_carb = sum(array(traj["Cell.fossil_carbon"][c][3:]) for c in cells) - -print((atmos_carb+terre_carb+ocean_carb)[-1]) -ax32.plot(t[3:], atmos_carb, - color="cyan", lw=2, label="atmosphere") -ax32.plot(t[3:], ocean_carb, - color="blue", lw=2, label="upper oceans") -ax32.plot(t[3:], terre_carb, - color="green", lw=2, label="plants & soils") -ax32.plot(t[3:], fossi_carb, - color="gray", lw=2, label="fossils") -ax32.set_ylim(0,3500) - -ax32.set_xlabel('model year') -ax32.set_xlim(0,120) #(1990,2110) -#ax32.set_xlim(t.min(), t.max()) -f.subplots_adjust(hspace=0, wspace=0.05) -tight_layout() -savefig("figure5.pdf") diff --git a/studies/plot_jobsts_prototype_1.py b/studies/plot_jobsts_prototype_1.py deleted file mode 100755 index 80921a7e..00000000 --- a/studies/plot_jobsts_prototype_1.py +++ /dev/null @@ -1,123 +0,0 @@ -"""Skript to plot Jobsts prototype model results.""" - -# This file is part of pycopancore. -# -# Copyright (C) 2016-2017 by COPAN team at Potsdam Institute for Climate -# Impact Research -# -# URL: -# Contact: core@pik-potsdam.de -# License: BSD 2-clause license - -import numpy as np -from numpy import array, average, mean -from pylab import plot, gca, show, figure, subplots, gca, semilogy, legend, tight_layout, NullLocator -from pickle import load - -f, ((ax11, ax12), (ax21, ax22), (ax31, ax32)) = subplots(nrows=3, ncols=2, sharex=True, sharey=False) -lws = 1 -al = 0.5 - -# LEFT: without policy - -traj = load(open("/home/jobst/work/without.pickle","rb")) -worlds = list(traj["World.atmospheric_carbon"].keys()) -social_systems = list(traj["SocialSystem.population"].keys()) -cells = list(traj["Cell.fossil_carbon"].keys()) -individuals = list(traj["Individual.is_environmentally_friendly"].keys()) -t = np.array(traj['t']) - -print(sum(array(traj["SocialSystem.protected_terrestrial_carbon"][s]) for s in social_systems) - / sum(array(traj["Cell.terrestrial_carbon"][c]) for c in cells)) -quit() - -# cultural -ax11.plot(t[3:], 100*average([array(traj["Individual.is_environmentally_friendly"][i][3:]*1) for i in individuals], axis=0, -# weights=[array(traj["Individual.represented_population"][i][3:]*1) for i in individuals] - ),color="green",lw=lws, label="env. friendly individuals") -ax11.plot(t[3:], 100*mean([array(traj["SocialSystem.has_renewable_subsidy"][s][3:]*1) for s in social_systems], axis=0),color="darkorange",lw=lws, label="regions w/ renewable subsidy") -ax11.plot(t[3:], 100*mean([array(traj["SocialSystem.has_emissions_tax"][s][3:]*1) for s in social_systems], axis=0),color="blue",lw=lws, label="regions w/ emissions tax") -ax11.plot(t[3:], 100*mean([array(traj["SocialSystem.has_fossil_ban"][s][3:]*1) for s in social_systems], axis=0),color="gray",lw=lws, label="regions w/ fossil ban") -ax11.set_ylabel('percent') -ax11.set_ylim(-5,105) - -# metabolic -for i, s in enumerate(social_systems): - Es = array(traj["SocialSystem.secondary_energy_flow"][s][3:]) - ax21.plot(t[3:], 100*array(traj["SocialSystem.biomass_input_flow"][s][3:]) * 40e9 / Es, color="green", lw=lws, alpha=al, label=None if i else "biomass") - ax21.plot(t[3:], 100*array(traj["SocialSystem.fossil_fuel_input_flow"][s][3:]) * 47e9 / Es, color="gray", lw=lws, alpha=al, label=None if i else "fossils") - ax21.plot(t[3:], 100*array(traj["SocialSystem.renewable_energy_input_flow"][s][3:]) / Es, color="darkorange", lw=lws, alpha=al, label=None if i else "renewables") -#plot(t[3:], 100*average([array(traj["biomass_input_flow"][s][3:]) for s in social_systems], axis=0, -# weights=[array(traj["population"][s][3:]) for s in social_systems]) * 40e9 / Es, color="green", lw=3, label="global share of biomass energy") -#plot(t[3:], 100*average([array(traj["fossil_fuel_input_flow"][s][3:]) for s in social_systems], axis=0, -# weights=[array(traj["population"][s][3:]) for s in social_systems]) * 47e9 / Es, color="gray", lw=3, label="global share of fossil energy") -#plot(t[3:], 100*average([array(traj["renewable_energy_input_flow"][s][3:]) for s in social_systems], axis=0, -# weights=[array(traj["population"][s][3:]) for s in social_systems]) / Es, color="darkorange", lw=3, label="global share of renewables") -ax21.set_ylabel('percent') -ax21.set_ylim(-5,105) - -# natural -ax31.plot(t[3:], traj["World.atmospheric_carbon"][worlds[0]][3:], color="cyan", lw=2, label="atmosphere") -ax31.plot(t[3:], traj["World.upper_ocean_carbon"][worlds[0]][3:], color="blue", lw=2, label="upper oceans") -ax31.plot(t[3:], sum(array(traj["Cell.terrestrial_carbon"][c][3:]) for c in cells), color="green", lw=2, label="plants & soils") -ax31.plot(t[3:], sum(array(traj["Cell.fossil_carbon"][c][3:]) for c in cells), color="gray", lw=2, label="fossils") -#for i, s in enumerate(social_systems): -# plot(t[3:], traj["protected_terrestrial_carbon"][s][3:],color="green",lw=lws, label=None if i else "protected biomass") -ax31.set_ylabel('gigatonnes carbon') - -# RIGHT: with policy - -traj = load(open("/home/jobst/work/with.pickle","rb")) -worlds = list(traj["World.atmospheric_carbon"].keys()) -social_systems = list(traj["SocialSystem.population"].keys()) -cells = list(traj["Cell.fossil_carbon"].keys()) -individuals = list(traj["Individual.is_environmentally_friendly"].keys()) -t = np.array(traj['t']) - -# cultural -ax12.plot(t[3:], 100*average([array(traj["Individual.is_environmentally_friendly"][i][3:]*1) for i in individuals], axis=0, - weights=[array(traj["Individual.represented_population"][i][3:]*1) for i in individuals] - ),color="green",lw=lws, label="env. friendly individuals") -ax12.plot(t[3:], 100*mean([array(traj["SocialSystem.has_renewable_subsidy"][s][3:]*1) for s in social_systems], axis=0),color="darkorange",lw=lws, label="regions w/ renewable subsidy") -ax12.plot(t[3:], 100*mean([array(traj["SocialSystem.has_emissions_tax"][s][3:]*1) for s in social_systems], axis=0),color="blue",lw=lws, label="regions w/ emissions tax") -ax12.plot(t[3:], 100*mean([array(traj["SocialSystem.has_fossil_ban"][s][3:]*1) for s in social_systems], axis=0),color="gray",lw=lws, label="regions w/ fossil ban") -ax12.set_ylim(-5,105) -ax12.yaxis.set_major_locator(NullLocator()) -ax12.legend() - -# metabolic -for i, s in enumerate(social_systems): - Es = array(traj["SocialSystem.secondary_energy_flow"][s][3:]) - ax22.plot(t[3:], 100*array(traj["SocialSystem.biomass_input_flow"][s][3:]) * 40e9 / Es, color="green", lw=lws, alpha=al, label=None if i else "biomass") - ax22.plot(t[3:], 100*array(traj["SocialSystem.fossil_fuel_input_flow"][s][3:]) * 47e9 / Es, color="gray", lw=lws, alpha=al, label=None if i else "fossils") - ax22.plot(t[3:], 100*array(traj["SocialSystem.renewable_energy_input_flow"][s][3:]) / Es, color="darkorange", lw=lws, alpha=al, label=None if i else "renewables") -#plot(t[3:], 100*average([array(traj["biomass_input_flow"][s][3:]) for s in social_systems], axis=0, -# weights=[array(traj["population"][s][3:]) for s in social_systems]) * 40e9 / Es, color="green", lw=3, label="global share of biomass energy") -#plot(t[3:], 100*average([array(traj["fossil_fuel_input_flow"][s][3:]) for s in social_systems], axis=0, -# weights=[array(traj["population"][s][3:]) for s in social_systems]) * 47e9 / Es, color="gray", lw=3, label="global share of fossil energy") -#plot(t[3:], 100*average([array(traj["renewable_energy_input_flow"][s][3:]) for s in social_systems], axis=0, -# weights=[array(traj["population"][s][3:]) for s in social_systems]) / Es, color="darkorange", lw=3, label="global share of renewables") -ax22.set_ylim(-5,105) -ax22.yaxis.set_major_locator(NullLocator()) -ax22.legend() - -# natural -ax32.plot(t[3:], traj["World.atmospheric_carbon"][worlds[0]][3:], color="cyan", lw=2, label="atmosphere") -ax32.plot(t[3:], traj["World.upper_ocean_carbon"][worlds[0]][3:], color="blue", lw=2, label="upper oceans") -ax32.plot(t[3:], sum(array(traj["Cell.terrestrial_carbon"][c][3:]) for c in cells), color="green", lw=2, label="plants & soils") -ax32.plot(t[3:], sum(array(traj["Cell.fossil_carbon"][c][3:]) for c in cells), color="gray", lw=2, label="fossils") -#for i, s in enumerate(social_systems): -# plot(t[3:], traj["protected_terrestrial_carbon"][s][3:],color="green",lw=lws, label=None if i else "protected biomass") -#ax32.yaxis.set_major_locator(NullLocator()) -ax32.legend() - -f.subplots_adjust(hspace=0, wspace=0) -show() - -# TODO: -# policy shares, env. friendly shares -# transparancy, means -# wellb. abs., renew., pop. log -# total protected -# horiz. -# save dump with codename,uid as key \ No newline at end of file diff --git a/studies/run_adaptive_voter_model.py b/studies/run_adaptive_voter_model.py deleted file mode 100755 index c271908d..00000000 --- a/studies/run_adaptive_voter_model.py +++ /dev/null @@ -1,134 +0,0 @@ -"""Skript to run the model.""" - -# This file is part of pycopancore. -# -# Copyright (C) 2016-2017 by COPAN team at Potsdam Institute for Climate -# Impact Research -# -# URL: -# Contact: core@pik-potsdam.de -# License: BSD 2-clause license -from time import time -import datetime as dt -# from numpy import random -import random -# import networkx as nx -import numpy as np -# import sys -import pycopancore.models.adaptive_voter_model as M -# import pycopancore.models.only_copan_global_like_carbon_cycle as M -# from pycopancore import master_data_model as D -from pycopancore.runners import Runner - -# import plotly.plotly as py -import plotly.offline as py -import plotly.graph_objs as go - -# first thing: set seed so that each execution must return same thing: -random.seed(1) -# TODO: figure out why it doesn't seem to work here ... - -# parameters: -timeinterval = 100 -timestep = 0.1 -expected_degree = 10 -nindividuals = 4000 -rewiring_probability = 0.1 -possible_opinions = list(range(2)) -p_initial = 0.7 # probability of initial opinion 0 (over opinion 1) - -# instantiate model -model = M.Model() - -# instantiate process taxa: -culture = M.Culture(rewiring=rewiring_probability) - -# generate entities and distribute opinions uniformly randomly: -world = M.World(culture=culture) -social_system = M.SocialSystem(world=world, culture=culture) -cell = M.Cell(world=world, social_system=social_system) -individuals = [M.Individual(cell=cell, - initial_opinion=int(random.random() < p_initial)) - for _ in range(nindividuals)] - - -def erdosrenyify(graph, p=0.5): - """Create a ErdosRenzi graph from networkx graph. - - Take a a networkx.Graph with nodes and distribute the edges following the - erdos-renyi graph procedure. - """ - assert not graph.edges(), "your graph has already edges" - nodes = list(graph.nodes()) - for i, n1 in enumerate(nodes[:-1]): - for n2 in nodes[i+1:]: - if random.random() < p: - graph.add_edge(n1, n2) - - -# set the initial graph structure to be an erdos-renyi graph -print("erdosrenyifying the graph ... ", end="", flush=True) -start = time() -erdosrenyify(culture.acquaintance_network, p=expected_degree / nindividuals) -print("done ({})".format(dt.timedelta(seconds=(time() - start)))) - -runner = Runner(model=model) - -start = time() -traj = runner.run(t_1=timeinterval, dt=timestep) -runtime = dt.timedelta(seconds=(time() - start)) -print("runtime: {runtime}".format(**locals())) - - -t = np.array(traj['t']) -print("max. time step", (t[1:]-t[:-1]).max()) - -individuals_opinions = np.array([traj[M.Individual.opinion][ind] - for ind in individuals]) - -nopinion1_list = np.sum(individuals_opinions, axis=0) / nindividuals -nopinion0_list = 1 - nopinion1_list - -# everything below is just plotting commands for plotly - -data_opinion0 = go.Scatter( - x=t, - y=nopinion0_list, - mode="lines", - name="relative amount opinion 0", - line=dict( - color="lightblue", - width=2 - ) -) -data_opinion1 = go.Scatter( - x=t, - y=nopinion1_list, - mode="lines", - name="relative amount opinion 1", - line=dict( - color="orange", - width=2 - ) -) -data_majority_opinion = go.Scatter( - x=t, - y=traj[M.SocialSystem.opinion][social_system], - mode="lines+markers", - name="majority opinion", - line=dict( - color="red", - width=2 - ), - marker=dict( - color="red", - size=4 - ) -) - -layout = dict(title='Adaptive Voter Model', - xaxis=dict(title='time'), - ) - -fig = dict(data=[data_opinion0, data_opinion1, data_majority_opinion], layout=layout) -py.plot(fig, filename="adaptive-voter-model.html") diff --git a/studies/run_carbon_voters_anderies.py b/studies/run_carbon_voters_anderies.py deleted file mode 100755 index 96d5c60e..00000000 --- a/studies/run_carbon_voters_anderies.py +++ /dev/null @@ -1,211 +0,0 @@ -"""Skript to run Carbon Voters model.""" - -# This file is part of pycopancore. -# -# Copyright (C) 2016-2017 by COPAN team at Potsdam Institute for Climate -# Impact Research -# -# URL: -# Contact: core@pik-potsdam.de -# License: BSD 2-clause license - -from time import time -import datetime as dt -# from numpy import random -import random -# import networkx as nx -import numpy as np -# import sys -import pycopancore.models.carbon_voters_anderies_model as M -# import pycopancore.models.only_copan_global_like_carbon_cycle as M -from pycopancore import master_data_model as D -from pycopancore.runners import Runner - -# import plotly.plotly as py -import plotly.offline as py -import plotly.graph_objs as go - -# first thing: set seed so that each execution must return same thing: -random.seed(1) -# TODO: figure out why it doesn't seem to work here ... - -# parameters: -timeinterval = 60 -timestep = 1 -expected_degree = 10 -nindividuals = 400 -rewiring_probability = 0.1 -possible_opinions = list(range(2)) -impact_scaling_factor=20 -no_impact_opinion_change=0.5 -no_impact_atmospheric_carbon_level=0.2 - -# use fast method and with multple updates -M.avof.Culture.configure( - update_mode=M.avof.Culture.update_modes.fast, - synchronous_updates=100 -) - -# instantiate model -model = M.Model() - - -# instantiate process taxa: -culture = M.Culture( - timestep=timestep, - rewiring=rewiring_probability, impact_scaling_factor=impact_scaling_factor, - no_impact_opinion_change=no_impact_opinion_change, - no_impact_atmospheric_carbon_level=no_impact_atmospheric_carbon_level -) -environment = M.Environment() - -# generate entities and distribute opinions uniformly randomly: -world = M.World(culture=culture, environment=environment, - atmospheric_carbon=0.2 * D.gigatonnes_carbon, - ocean_carbon=0.6 * D.gigatonnes_carbon - ) -social_system = M.SocialSystem(world=world) -cell = M.Cell(world=world, social_system=social_system) -individuals = [M.Individual(cell=cell, - initial_opinion=float(np.random.choice(possible_opinions, 1, p=[0.6,0.4]))) - for _ in range(nindividuals)] # individual opinion 0 with prob. p1, 1(aware) with prob. p2 - -# set initial values -Sigma0 = 1.5e8 * D.square_kilometers -cell.land_area = Sigma0 -# print(M.Cell.land_area.get_values(cells)) - -L0 = 0.2 * D.gigatonnes_carbon # 2480 is yr 2000 -cell.terrestrial_carbon = L0 -# print(M.Cell.terrestrial_carbon.get_values(cells)) - -G0 = 0.5 * D.gigatonnes_carbon # 1125 is yr 2000 -cell.fossil_carbon = G0 - -# TODO: ask Jobst, why are all individuals already in the network? - - -def erdosrenyify(graph, p=0.5): - """Create a ErdosRenzi graph from networkx graph. - - Take a a networkx.Graph with nodes and distribute the edges following the - erdos-renyi graph procedure. - """ - assert not graph.edges(), "your graph has already edges" - nodes = list(graph.nodes()) - for i, n1 in enumerate(nodes[:-1]): - for n2 in nodes[i+1:]: - if random.random() < p: - graph.add_edge(n1, n2) - - -# set the initial graph structure to be an erdos-renyi graph -print("erdosrenyifying the graph ... ", end="", flush=True) -start = time() -erdosrenyify(culture.acquaintance_network, p=expected_degree / nindividuals) -print("done ({})".format(dt.timedelta(seconds=(time() - start)))) - -runner = Runner(model=model) - -start = time() -traj = runner.run(t_1=timeinterval, dt=timestep) -runtime = dt.timedelta(seconds=(time() - start)) -print("runtime: {runtime}".format(**locals())) - - -t = np.array(traj['t']) -print("max. time step", (t[1:]-t[:-1]).max()) - -individuals_opinions = np.array([traj[M.Individual.opinion][ind] - for ind in individuals]) - -nopinion1_list = np.sum(individuals_opinions, axis=0) / nindividuals -nopinion0_list = 1 - nopinion1_list - -# everything below is just plotting commands for plotly - -data_opinion0 = go.Scatter( - x=t, - y=nopinion0_list, - mode="lines", - name="relative amount opinion 0", - line=dict( - color="lightblue", - width=2 - ) -) -data_opinion1 = go.Scatter( - x=t, - y=nopinion1_list, - mode="lines", - name="relative amount opinion 1", - line=dict( - color="orange", - width=2 - ) -) -# majority opinion -data_majority_opinion = go.Scatter( - x=t, - y=traj[M.SocialSystem.opinion][social_system], - mode="lines+markers", - name="majority opinion", - line=dict( - color="red", - width=2 - ), - marker=dict( - color="red", - size=4 - ) -) -# carbon -data_ca = go.Scatter( - x=t, - y=traj[M.World.atmospheric_carbon][world], - mode="lines", - name="atmospheric carbon", - line=dict( - color="lightblue", - width=4 - ) -) -data_ct = go.Scatter( - x=t, - y=traj[M.World.terrestrial_carbon][world], - mode="lines", - name="terrestrial carbon", - line=dict( - color="green", - width=4 - ) -) -data_cm = go.Scatter( - x=t, - y=traj[M.World.ocean_carbon][world], - mode="lines", - name="maritime carbon", - line=dict( - color="blue", - width=4 - ) -) -data_cf = go.Scatter( - x=t, - y=traj[M.World.fossil_carbon][world], - mode="lines", - name="fossil carbon", - line=dict( - color="gray", - width=4 - ) -) - -layout = dict(title='Adaptive Voter Model and Anderies Carbon Cycle', - xaxis=dict(title='time'), - yaxis=dict(title='relative opinion and carbon amounts'), - ) - -fig = dict(data=[data_opinion0, data_opinion1, data_majority_opinion, - data_ca, data_cf, data_cm, data_ct], layout=layout) -py.plot(fig, filename="adaptive-voter-model.html") diff --git a/studies/run_example1.py b/studies/run_example1.py deleted file mode 100755 index 1b3b4316..00000000 --- a/studies/run_example1.py +++ /dev/null @@ -1,231 +0,0 @@ -"""Script to run example1 model.""" - -from time import time -from numpy import random, array -import numpy as np - -import pycopancore.models.example1 as M -from pycopancore import master_data_model as D -from pycopancore.runners import Runner -import pycopancore as pcc - -from pylab import plot, gca, show, figure, subplot, gca, semilogy, legend - -from numba.errors import NumbaDeprecationWarning, NumbaPendingDeprecationWarning -import warnings -warnings.simplefilter('ignore', category=NumbaDeprecationWarning) -warnings.simplefilter('ignore', category=NumbaPendingDeprecationWarning) - -# first thing: set seed so that each execution must return same thing: -pcc.set_seed(10) - -# parameters: - -nworlds = 1 # no. worlds -nsocs = 5 # no. social_systems -ncells = 100 # no. cells -ninds = 1000 # no. individuals - -t_1 = 2120 - -# choose one of two scenarios: -with_social = 1 # 0 or 1 - -# directory to store results: -dir = "/tmp/"; - -if with_social: - filename = dir + "with_social.pickle" - with_migration = 1 - with_awareness = 1 - with_learning = 1 - with_voting = 1 -else: - filename = dir + "without_social.pickle" - with_migration = 0 - with_awareness = 0 - with_learning = 0 - with_voting = 0 -with_spillovers = 1 - -print("Using model as defined in file", M.__file__) -model = M.Model() -runner = Runner(model=model) - -# instantiate process taxa: -environment = M.Environment() -metabolism = M.Metabolism( - renewable_energy_knowledge_spillover_fraction = - .1 if with_spillovers else 0, - basic_emigration_probability_rate = - 16e-13 if with_migration else 0, # leads to ca. 5mio. at 5 socs, (real) - ) -culture = M.Culture( - awareness_lower_carbon_density=1e-4, - awareness_upper_carbon_density=2e-4, - awareness_update_rate = 10 if with_awareness else 0, - environmental_friendliness_learning_rate = 1 if with_learning else 0, - max_protected_terrestrial_carbon_share=0, - terrestrial_carbon_averaging_time=10, - ) - -# generate entities and plug them together at random: -worlds = [M.World(environment=environment, - metabolism=metabolism, - culture=culture, - atmospheric_carbon = 830 * D.gigatonnes_carbon, - upper_ocean_carbon = (5500 - 830 - 2480 - 1125) * D.GtC - ) for w in range(nworlds)] -social_systems = [M.SocialSystem( - world=random.choice(worlds), - has_renewable_subsidy = random.choice([False, True], - p=[3/4, 1/4]), - has_emissions_tax = random.choice([False, True], - p=[4/5, 1/5]), - has_fossil_ban = False, - time_between_votes = 4 if with_voting else 1e100, - ) for s in range(nsocs)] -cells = [M.Cell(social_system=random.choice(social_systems)) - for c in range(ncells)] -individuals = [M.Individual( - cell=random.choice(cells), - is_environmentally_friendly = - random.choice([False, True], p=[.7, .3]), - ) - for i in range(ninds)] - -# initialize block model acquaintance network: -target_degree = 150 -target_degree_samecell = 0.5 * target_degree -target_degree_samesoc = 0.35 * target_degree -target_degree_other = 0.15 * target_degree -p_samecell = target_degree_samecell / (ninds/ncells - 1) -p_samesoc = target_degree_samesoc / (ninds/nsocs - ninds/ncells - 1) -p_other = target_degree_other / (ninds - ninds/nsocs - 1) -for index, i in enumerate(individuals): - for j in individuals[:index]: - if random.uniform() < ( - p_samecell if i.cell == j.cell - else p_samesoc if i.social_system == j.social_system \ - else p_other): - culture.acquaintance_network.add_edge(i, j) - -# set renewable sector productivities randomly: -rel_prod = 2 * random.uniform(size=ncells) -M.Cell.renewable_sector_productivity.set_values(cells, rel_prod * M.Cell.renewable_sector_productivity.default) - -# distribute area and vegetation randomly but correlatedly: -r = random.uniform(size=ncells) -Sigma0 = 1.5e8 * D.square_kilometers * r / sum(r) -M.Cell.land_area.set_values(cells, Sigma0) - -r += random.uniform(size=ncells) -L0 = 2480 * D.gigatonnes_carbon * r / sum(r) # 2480 is yr 2000 -M.Cell.terrestrial_carbon.set_values(cells, L0) -M.Cell.mean_past_terrestrial_carbon.set_values(cells, L0) - -r = np.exp(random.normal(size=ncells)) -G0 = 1125 * D.gigatonnes_carbon * r / sum(r) # 1125 is yr 2000 -M.Cell.fossil_carbon.set_values(cells, G0) - -r = random.uniform(size=nsocs) -P0 = 6e9 * D.people * r / sum(r) # 6e9 is yr 2000 -M.SocialSystem.population.set_values(social_systems, P0) -M.SocialSystem.migrant_population.set_values(social_systems, P0 * 250e6 / 6e9) -for s in social_systems: - s.max_protected_terrestrial_carbon = \ - 0.90 * sum(c.terrestrial_carbon for c in s.cells) - -r = random.uniform(size=nsocs) -K0 = sum(P0) * 1e4 * D.dollars/D.people * r / sum(r) # ? -M.SocialSystem.physical_capital.set_values(social_systems, K0) - -# for renewables, do NOT divide by number of socs: -r = random.uniform(size=nsocs) -S0 = 1e12 * D.gigajoules * r / r.mean() -M.SocialSystem.renewable_energy_knowledge.set_values(social_systems, S0) - -w = worlds[0] -s = social_systems[0] -c = cells[0] -for v in environment.variables: print(v,v.get_value(environment)) -for v in metabolism.variables: print(v,v.get_value(metabolism)) -for v in w.variables: print(v,v.get_value(w)) -for v in s.variables: print(v,v.get_value(s)) -for v in c.variables: print(v,v.get_value(c)) - -# do simulation: -start = time() -traj = runner.run(t_0=2000, t_1=t_1, dt=1, - add_to_output=[M.Individual.represented_population, - M.Cell.mean_past_terrestrial_carbon]) - -for v in environment.variables: print(v,v.get_value(environment)) -for v in metabolism.variables: print(v,v.get_value(metabolism)) -for v in w.variables: print(v,v.get_value(w)) -for v in s.variables: print(v,v.get_value(s)) -for v in c.variables: print(v,v.get_value(c)) - - -from pickle import dump -tosave = { - v.owning_class.__name__ + "." - + v.codename: {str(e): traj[v][e] - for e in traj[v].keys() - } - for v in traj.keys() if v is not "t" - } -tosave["t"] = traj["t"] -dump(tosave, open(filename,"wb")) -print(time()-start, " seconds") - -t = np.array(traj['t']) -print("max. time step", (t[1:]-t[:-1]).max()) - -exit() - -print("\nYr 2000 values (real):") -print("emigration (5e6):",sum(traj[M.SocialSystem.emigration][s][5] - for s in social_systems)) -print("photo (123):",sum(traj[M.Cell.photosynthesis_carbon_flow][c][5] - for c in cells)) -print("resp (118):",sum(traj[M.Cell.terrestrial_respiration_carbon_flow][c][5] - for c in cells)) -print("GWP (4e13):",sum(traj[M.SocialSystem.economic_output_flow][s][5] - for s in social_systems)) -B0 = sum(traj[M.SocialSystem.biomass_input_flow][s][5] - for s in social_systems) -Bglobal = B0 * D.gigatonnes_carbon / D.years -Fglobal = sum(traj[M.SocialSystem.fossil_fuel_input_flow][s][5] - for s in social_systems) * D.gigatonnes_carbon / D.years -Rglobal = sum(traj[M.SocialSystem.renewable_energy_input_flow][s][5] - for s in social_systems) * D.gigajoules / D.years -Eglobal = sum(traj[M.SocialSystem.secondary_energy_flow][s][5] - for s in social_systems) * D.gigajoules / D.years -print("B (3), F (11), R(100):", - Bglobal, Bglobal.tostr(unit=D.gigatonnes_carbon/D.years), - Fglobal, Fglobal.tostr(unit=D.gigatonnes_carbon/D.years), - Rglobal, Rglobal.tostr(unit=D.gigawatts), - ) -print("life exp. at end:", 1/np.mean([traj[M.SocialSystem.mortality][s][-1] - for s in social_systems])) -print("cap. deprec. at begin (0.1?):", - np.mean([traj[M.SocialSystem.physical_capital_depreciation_rate][s][5] - for s in social_systems])) -print("cap. deprec. at end (0.1?):", - np.mean([traj[M.SocialSystem.physical_capital_depreciation_rate][s][-1] - for s in social_systems])) -print("deaths at begin (>250000?):", sum(traj[M.SocialSystem.deaths][s][5] - for s in social_systems)) -print("deaths at end (>250000?):", sum(traj[M.SocialSystem.deaths][s][-1] - for s in social_systems)) -print("temp. at begin:", traj[M.World.surface_air_temperature][worlds[0]][5]) -print("temp. at end:", traj[M.World.surface_air_temperature][worlds[0]][-1]) -print("prot. carbon share:", - [traj[M.SocialSystem.protected_terrestrial_carbon][s][-1] - / sum(traj[M.Cell.terrestrial_carbon][c][-1] - for c in s.cells) for s in social_systems]) -print(traj[M.World.terrestrial_carbon][worlds[0]][-1], - sum(traj[M.Cell.terrestrial_carbon][c][-1] for c in worlds[0].cells)) - - diff --git a/studies/run_example2.py b/studies/run_example2.py deleted file mode 100755 index af0219cd..00000000 --- a/studies/run_example2.py +++ /dev/null @@ -1,211 +0,0 @@ -"""Script to run example2 model.""" - -from time import time -from numpy import random, array -import numpy as np - -import pycopancore.models.example2 as M -from pycopancore import master_data_model as D -from pycopancore.runners import Runner - -from pylab import plot, gca, show, figure, subplot, gca, semilogy, legend - -# first thing: set seed so that each execution must return same thing: -random.seed(10) - -# parameters: - -nworlds = 1 # no. worlds -nsocs = 2 # no. social_systems -ncells = 4 # no. cells -ninds = 400 # no. individuals - -t_1 = 2100 -dir = "/tmp/" -# choose one of two scenarios: -filename = "with.pickle" -#filename = "without.pickle" -# (these files will be read by plot_example1.py) - -if filename == "with.pickle": - with_awareness = 1 - with_learning = 1 - with_voting = 1 -else: - with_awareness = 0 - with_learning = 0 - with_voting = 0 - -model = M.Model() - -# instantiate process taxa: - -environment = M.Environment() - -metabolism = M.Metabolism( - renewable_energy_knowledge_spillover_fraction = 0 - ) - -culture = M.Culture( - awareness_lower_carbon_density=1e-5, - awareness_upper_carbon_density=4e-5, - awareness_update_rate = 1 if with_awareness else 0, - environmental_friendliness_learning_rate = 1 if with_learning else 0, - ) - -# generate entities and plug them together: - -(world, ) = worlds = [M.World( - environment = environment, - metabolism = metabolism, - culture = culture, - atmospheric_carbon = 830 * D.gigatonnes_carbon, - upper_ocean_carbon = (5500 - 830 - 2480 - 1125) * D.GtC - ) for w in range(nworlds)] - -(north, south) = social_systems = [M.SocialSystem( - world = world, - has_renewable_subsidy = False, - has_emissions_tax = False, - has_fossil_ban = False, - emissions_tax_intro_threshold = 0.5, # disabled - renewable_subsidy_intro_threshold = 1, # disabled - fossil_ban_intro_threshold = 1, # disabled - emissions_tax_level = 30 * 200e9, # see Wikipedia social cost of carbon. 100e9*3.5, - time_between_votes = 4 if with_voting else 1e100, - ) for s in range(nsocs)] - -(boreal, temperate, subtropical, tropical) = cells = [M.Cell( - social_system = social_systems[c//2], - renewable_sector_productivity = [.7, .9, 1.1, 1.3][c] - * 2000 * M.Cell.renewable_sector_productivity.default, - # represents dependency of solar energy on solar insolation angle - fossil_sector_productivity = M.Cell.fossil_sector_productivity.default * 7, - biomass_sector_productivity = M.Cell.biomass_sector_productivity.default * 5 - # these values result in realistic total energy production for the year 2000, see below - ) for c in range(ncells)] - -individuals = [M.Individual( - cell = cells[i%4], - is_environmentally_friendly = - random.choice([False, True], p=[.8, .2]), # represents the "20% suffice" assumption - ) - for i in range(ninds)] - -# initialize block model acquaintance network: -target_degree = 10 # = 2.5% of all agents. Dunbar's number would be too large -target_degree_samecell = 0.5 * target_degree -target_degree_samesoc = 0.35 * target_degree -target_degree_other = 0.15 * target_degree -p_samecell = target_degree_samecell / (ninds/ncells - 1) -p_samesoc = target_degree_samesoc / (ninds/nsocs - ninds/ncells - 1) -p_other = target_degree_other / (ninds - ninds/nsocs - 1) -for index, i in enumerate(individuals): - for j in individuals[:index]: - if random.uniform() < ( - p_samecell if i.cell == j.cell - else p_samesoc if i.social_system == j.social_system \ - else p_other): - culture.acquaintance_network.add_edge(i, j) - -# distribute area and vegetation uniformly since it seems there are no real differences between the actual zones: -Sigma0 = 1.5e8 * D.square_kilometers * array([0.25, 0.25, .25, .36]) -M.Cell.land_area.set_values(cells, Sigma0) - -L0 = 2480 * D.gigatonnes_carbon * array([0.25, 0.25, .25, .25]) # 2480 is yr 2000 -M.Cell.terrestrial_carbon.set_values(cells, L0) -M.Cell.mean_past_terrestrial_carbon.set_values(cells, L0) - -# distribute fossils linearly from north to south: -G0 = 1125 * D.gigatonnes_carbon * array([.4, .3, .2, .1]) # 1125 is yr 2000 -M.Cell.fossil_carbon.set_values(cells, G0) - -# distribute population 1:3 between north and south, and 2:3 within each: -r = random.uniform(size=nsocs) -P0 = 6e9 * D.people * array([0.1, 0.15, 0.3, 0.45]) # 6e9 is yr 2000 -M.SocialSystem.population.set_values(social_systems, P0) - -# distribute capital 2:1: -K0 = sum(P0) * 1e4 * D.dollars/D.people * array([2/3, 1/3]) -M.SocialSystem.physical_capital.set_values(social_systems, K0) - -S0 = 1e12 * D.gigajoules * array([1, 1]) -M.SocialSystem.renewable_energy_knowledge.set_values(social_systems, S0) - -w = worlds[0] -s = social_systems[0] -c = cells[0] -for v in environment.variables: print(v,v.get_value(environment)) -for v in metabolism.variables: print(v,v.get_value(metabolism)) -for v in w.variables: print(v,v.get_value(w)) -for v in s.variables: print(v,v.get_value(s)) -for v in c.variables: print(v,v.get_value(c)) - - -# do simulation: -runner = Runner(model=model) -start = time() -traj = runner.run(t_0=2000, t_1=t_1, dt=1, - add_to_output=[ - M.Individual.represented_population, - M.Cell.mean_past_terrestrial_carbon, - M.SocialSystem.population - ]) - - -for v in environment.variables: print(v,v.get_value(environment)) -for v in metabolism.variables: print(v,v.get_value(metabolism)) -for v in w.variables: print(v,v.get_value(w)) -for v in s.variables: print(v,v.get_value(s)) -for v in c.variables: print(v,v.get_value(c)) - - -from pickle import dump -tosave = { - v.owning_class.__name__ + "." - + v.codename: {str(e): traj[v][e] - for e in traj[v].keys() - } - for v in traj.keys() if v is not "t" - } -tosave["t"] = traj["t"] -dump(tosave, open(dir+filename,"wb")) -print(time()-start, " seconds") - -t = np.array(traj['t']) -print("max. time step", (t[1:]-t[:-1]).max()) - -print("\nyr 2000 values (real):") -print("photo (123):",sum(traj[M.Cell.photosynthesis_carbon_flow][c][5] - for c in cells)) -print("resp (118):",sum(traj[M.Cell.terrestrial_respiration_carbon_flow][c][5] - for c in cells)) -print("GWP (4e13):",sum(traj[M.SocialSystem.economic_output_flow][s][5] - for s in social_systems)) -B0 = sum(traj[M.SocialSystem.biomass_input_flow][s][5] - for s in social_systems) -Bglobal = B0 * D.gigatonnes_carbon / D.years -Fglobal = sum(traj[M.SocialSystem.fossil_fuel_input_flow][s][5] - for s in social_systems) * D.gigatonnes_carbon / D.years -Rglobal = sum(traj[M.SocialSystem.renewable_energy_input_flow][s][5] - for s in social_systems) * D.gigajoules / D.years -Eglobal = sum(traj[M.SocialSystem.secondary_energy_flow][s][5] - for s in social_systems) * D.gigajoules / D.years -print("B (3), F (11), R(100):", - Bglobal, Bglobal.tostr(unit=D.gigatonnes_carbon/D.years), - Fglobal, Fglobal.tostr(unit=D.gigatonnes_carbon/D.years), - Rglobal, Rglobal.tostr(unit=D.gigawatts), - ) -print("cap. deprec. at begin (0.1?):", - np.mean([traj[M.SocialSystem.physical_capital_depreciation_rate][s][5] - for s in social_systems])) -print("cap. deprec. at end (0.1?):", - np.mean([traj[M.SocialSystem.physical_capital_depreciation_rate][s][-1] - for s in social_systems])) -print("temp. at begin:", traj[M.World.surface_air_temperature][worlds[0]][5]) -print("temp. at end:", traj[M.World.surface_air_temperature][worlds[0]][-1]) -print("has emissions tax at begin", traj[M.SocialSystem.has_emissions_tax][north][5]) -print("has emissions tax at end", traj[M.SocialSystem.has_emissions_tax][north][-1]) -print("biomass prod. at begin", traj[M.Cell.biomass_relative_productivity][boreal][5] / traj[M.Cell.terrestrial_carbon][boreal][5]**2) -print("biomass prod. at end", traj[M.Cell.biomass_relative_productivity][boreal][-1] / traj[M.Cell.terrestrial_carbon][boreal][-1]**2) - diff --git a/studies/run_example2_mw.py b/studies/run_example2_mw.py deleted file mode 100755 index a5c2dd2e..00000000 --- a/studies/run_example2_mw.py +++ /dev/null @@ -1,229 +0,0 @@ -"""Script to run example2 model.""" - -from time import time -from numpy import random, array -import numpy as np - -import pycopancore.models.example2 as M -from pycopancore import master_data_model as D -from pycopancore.runners import Runner - -from pylab import plot, gca, show, figure, subplot, gca, semilogy, legend - -# first thing: set seed so that each execution must return same thing: -random.seed(10) - -# parameters: - -p_env_friendly = 0.9 -with_social = True - -nworlds = 1 # no. worlds -nsocs = 2 # no. social_systems -ncells = 4 # no. cells -ninds = 400 # no. individuals - -t_1 = 2120 - -# choose one of two scenarios: -#filename = "/home/jobst/work/without.pickle" -# (these files will be read by plot_example1.py) - -if with_social: - filename = "core_with_social_p_{0}.p".format(p_env_friendly) - with_awareness = 1 - with_learning = 1 - with_voting = 1 -else: - filename = "core_without_social_p_{0}.p".format(p_env_friendly) - with_awareness = 0 - with_learning = 0 - with_voting = 0 - -model = M.Model() - -# instantiate process taxa: - -environment = M.Environment() - -metabolism = M.Metabolism( - renewable_energy_knowledge_spillover_fraction = 0 - ) - -culture = M.Culture( - awareness_lower_carbon_density=1e-5, - awareness_upper_carbon_density=4e-5, - awareness_update_rate = 1 if with_awareness else 0, - environmental_friendliness_learning_rate = 1 if with_learning else 0, - ) - -# generate entities and plug them together: - -(world, ) = worlds = [M.World( - environment = environment, - metabolism = metabolism, - culture = culture, - atmospheric_carbon = 830 * D.gigatonnes_carbon, - upper_ocean_carbon = (5500 - 830 - 2480 - 1125) * D.GtC - ) for w in range(nworlds)] - -(north, south) = social_systems = [M.SocialSystem( - world = world, - has_renewable_subsidy = False, - has_emissions_tax = False, - has_fossil_ban = False, - emissions_tax_intro_threshold = 1, # disabled - renewable_subsidy_intro_threshold = 0.5, # disabled - fossil_ban_intro_threshold = 0.5, # disabled - emissions_tax_level = 20 * 200e9, # see Wikipedia social cost of carbon. 100e9*3.5, - time_between_votes = 4 if with_voting else 1e100, - ) for s in range(nsocs)] - -(boreal, temperate, subtropical, tropical) = cells = [M.Cell( - social_system = social_systems[c//2], - renewable_sector_productivity = [.7, .9, 1.1, 1.3][c] - * 100000 * M.Cell.renewable_sector_productivity.default, - # represents dependency of solar energy on solar insolation angle - fossil_sector_productivity = M.Cell.fossil_sector_productivity.default *280, - #biomass_sector_productivity = M.Cell.biomass_sector_productivity.default * 5 - biomass_sector_productivity=3e5*10**(0.4)*900, - # these values result in realistic total energy production for the year 2000, see below - ) for c in range(ncells)] - -individuals = [M.Individual( - cell = cells[i%4], - is_environmentally_friendly = - random.choice([False, True], p=[1-p_env_friendly, - p_env_friendly]), # represents the "20% suffice" assumption - ) - for i in range(ninds)] - -# initialize block model acquaintance network: -target_degree = 10 # = 2.5% of all agents. Dunbar's number would be too large -target_degree_samecell = 0.5 * target_degree -target_degree_samesoc = 0.35 * target_degree -target_degree_other = 0.15 * target_degree -p_samecell = target_degree_samecell / (ninds/ncells - 1) -p_samesoc = target_degree_samesoc / (ninds/nsocs - ninds/ncells - 1) -p_other = target_degree_other / (ninds - ninds/nsocs - 1) -for index, i in enumerate(individuals): - for j in individuals[:index]: - if random.uniform() < ( - p_samecell if i.cell == j.cell - else p_samesoc if i.social_system == j.social_system \ - else p_other): - culture.acquaintance_network.add_edge(i, j) - -# distribute area and vegetation uniformly since it seems there are no real differences between the actual zones: -Sigma0 = 1.5e8 * D.square_kilometers * array([0.25, 0.25, .25, .36]) -M.Cell.land_area.set_values(cells, Sigma0) - -L0 = 2480 * D.gigatonnes_carbon * array([0.25, 0.25, .25, .25]) # 2480 is yr 2000 -M.Cell.terrestrial_carbon.set_values(cells, L0) - -# distribute fossils linearly from north to south: -G0 = 1125 * D.gigatonnes_carbon * array([.4, .3, .2, .1]) # 1125 is yr 2000 -M.Cell.fossil_carbon.set_values(cells, G0) - -# distribute population 1:3 between north and south, and 2:3 within each: -r = random.uniform(size=nsocs) -P0 = 6e9 * D.people * array([0.1, 0.15, 0.3, 0.45]) # 6e9 is yr 2000 -M.SocialSystem.population.set_values(social_systems, P0) - -# distribute capital 2:1: -K0 = sum(P0) * 1e4 * D.dollars/D.people * array([2/3, 1/3]) -M.SocialSystem.physical_capital.set_values(social_systems, K0) - -S0 = 1e12 * D.gigajoules * array([1, 1]) -M.SocialSystem.renewable_energy_knowledge.set_values(social_systems, S0) - -w = worlds[0] -s = social_systems[0] -c = cells[0] -for v in environment.variables: print(v,v.get_value(environment)) -for v in metabolism.variables: print(v,v.get_value(metabolism)) -for v in w.variables: print(v,v.get_value(w)) -for v in s.variables: print(v,v.get_value(s)) -for v in c.variables: print(v,v.get_value(c)) - - -# do simulation: -runner = Runner(model=model) -start = time() -traj = runner.run(t_0=2000, t_1=t_1, dt=1, - add_to_output=[M.Individual.represented_population]) - - -for v in environment.variables: print(v,v.get_value(environment)) -for v in metabolism.variables: print(v,v.get_value(metabolism)) -for v in w.variables: print(v,v.get_value(w)) -for v in s.variables: print(v,v.get_value(s)) -for v in c.variables: print(v,v.get_value(c)) - - -from pickle import dump -tosave = { - v.owning_class.__name__ + "." - + v.codename: {str(e): traj[v][e] - for e in traj[v].keys() - } - for v in traj.keys() if v is not "t" - } -tosave["t"] = traj["t"] -dump(tosave, open(filename,"wb")) -print(time()-start, " seconds") - -t = np.array(traj['t']) -print("max. time step", (t[1:]-t[:-1]).max()) - -print("\nyr 2000 values (real):") -print("photo (123):",sum(traj[M.Cell.photosynthesis_carbon_flow][c][5] - for c in cells)) -print("resp (118):",sum(traj[M.Cell.terrestrial_respiration_carbon_flow][c][5] - for c in cells)) -print("GWP (4e13):",sum(traj[M.SocialSystem.economic_output_flow][s][5] - for s in social_systems)) -B0 = sum(traj[M.SocialSystem.biomass_input_flow][s][5] - for s in social_systems) -Bglobal = B0 * D.gigatonnes_carbon / D.years -Fglobal = sum(traj[M.SocialSystem.fossil_fuel_input_flow][s][5] - for s in social_systems) * D.gigatonnes_carbon / D.years -Rglobal = sum(traj[M.SocialSystem.renewable_energy_input_flow][s][5] - for s in social_systems) * D.gigajoules / D.years -Eglobal = sum(traj[M.SocialSystem.secondary_energy_flow][s][5] - for s in social_systems) * D.gigajoules / D.years -print("B (3), F (11), R(100):", - Bglobal, Bglobal.tostr(unit=D.gigatonnes_carbon/D.years), - Fglobal, Fglobal.tostr(unit=D.gigatonnes_carbon/D.years), - Rglobal, Rglobal.tostr(unit=D.gigawatts), - ) - -B0 = sum(traj[M.SocialSystem.biomass_input_flow][s][-1] - for s in social_systems) -Bglobal = B0 * D.gigatonnes_carbon / D.years -Fglobal = sum(traj[M.SocialSystem.fossil_fuel_input_flow][s][-1] - for s in social_systems) * D.gigatonnes_carbon / D.years -Rglobal = sum(traj[M.SocialSystem.renewable_energy_input_flow][s][-1] - for s in social_systems) * D.gigajoules / D.years -Eglobal = sum(traj[M.SocialSystem.secondary_energy_flow][s][-1] - for s in social_systems) * D.gigajoules / D.years -print("B (3), F (11), R(100):", - Bglobal, Bglobal.tostr(unit=D.gigatonnes_carbon/D.years), - Fglobal, Fglobal.tostr(unit=D.gigatonnes_carbon/D.years), - Rglobal, Rglobal.tostr(unit=D.gigawatts), - ) - - -print("cap. deprec. at begin (0.1?):", - np.mean([traj[M.SocialSystem.physical_capital_depreciation_rate][s][5] - for s in social_systems])) -print("cap. deprec. at end (0.1?):", - np.mean([traj[M.SocialSystem.physical_capital_depreciation_rate][s][-1] - for s in social_systems])) -print("temp. at begin:", traj[M.World.surface_air_temperature][worlds[0]][5]) -print("temp. at end:", traj[M.World.surface_air_temperature][worlds[0]][-1]) -print("has emissions tax at begin", traj[M.SocialSystem.has_emissions_tax][north][5]) -print("has emissions tax at end", traj[M.SocialSystem.has_emissions_tax][north][-1]) -print("biomass prod. at begin", traj[M.Cell.biomass_relative_productivity][boreal][5] / traj[M.Cell.terrestrial_carbon][boreal][5]**2) -print("biomass prod. at end", traj[M.Cell.biomass_relative_productivity][boreal][-1] / traj[M.Cell.terrestrial_carbon][boreal][-1]**2) - diff --git a/studies/run_example2_varying_learning_rate.py b/studies/run_example2_varying_learning_rate.py deleted file mode 100644 index 98425186..00000000 --- a/studies/run_example2_varying_learning_rate.py +++ /dev/null @@ -1,258 +0,0 @@ -"""Script to run example2 model.""" - -from time import time -from numpy import random, array -import numpy as np - -import pycopancore.models.example2 as M -from pycopancore import master_data_model as D -from pycopancore.runners import Runner - -from pylab import plot, gca, show, figure, subplot, gca, semilogy, legend -import argparse -import os - -parser = argparse.ArgumentParser() -parser.add_argument('-i','--task-id', required=True, type=int) -parser.add_argument('-s','--seed', required=True, type=int) -args = vars(parser.parse_args()) - -seed = args["seed"] -task = args["task_id"] - -random.seed(seed) - -p_env_friendly = 0.40 #0.25 -updates = np.logspace(np.log10(1/50), np.log10(12), 50)[task] -with_social = True -t_1 = 2120 - -# parameters: - -#This is going in the right direction -#S0 = 2e11 * D.gigajoules * array([1, 1]) -#renewable_scaling = 2500000 - -#1e12 collapse -#5e11 collapse -#2.5e11 almost collapse -#4e11 scaling 600000, 98 W collapse -#3e11 scaling 1100000 101.91 GW almost collapse -S0 = 2e11 * D.gigajoules * array([1, 1]) -renewable_scaling = 2500000 - - -nworlds = 1 # no. worlds -nsocs = 2 # no. social_systems -ncells = 4 # no. cells -ninds = 400 # no. individuals - - -# choose one of two scenarios: -#filename = "/home/jobst/work/without.pickle" -# (these files will be read by plot_example1.py) - -if with_social: - filename = "core_with_social_u_{0}_loweredS0_{1}.p".format(updates,seed) - with_awareness = 1 - with_learning = 1 - with_voting = 1 -else: - filename = "core_without_social_u_{0}_loweredS0_{1}.p".format(updates, seed) - with_awareness = 0 - with_learning = 0 - with_voting = 0 - -model = M.Model() - -# instantiate process taxa: - -environment = M.Environment() - -metabolism = M.Metabolism( - renewable_energy_knowledge_spillover_fraction = 0 - ) - -culture = M.Culture( - awareness_lower_carbon_density=1e-5, - awareness_upper_carbon_density=4e-5, - awareness_update_rate = updates if with_awareness else 0, - environmental_friendliness_learning_rate = updates if with_learning else 0, - ) - -# generate entities and plug them together: - -(world, ) = worlds = [M.World( - environment = environment, - metabolism = metabolism, - culture = culture, - atmospheric_carbon = 830 * D.gigatonnes_carbon, - upper_ocean_carbon = (5500 - 830 - 2480 - 1125) * D.GtC - ) for w in range(nworlds)] - -(north, south) = social_systems = [M.SocialSystem( - world = world, - has_renewable_subsidy = False, - has_emissions_tax = False, - has_fossil_ban = False, - emissions_tax_intro_threshold = 1, # disabled - renewable_subsidy_intro_threshold = 0.5, # disabled - fossil_ban_intro_threshold = 0.5, # disabled - renewable_subsidy_keeping_threshold = 0.5, - fossil_ban_keeping_threshold = 0.5, - emissions_tax_level = 20 * 200e9, # see Wikipedia social cost of carbon. 100e9*3.5, - time_between_votes = 4 if with_voting else 1e100, - ) for s in range(nsocs)] - -# renewable_scaling = 100000 -(boreal, temperate, subtropical, tropical) = cells = [M.Cell( - social_system = social_systems[c//2], - renewable_sector_productivity = [.7, .9, 1.1, 1.3][c] - * renewable_scaling * M.Cell.renewable_sector_productivity.default, - # represents dependency of solar energy on solar insolation angle - fossil_sector_productivity = M.Cell.fossil_sector_productivity.default *280, - #biomass_sector_productivity = M.Cell.biomass_sector_productivity.default * 5 - biomass_sector_productivity=3e5*10**(0.4)*900, - # these values result in realistic total energy production for the year 2000, see below - ) for c in range(ncells)] - -individuals = [M.Individual( - cell = cells[i%4], - is_environmentally_friendly = - random.choice([False, True], p=[1-p_env_friendly, - p_env_friendly]), # represents the "20% suffice" assumption - ) - for i in range(ninds)] - -# initialize block model acquaintance network: -target_degree = 10 # = 2.5% of all agents. Dunbar's number would be too large -target_degree_samecell = 0.5 * target_degree -target_degree_samesoc = 0.35 * target_degree -target_degree_other = 0.15 * target_degree -p_samecell = target_degree_samecell / (ninds/ncells - 1) -p_samesoc = target_degree_samesoc / (ninds/nsocs - ninds/ncells - 1) -p_other = target_degree_other / (ninds - ninds/nsocs - 1) -for index, i in enumerate(individuals): - for j in individuals[:index]: - if random.uniform() < ( - p_samecell if i.cell == j.cell - else p_samesoc if i.social_system == j.social_system \ - else p_other): - culture.acquaintance_network.add_edge(i, j) - -# distribute area and vegetation uniformly since it seems there are no real differences between the actual zones: -Sigma0 = 1.5e8 * D.square_kilometers * array([0.25, 0.25, .25, .25]) -M.Cell.land_area.set_values(cells, Sigma0) - -L0 = 2480 * D.gigatonnes_carbon * array([0.25, 0.25, .25, .25]) # 2480 is yr 2000 -M.Cell.terrestrial_carbon.set_values(cells, L0) - -# distribute fossils linearly from north to south: -G0 = 1125 * D.gigatonnes_carbon * array([.4, .3, .2, .1]) # 1125 is yr 2000 -M.Cell.fossil_carbon.set_values(cells, G0) - -# distribute population 1:3 between north and south, and 2:3 within each: -r = random.uniform(size=nsocs) -#P0 = 6e9 * D.people * array([0.1, 0.15, 0.3, 0.45]) # 6e9 is yr 2000 -P0 = 6e9 * D.people * array([0.25, 0.75]) # 6e9 is yr 2000 - -M.SocialSystem.population.set_values(social_systems, P0) - -# distribute capital 2:1: -K0 = sum(P0) * 1e4 * D.dollars/D.people * array([2/3, 1/3]) -M.SocialSystem.physical_capital.set_values(social_systems, K0) - -#S0 = 1e12 * D.gigajoules * array([1, 1]) -#S0 = 1e12 * D.gigajoules * array([1, 1]) -M.SocialSystem.renewable_energy_knowledge.set_values(social_systems, S0) - -w = worlds[0] -s = social_systems[0] -c = cells[0] -for v in environment.variables: print(v,v.get_value(environment)) -for v in metabolism.variables: print(v,v.get_value(metabolism)) -for v in w.variables: print(v,v.get_value(w)) -for v in s.variables: print(v,v.get_value(s)) -for v in c.variables: print(v,v.get_value(c)) - - -# do simulation: -runner = Runner(model=model) -start = time() -traj = runner.run(t_0=2000, t_1=t_1, dt=1, - add_to_output=[M.Individual.represented_population]) - - -for v in environment.variables: print(v,v.get_value(environment)) -for v in metabolism.variables: print(v,v.get_value(metabolism)) -for v in w.variables: print(v,v.get_value(w)) -for v in s.variables: print(v,v.get_value(s)) -for v in c.variables: print(v,v.get_value(c)) - - -from pickle import dump -tosave = { - v.owning_class.__name__ + "." - + v.codename: {str(e): traj[v][e] - for e in traj[v].keys() - } - for v in traj.keys() if v is not "t" - } -tosave["t"] = traj["t"] -dump(tosave, open(filename,"wb")) -print(time()-start, " seconds") - -t = np.array(traj['t']) -print("max. time step", (t[1:]-t[:-1]).max()) - -print("\nyr 2000 values (real):") -print("photo (123):",sum(traj[M.Cell.photosynthesis_carbon_flow][c][5] - for c in cells)) -print("resp (118):",sum(traj[M.Cell.terrestrial_respiration_carbon_flow][c][5] - for c in cells)) -print("GWP (4e13):",sum(traj[M.SocialSystem.economic_output_flow][s][5] - for s in social_systems)) -B0 = sum(traj[M.SocialSystem.biomass_input_flow][s][5] - for s in social_systems) -Bglobal = B0 * D.gigatonnes_carbon / D.years -Fglobal = sum(traj[M.SocialSystem.fossil_fuel_input_flow][s][5] - for s in social_systems) * D.gigatonnes_carbon / D.years -Rglobal = sum(traj[M.SocialSystem.renewable_energy_input_flow][s][5] - for s in social_systems) * D.gigajoules / D.years -Eglobal = sum(traj[M.SocialSystem.secondary_energy_flow][s][5] - for s in social_systems) * D.gigajoules / D.years -print("B (3), F (11), R(100):", - Bglobal, Bglobal.tostr(unit=D.gigatonnes_carbon/D.years), - Fglobal, Fglobal.tostr(unit=D.gigatonnes_carbon/D.years), - Rglobal, Rglobal.tostr(unit=D.gigawatts), - ) - -B0 = sum(traj[M.SocialSystem.biomass_input_flow][s][-1] - for s in social_systems) -Bglobal = B0 * D.gigatonnes_carbon / D.years -Fglobal = sum(traj[M.SocialSystem.fossil_fuel_input_flow][s][-1] - for s in social_systems) * D.gigatonnes_carbon / D.years -Rglobal = sum(traj[M.SocialSystem.renewable_energy_input_flow][s][-1] - for s in social_systems) * D.gigajoules / D.years -Eglobal = sum(traj[M.SocialSystem.secondary_energy_flow][s][-1] - for s in social_systems) * D.gigajoules / D.years -print("B (3), F (11), R(100):", - Bglobal, Bglobal.tostr(unit=D.gigatonnes_carbon/D.years), - Fglobal, Fglobal.tostr(unit=D.gigatonnes_carbon/D.years), - Rglobal, Rglobal.tostr(unit=D.gigawatts), - ) - - -print("cap. deprec. at begin (0.1?):", - np.mean([traj[M.SocialSystem.physical_capital_depreciation_rate][s][5] - for s in social_systems])) -print("cap. deprec. at end (0.1?):", - np.mean([traj[M.SocialSystem.physical_capital_depreciation_rate][s][-1] - for s in social_systems])) -print("temp. at begin:", traj[M.World.surface_air_temperature][worlds[0]][5]) -print("temp. at end:", traj[M.World.surface_air_temperature][worlds[0]][-1]) -print("has emissions tax at begin", traj[M.SocialSystem.has_emissions_tax][north][5]) -print("has emissions tax at end", traj[M.SocialSystem.has_emissions_tax][north][-1]) -print("biomass prod. at begin", traj[M.Cell.biomass_relative_productivity][boreal][5] / traj[M.Cell.terrestrial_carbon][boreal][5]**2) -print("biomass prod. at end", traj[M.Cell.biomass_relative_productivity][boreal][-1] / traj[M.Cell.terrestrial_carbon][boreal][-1]**2) - diff --git a/studies/run_exodus.py b/studies/run_exodus.py deleted file mode 100755 index 387a39cf..00000000 --- a/studies/run_exodus.py +++ /dev/null @@ -1,199 +0,0 @@ -"""This is the test exodus model. - -In this version only the Step-process 'aging' of entitytype 'Individual' is -implemented, such that the only relevant attributes of 'Individual' are 'age' -and 'cell'. -""" - -# This file is part of pycopancore. -# -# Copyright (C) 2016-2017 by COPAN team at Potsdam Institute for Climate -# Impact Research -# -# URL: -# Contact: core@pik-potsdam.de -# License: BSD 2-clause license - -import random -from scipy import stats -from time import time -import datetime as dt -import numpy as np -import networkx as nx -import pickle, json - -#import plotly.offline as py -#import plotly.graph_objs as go -from matplotlib.pyplot import plot, gca, show, savefig - -import pycopancore.models.exodus as M -from pycopancore.runners.runner import Runner - - -# setting timeinterval for run method 'Runner.run()' -timeinterval = 200 -# setting time step to hand to 'Runner.run()' -timestep = .1 - -nm = 1 # number of municipalities, also cities -nc = 1 # number of counties, also farmland_cells -na = 200 # number of agents -pf = .5 # percentage of farmers -nf = int(na * pf) # number of farmers -nt = int(na - nf) # number of townsmen - - -model = M.Model() - -# instantiate process taxa culture: -# In this certain case we need 'M.Culture()' for the acquaintance network. -culture = M.Culture(fully_connected_network=True) # fully connected -> static network -metabolism = M.Metabolism(market_frequency=1) - -# instantiate world: -world = M.World(culture=culture, metabolism=metabolism, - water_price=.1) -# Instantiate SocialSystems: -municipalities = [M.SocialSystem(world=world, - municipality_like=True, - base_mean_income=6130, - scaling_parameter=1.12, - migration_cost=0, - last_one_standing=False, - continuous_exploration=False) - for m in range(nm) - ] - -counties = [M.SocialSystem(world=world, - municipality_like=False, - migration_cost=0, - last_one_standing=False, - continuous_exploration=False) - for c in range(nc) - ] -# Instantiate farmland cells: -farmland_cells = [] -county_allocation = list(counties) -for fc in range(nc): - # chose county: - county = random.choice(county_allocation) - county_allocation.remove(county) - farmland_cells.append(M.Cell(world=world, - social_system=county, - characteristic='farmland', - land_area=0.0025 * (nf + nt) / nc, # in square kilometers - average_precipitation=0.75)) -# Instantiate city cells: -city_cells = [] -municipality_allocation = list(municipalities) - -for cc in range(nm): - # chose county: - municipality = random.choice(municipality_allocation) - municipality_allocation.remove(municipality) - city_cells.append(M.Cell(world=world, - social_system=municipality, - characteristic='city', - average_precipitation=0)) - -# Instantiate farmers: -farmers = [] -for f in range(nf): - # Chose cell - farmland = random.choice(farmland_cells) - # determine liquidity before first market: - liq = stats.lognorm.rvs(scale=300, s=0.34, loc=0) - farmers.append(M.Individual(cell=farmland, - profession='farmer', - outspokenness=3, - liquidity=liq, - nutrition=1000)) -# Instantiate townsmen: -townsmen = [] -for t in range(nt): - # Chose cell - city = random.choice(city_cells) - # determine liquidity before first market: - liq = stats.lognorm.rvs(scale=700, s=0.34, loc=0) - townsmen.append(M.Individual(cell=city, - profession='townsman', - outspokenness=3, - liquidity=liq, - nutrition=100)) - -start = time() -# Calculate social_systems variables before run: -print('calculating social_system attributes before run:') -for soc in M.SocialSystem.instances: - soc.calc_population(0) - soc.calculate_mean_income_or_farmsize(0) - soc.calculate_average_liquidity(0) -# Calculate other stuff: -for ind in M.Individual.instances: - ind.calc_farm_size() - ind.calc_gross_income() - ind.calculate_harvest(0) - ind.calculate_utility(0) -for soc in M.SocialSystem.instances: - soc.calculate_average_utility(0) - soc.calculate_gini(0) - soc.calculate_migration_rate(0) - -world.calc_total_gross_income(0) -world.calc_total_harvest(0) -world.calc_total_nutrition(0) -world.calc_total_liquidity(0) - -# Run market clearing once: -metabolism.do_market_clearing(0) - -print("done ({})".format(dt.timedelta(seconds=(time() - start)))) - -termination_conditions = [[M.Metabolism.check_for_market_equilibrium, metabolism], - [M.World.check_for_exceptions, world]] - -print('\n runner starting') -# Runner is instantiated -r = Runner(model=model, termination_calls=termination_conditions - ) - -start = time() -# run the Runner and saving the return dict in traj -traj = r.run(t_1=timeinterval, - dt=timestep, - max_resolution=True - ) -runtime = dt.timedelta(seconds=(time() - start)) -print('runtime: {runtime}'.format(**locals())) - - -# Saving: -print('saving:') -#traj.save(filename='data') -print('...is done') - -# Plotting: -t = np.array(traj['t']) -# for key, val in traj.items(): -# print('key', key,) -plot(t, traj[M.World.water_price][world], "b", lw=3) -#plot(t, traj[M.World.total_gross_income][world], "m:", lw=3) -#plot(t, traj[M.World.total_harvest][world], "m--", lw=3) -# plot(t, traj[M.Culture.network_clustering][culture], "r--", lw=3) -# plot(t, traj[M.Culture.modularity][culture], "r:", lw=3) - -for soc in municipalities: - plot(t, traj[M.SocialSystem.population][soc], "r", lw=3) - #plot(t, traj[M.SocialSystem.average_utility][soc], "r:", lw=3) - #plot(t, traj[M.SocialSystem.gini_coefficient][soc], "r--", lw=3) -for soc in counties: - plot(t, traj[M.SocialSystem.population][soc], "k", lw=3) - #plot(t, traj[M.SocialSystem.average_utility][soc], "k:", lw=3) - #plot(t, traj[M.SocialSystem.gini_coefficient][soc], "k--", lw=3) - -# for ind in M.Individual.instances: -# plot(t, traj[M.Individual.utility][ind], "y", lw=0.5) -gca().set_yscale('symlog') - -# savefig('20_ag_4_soc.png', dpi=150) -show() diff --git a/studies/run_exodus_oscillations.py b/studies/run_exodus_oscillations.py deleted file mode 100755 index b5defcb1..00000000 --- a/studies/run_exodus_oscillations.py +++ /dev/null @@ -1,218 +0,0 @@ -"""This is the test script for the seven dwarfs step by step tutorial. - -In this version only the Step-process 'aging' of entitytype 'Individual' is -implemented, such that the only relevant attributes of 'Individual' are 'age' -and 'cell'. -""" - -# This file is part of pycopancore. -# -# Copyright (C) 2016-2017 by COPAN team at Potsdam Institute for Climate -# Impact Research -# -# URL: -# Contact: core@pik-potsdam.de -# License: BSD 2-clause license - -import random -from scipy import stats -from time import time -import datetime as dt -import numpy as np -import networkx as nx -import pickle, json - -import plotly.offline as py -import plotly.graph_objs as go -from matplotlib.pyplot import plot, gca, show, savefig - -import pycopancore.models.exodus as M -from pycopancore.runners.runner import Runner - - -# setting timeinterval for run method 'Runner.run()' -timeinterval = 10 -# setting time step to hand to 'Runner.run()' -timestep = .1 - -# Since this is a special model, only 2 of each type of cells are allowed. -nm = 2 # number of municipalities, also cities -nc = 2 # number of counties, also farmland_cells -na = 100 # number of agents -pf = .5 # percentage of farmers -nf = int(na * pf) # number of farmers -nt = int(na - nf) # number of townsmen - - -model = M.Model() - -# instantiate process taxa culture: -# In this certain case we need 'M.Culture()' for the acquaintance network. -culture = M.Culture(fully_connected_network=True) -metabolism = M.Metabolism(market_frequency=1) - -# instantiate world: -world = M.World(culture=culture, metabolism=metabolism, - water_price=.1) -# Instantiate Social Systems: -municipalities = [M.SocialSystem(world=world, - municipality_like=True, - base_mean_income=1000, - scaling_parameter=1.12, - migration_cost=0) - for m in range(nm) - ] - -counties = [M.SocialSystem(world=world, - municipality_like=False, - migration_cost=0) - for c in range(nc) - ] -# Instantiate farmland cells: -farmland_cells = [] -farmland_cells.append(M.Cell(world=world, - social_system=counties[0], - characteristic='farmland', - land_area=0.01 * (nf + nt) / nc, - average_precipitation=0.75, - location=(0, 0))) -farmland_cells.append(M.Cell(world=world, - social_system=counties[1], - characteristic='farmland', - land_area=0.01 * (nf + nt) / nc, - average_precipitation=0.75, - location=(0, 1))) -# Instantiate city cells: -city_cells = [] -city_cells.append(M.Cell(world=world, - social_system=municipalities[0], - characteristic='city', - average_precipitation=0, - location=(1, 1))) -city_cells.append(M.Cell(world=world, - social_system=municipalities[1], - characteristic='city', - average_precipitation=0, - location=(1, 0))) - -# Instantiate farmers: -farmers = [] -for f in range(nf): - # Chose cell - farmland = random.choice(farmland_cells) - # determine liquidity before first market: - liq = stats.lognorm.rvs(scale=300, s=0.34, loc=0) - farmers.append(M.Individual(cell=farmland, - profession='farmer', - outspokenness=.1, - liquidity=liq, - nutrition=1000, - preferential_migration=True)) -# Instantiate townsmen: -townsmen = [] -for t in range(nt): - # Chose cell - city = random.choice(city_cells) - # determine liquidity before first market: - liq = stats.lognorm.rvs(scale=700, s=0.34, loc=0) - townsmen.append(M.Individual(cell=city, - profession='townsman', - outspokenness=.1, - liquidity=liq, - nutrition=100, - preferential_migration=True)) - -start = time() -# Calculate social_systems variables before run: -print('calculating social_system attributes before run:') -for soc in M.SocialSystem.instances: - soc.calc_population(0) - soc.calculate_mean_income_or_farmsize(0) - soc.calculate_average_liquidity(0) -# Calculate other stuff: -for ind in M.Individual.instances: - ind.calc_farm_size() - ind.calc_gross_income() - ind.calculate_harvest(0) - ind.calculate_utility(0) -for soc in M.SocialSystem.instances: - soc.calculate_average_utility(0) - soc.calculate_gini(0) - -world.calc_total_gross_income(0) -world.calc_total_harvest(0) -world.calc_total_nutrition(0) -world.calc_total_liquidity(0) - -# Run market clearing once: -metabolism.do_market_clearing(0) -# In case of a erdos renyi network: -# culture.calculate_modularity(0) -# culture.calculate_transitivity(0) -print("done ({})".format(dt.timedelta(seconds=(time() - start)))) - -termination_conditions = [[M.Metabolism.check_for_market_equilibrium, metabolism], - [M.World.check_for_exceptions, world]] - -print('\n runner starting') -# Runner is instantiated -r = Runner(model=model, termination_calls=termination_conditions - ) - -start = time() -# run the Runner and saving the return dict in traj -traj = r.run(t_1=timeinterval, dt=timestep, max_resolution=True) -runtime = dt.timedelta(seconds=(time() - start)) -print('runtime: {runtime}'.format(**locals())) - - -# Saving: -print('saving:') -traj.save(filename='data') -print('...is done') - -# Plotting: -t = np.array(traj['t']) -# for key, val in traj.items(): -# print('key', key,) -plot(t, traj[M.World.water_price][world], "b", lw=3) -plot(t, traj[M.World.total_gross_income][world], "m:", lw=3) -plot(t, traj[M.World.total_harvest][world], "m--", lw=3) -# plot(t, traj[M.Culture.network_clustering][culture], "r--", lw=3) -# plot(t, traj[M.Culture.modularity][culture], "r:", lw=3) - -for soc in municipalities: - plot(t, traj[M.SocialSystem.population][soc], "r", lw=3) - #plot(t, traj[M.SocialSystem.average_utility][soc], "r:", lw=3) - #plot(t, traj[M.SocialSystem.gini_coefficient][soc], "r--", lw=3) -for soc in counties: - plot(t, traj[M.SocialSystem.population][soc], "k", lw=3) - #plot(t, traj[M.SocialSystem.average_utility][soc], "k:", lw=3) - #plot(t, traj[M.SocialSystem.gini_coefficient][soc], "k--", lw=3) - -# for ind in M.Individual.instances: -# plot(t, traj[M.Individual.utility][ind], "y", lw=0.5) -gca().set_yscale('symlog') - -# savefig('20_ag_4_soc.png', dpi=150) -show() - -# network_data = traj[M.Culture.acquaintance_network][culture] -# G = network_data[-1] - -# Make list to have colors according to profession: -# professions = {} -# for ind in M.Individual.instances: -# if ind.profession == 'farmer': -# professions[ind] = 'yellow' -# else: -# professions[ind] = 'red' -# colors = [professions.get(node) for node in list(G.nodes())] -# # Make second list to have labels according to social_system: -# social_systems = {} -# for ind in M.Individual.instances: -# social_systems[ind] = str(ind.social_system._uid) -# nx.draw(G, node_color=colors, -# labels=social_systems, -# pos=nx.spring_layout(G)) -# show() diff --git a/studies/run_exploit.py b/studies/run_exploit.py deleted file mode 100755 index 23ab8837..00000000 --- a/studies/run_exploit.py +++ /dev/null @@ -1,137 +0,0 @@ -"""Test Study for the exploit model. - -A study to test the runner with the exploit model. -It includes the module components exploit_social_learning, -most_simple_vegetation and simple_extraction. -""" - -# This file is part of pycopancore. -# -# Copyright (C) 2016-2017 by COPAN team at Potsdam Institute for Climate -# Impact Research -# -# URL: -# Contact: core@pik-potsdam.de -# License: BSD 2-clause license - -import numpy as np -from time import time -import datetime as dt -from numpy import random -import argparse - -import plotly.offline as py -import plotly.graph_objs as go - -import pycopancore.models.exploit as M -from pycopancore.runners.runner import Runner - -#parameters: -timeinterval = 100 -timestep = 0.1 -ni_sust = 50 # number of agents with sustainable strategy 1 -ni_nonsust = 50 # number of agents with unsustainable strategy 0 -nindividuals = ni_sust + ni_nonsust -nc = nindividuals # number of cells -p = 0.4 # link density - -# New Order of instantiating things !!!!! -# instantiate model -model = M.Model() - -# instantiate process taxa culture: -culture = M.Culture() - -# generate entitites: -world = M.World(culture=culture) -social_system = M.SocialSystem(world=world) -cells = [M.Cell(stock=1, capacity=1, growth_rate=1, social_system=social_system) - for c in range(nc)] -individuals = [M.Individual(strategy=0, imitation_tendency=0, - rewiring_prob=0.5, - cell=cells[i]) for i in range(ni_nonsust)]\ - + [M.Individual(strategy=1, imitation_tendency=0, - rewiring_prob=0.5, - cell=cells[i+ni_nonsust]) - for i in range(ni_sust)] - -for (i, c) in enumerate(cells): - c.individual = individuals[i] - - -def erdosrenyify(graph, p=0.5): - """Create a ErdosRenzi graph from networkx graph. - - Take a a networkx.Graph with nodes and distribute the edges following the - erdos-renyi graph procedure. - """ - assert not graph.edges(), "your graph has already edges" - nodes = list(graph.nodes()) - for i, n1 in enumerate(nodes[:-1]): - for n2 in nodes[i+1:]: - if random.random() < p: - graph.add_edge(n1, n2) - -# set the initial graph structure to be an erdos-renyi graph -print("erdosrenyifying the graph ... ", end="", flush=True) -start = time() -erdosrenyify(culture.acquaintance_network, p=p) -print("done ({})".format(dt.timedelta(seconds=(time() - start)))) - -print('\n runner starting') - -# Define termination signals as list [ signal_method, object_method_works_on ] -signal_consensus = [M.Culture.check_for_consensus, - culture] -# Define termination_callables as list of all signals -termination_callables = [signal_consensus] -print('termination_callables: ', termination_callables) - -r = Runner(model=model, termination_calls=termination_callables) -start = time() -traj = r.run(t_1=timeinterval, dt=timestep) -runtime = dt.timedelta(seconds=(time() - start)) -print('runtime: {runtime}'.format(**locals())) - -t = np.array(traj['t']) -print("max. time step", (t[1:]-t[:-1]).max()) -# print('keys:', np.array(traj.keys())) -# print('completeDict: ', traj) - -individuals_strategies = np.array([traj[M.Individual.strategy][ind] - for ind in individuals]) - -nopinion1_list = np.sum(individuals_strategies, axis=0) / nindividuals -nopinion0_list = 1 - nopinion1_list - -# everything below is just plotting commands for plotly - -data_opinion0 = go.Scatter( - x=t, - y=nopinion0_list, - mode="lines", - name="relative amount strategy 0", - line=dict( - color="lightblue", - width=2 - ) -) -data_opinion1 = go.Scatter( - x=t, - y=nopinion1_list, - mode="lines", - name="relative amount strategy 1", - line=dict( - color="orange", - width=2 - ) -) - -layout = dict(title='Exploit Model', - xaxis=dict(title='time'), - yaxis=dict(title='relative strategy amounts'), - ) - -fig = dict(data=[data_opinion0, data_opinion1], layout=layout) -py.plot(fig, filename="exlpoit_model.html") - diff --git a/studies/run_groups_illustration.py b/studies/run_groups_illustration.py deleted file mode 100644 index c17fb1d6..00000000 --- a/studies/run_groups_illustration.py +++ /dev/null @@ -1,173 +0,0 @@ -"""This is an illustration script for some of the features that come with the group entity based on the seven dwarfs model. -""" - -# This file is part of pycopancore. -# -# Copyright (C) 2016-2017 by COPAN team at Potsdam Institute for Climate -# Impact Research -# -# URL: -# Contact: core@pik-potsdam.de -# License: BSD 2-clause license - -import numpy as np -from numpy.random import uniform -from time import time -import datetime as dt - -import networkx as nx -from networkx.algorithms import bipartite -import matplotlib.pyplot as plt - -import plotly.offline as py -import plotly.graph_objs as go - -import pycopancore.models.groups_seven_dwarfs as M -from pycopancore.runners.runner import Runner - -# from studies import plot_multilayer as pm -# from mpl_toolkits.mplot3d import Axes3D -# from mpl_toolkits.mplot3d.art3d import Line3DCollection - - -# setting timeinterval for run method 'Runner.run()' -timeinterval = 10 -# setting time step to hand to 'Runner.run()' -timestep = .1 -nc = 1 # number of caves -dwarfs = 10 # number of dwarfs - -# instantiate model M (needs to be done in the beginning of each script). -# This configures the model M through 'ModelLogics' in module -# 'base.model_logics' such that initialisation of attributes and entities gets -# possible -model = M.Model() - -# instantiate process taxa culture: -# In this certain case we need 'M.Culture()' for the acquaintance network. -culture = M.Culture() - -# instantiate world: -world = M.World(culture=culture) - -# instantiate one social system: -social_system = M.SocialSystem(world=world) - -# instantiate cells (the caves): -cells = [M.Cell(social_system=social_system, - eating_stock=100 - ) - for c in range(nc) - ] - -# instantiate dwarfs and assigning initial conditions -individuals = [M.Individual(cell=cells[0], - age=0, - beard_length=0, - beard_growth_parameter=0.5, - eating_parameter=.1 - ) for i in range(dwarfs) - ] - -print("\n The individuals:") -print(individuals) -print("\n \n") - -# assigning individuals to cell is not necessary since it is done by -# initializing the individuals in 'base.Individuals' with the 'cell' method - -# instantiate groups -ng = 10 #number of groups -groups = [M.Group(culture=culture, world=world) for i in range (ng)] - -print("\n The groups:") -print(groups) -print("\n \n") - -start = time() - -print("done ({})".format(dt.timedelta(seconds=(time() - start)))) - -print('\n runner starting') - -# first test for group network -#nx.draw(culture.group_membership_network) -#plt.show() - - -# initialize the network: -for i in individuals: - for g in groups: - culture.group_membership_network.add_edge(i, g) - -print("\n Individual 1 Group Memberships:") -print(list(individuals[0].group_memberships)) -print("\n") - -print("\n Group Members:") -print(list(groups[0].group_members)) -print("\n") - -#draw network of one group -# nx.draw(individuals[0].culture.group_membership_network) -# plt.show() - -GM = culture.group_membership_network - -print("\n The data structure in gm network:") -print(GM.nodes.data()) -print("\n") - -# How networkx would classicaly plot the network -nx.draw(culture.group_membership_network) -plt.show() - -# How to plot more intuitively using the type and color information -color_map = [] -shape_map = [] -for node in list(GM.nodes): - print(node) - print(GM.nodes[node]) - color_map.append(GM.nodes[node]["color"]) - - if GM.nodes[node]["type"] == "Group": - shape_map.append("o") - else: - shape_map.append("^") -top_nodes = {n for n, d in GM.nodes(data=True) if d["type"] == "Group"} -bottom_nodes = set(GM) - top_nodes -nx.draw(GM, node_color=color_map, with_labels=False, - pos=nx.bipartite_layout(GM, bottom_nodes, align="horizontal", aspect_ratio=4/1)) -plt.show() - -# Define termination signals as list [ signal_method, object_method_works_on ] -# the termination method 'check_for_extinction' must return a boolean -termination_signal = [M.Culture.check_for_extinction, - culture] - -# Define termination_callables as list of all signals -termination_callables = [termination_signal] - -# nx.draw(culture.acquaintance_network) -# plt.show() - -# Runner is instantiated -r = Runner(model=model, - termination_calls=termination_callables - ) - -start = time() -# run the Runner and saving the return dict in traj -traj = r.run(t_1=timeinterval, dt=timestep, add_to_output=[M.Culture.acquaintance_network]) -runtime = dt.timedelta(seconds=(time() - start)) -print('runtime: {runtime}'.format(**locals())) - -# saving time values to t -t = np.array(traj['t']) -print("max. time step", (t[1:]-t[:-1]).max()) - -# save and print membership - -membercheck = traj[M.Group.having_members] -plt.plot(t, membercheck[groups[0]]) # plot if dwarf 0 was member of group 0 -plt.show() diff --git a/studies/run_seven_dwarfs.py b/studies/seven_dwarfs/run_seven_dwarfs.py similarity index 100% rename from studies/run_seven_dwarfs.py rename to studies/seven_dwarfs/run_seven_dwarfs.py diff --git a/studies/test_jobsts_prototype_1.py b/studies/test_jobsts_prototype_1.py deleted file mode 100755 index 15a51a38..00000000 --- a/studies/test_jobsts_prototype_1.py +++ /dev/null @@ -1,259 +0,0 @@ -"""Skript to run Jobsts prototype model.""" - -# This file is part of pycopancore. -# -# Copyright (C) 2016-2017 by COPAN team at Potsdam Institute for Climate -# Impact Research -# -# URL: -# Contact: core@pik-potsdam.de -# License: BSD 2-clause license - -from time import time -from numpy import random, array -import numpy as np -import pycopancore.models.jobsts_prototype_1 as M -# import pycopancore.models.only_copan_global_like_carbon_cycle as M -from pycopancore import master_data_model as D -from pycopancore.runners import Runner - -from pylab import plot, gca, show, figure, subplot, gca, semilogy, legend - -# first thing: set seed so that each execution must return same thing: -random.seed(10) # 10 - -# parameters: - -nworlds = 1 # no. worlds -nsocs = 5 # no. social_systems #10 -ncells = 100 # no. cells #100 -ninds = 1000 # no. individuals - -model = M.Model() - -# instantiate process taxa: -environment = M.Environment() -metabolism = M.Metabolism( - renewable_energy_knowledge_spillover_fraction = .1, #.1, #.1, - # 1 w/o protection: success but desertification - # .75 w protection: success (even w/o or w much migration) - # .1 w protection: success but desertification - # 0 w/o protection: very slow success but desertification - # ?: oscillations - basic_emigration_probability_rate = 16e-13, # 5e-13 leads to ca. 5mio. at 10 socs, (real) - ) -culture = M.Culture( - awareness_lower_carbon_density=1e-4, #1e100, # 1e-6? - awareness_upper_carbon_density=2e-4, #1e100, # 2e-6? - awareness_update_rate=0, #1:SUCCESS, #1e-10 - environmental_friendliness_learning_rate=0, #1:SUCCESS - max_protected_terrestrial_carbon_share=0, - ) - -# generate entities and plug them together at random: -worlds = [M.World(environment=environment, metabolism=metabolism, culture=culture, - atmospheric_carbon = 830 * D.gigatonnes_carbon, - upper_ocean_carbon = (5500 - 830 - 2480 - 1125) * D.gigatonnes_carbon - ) for w in range(nworlds)] -social_systems = [M.SocialSystem(world=random.choice(worlds), - has_renewable_subsidy = random.choice([False, True], p=[3/4, 1/4]), #True, #False, - has_emissions_tax = random.choice([False, True], p=[4/5, 1/5]), #True, #False, - has_fossil_ban = False, #True, #False, - time_between_votes = 1e100, #4, #1e100, # 4 - ) for s in range(nsocs)] -cells = [M.Cell(social_system=random.choice(social_systems), - renewable_sector_productivity = 2 * random.rand() - * M.Cell.renewable_sector_productivity.default) - for c in range(ncells)] -individuals = [M.Individual( - cell=random.choice(cells), - is_environmentally_friendly = - random.choice([False, True], p=[.7, .3]), #True, #False, - ) - for i in range(ninds)] - -# initialize block model acquaintance network: -target_degree = 150 -target_degree_samecell = 0.5 * target_degree -target_degree_samesoc = 0.35 * target_degree -target_degree_other = 0.15 * target_degree -p_samecell = target_degree_samecell / (ninds/ncells - 1) -p_samesoc = target_degree_samesoc / (ninds/nsocs - ninds/ncells - 1) -p_other = target_degree_other / (ninds - ninds/nsocs - 1) -for index, i in enumerate(individuals): - for j in individuals[:index]: - if random.uniform() < ( - p_samecell if i.cell == j.cell - else p_samesoc if i.social_system == j.social_system \ - else p_other): - culture.acquaintance_network.add_edge(i, j) -#print("degrees:",culture.acquaintance_network.degree()) - -# distribute area and vegetation randomly but correlatedly: -r = random.uniform(size=ncells) -Sigma0 = 1.5e8 * D.square_kilometers * r / sum(r) -M.Cell.land_area.set_values(cells, Sigma0) -# print(M.Cell.land_area.get_values(cells)) - -r += random.uniform(size=ncells) -L0 = 2480 * D.gigatonnes_carbon * r / sum(r) # 2480 is yr 2000 -M.Cell.terrestrial_carbon.set_values(cells, L0) -# print(M.Cell.terrestrial_carbon.get_values(cells)) - -r = np.exp(random.normal(size=ncells)) -G0 = 1125 * D.gigatonnes_carbon * r / sum(r) # 1125 is yr 2000 -M.Cell.fossil_carbon.set_values(cells, G0) -# print(M.Cell.fossil_carbon.get_values(cells)) - -r = random.uniform(size=nsocs) -P0 = 6e9 * D.people * r / sum(r) # 500e9 is middle ages, 6e9 would be yr 2000 -M.SocialSystem.population.set_values(social_systems, P0) -M.SocialSystem.migrant_population.set_values(social_systems, P0 * 250e6/6e9) -for s in social_systems: - s.max_protected_terrestrial_carbon = 0.90 * sum(c.terrestrial_carbon for c in s.cells) - -# print(M.SocialSystem.population.get_values(social_systems)) - -r = random.uniform(size=nsocs) -K0 = sum(P0) * 1e4 * D.dollars/D.people * r / sum(r) # ? -M.SocialSystem.physical_capital.set_values(social_systems, K0) -# print(M.SocialSystem.physical_capital.get_values(social_systems)) - -# for renewables, do NOT divide by number of socs: -r = random.uniform(size=nsocs) -# in AWS paper: 1e12 (alternatively: 1e13): -S0 = 1e12 * D.gigajoules * r / r.mean() -M.SocialSystem.renewable_energy_knowledge.set_values(social_systems, S0) -# print(M.SocialSystem.renewable_energy_knowledge.get_values(social_systems)) - -# TODO: add noise to parameters - -w = worlds[0] -s = social_systems[0] -c = cells[0] -for v in environment.variables: print(v,v.get_value(environment)) -for v in metabolism.variables: print(v,v.get_value(metabolism)) -for v in w.variables: print(v,v.get_value(w)) -for v in s.variables: print(v,v.get_value(s)) -for v in c.variables: print(v,v.get_value(c)) - -# from pycopancore.private._expressions import eval -# import pycopancore.model_components.base.interface as B -# import sympy as sp - -runner = Runner(model=model) - -start = time() -traj = runner.run(t_0=2000, t_1=2000+100, dt=1, add_to_output=[M.Individual.represented_population]) - - -for v in environment.variables: print(v,v.get_value(environment)) -for v in metabolism.variables: print(v,v.get_value(metabolism)) -for v in w.variables: print(v,v.get_value(w)) -for v in s.variables: print(v,v.get_value(s)) -for v in c.variables: print(v,v.get_value(c)) - - -from pickle import dump -tosave = { - v.owning_class.__name__ + "." - + v.codename: {str(e): traj[v][e] - for e in traj[v].keys() - } - for v in traj.keys() if v is not "t" - } -tosave["t"] = traj["t"] -dump(tosave, open("/home/jobst/work/without.pickle","wb")) -print(time()-start, " seconds") - -t = np.array(traj['t']) -print("max. time step", (t[1:]-t[:-1]).max()) - -figure() -lws = 1 - -subplot(511) # cultural -for i, s in enumerate(social_systems): -# plot(t[3:], traj[M.SocialSystem.protected_terrestrial_carbon_share][s][3:],color="green",lw=lws, label=None if i else "share of protected biomass") - plot(t[3:], traj[M.SocialSystem.has_renewable_subsidy][s][3:]*1,color="darkorange",lw=lws, label=None if i else "renewable subsidy in place?") - plot(t[3:], traj[M.SocialSystem.has_emissions_tax][s][3:]*1,color="blue",lw=lws, label=None if i else "emissions tax in place?") - plot(t[3:], traj[M.SocialSystem.has_fossil_ban][s][3:]*1,color="gray",lw=lws, label=None if i else "fossil ban in place?") -legend() - -subplot(512) # metabolic, logscale: capital, knowledge, production, wellbeing -for i, s in enumerate(social_systems): - semilogy(t[3:], array(traj[M.SocialSystem.physical_capital][s][3:])/1e6, color="black", lw=lws, label=None if i else "physical capital [mio. $]") - semilogy(t[3:], array(traj[M.SocialSystem.renewable_energy_knowledge][s][3:])/1e6, color="darkorange", lw=lws, label=None if i else "renewable energy knowledge [PJ]") - semilogy(t[3:], array(traj[M.SocialSystem.economic_output_flow][s][3:])/1e6, color="blue", lw=lws, label=None if i else "GDP [mio. $ per year]") - semilogy(t[3:], array(traj[M.SocialSystem.wellbeing][s][3:]), color="magenta",lw=lws, label=None if i else "wellbeing [$ per year and person]") -legend() - -subplot(513) # metabolic: population (left), migration (right) -ax1 = gca() -#ax1.set_xlabel('years') -# Make the y-axis label, ticks and tick labels match the line color. -ax1.set_ylabel('humans') -ax1.tick_params('y') -ax2 = ax1.twinx() -ax2.set_ylabel('humans per year', color='gray') -ax2.tick_params('y', colors='gray') -for i, s in enumerate(social_systems): - ax1.plot(t[3:], traj[M.SocialSystem.population][s][3:],color="black",lw=lws, label=None if i else "population") - ax1.plot(t[3:], traj[M.SocialSystem.migrant_population][s][3:],"-.",color="black",lw=lws, label=None if i else "migrant population") - ax2.plot(t[3:], traj[M.SocialSystem.immigration][s][3:],"--",color="gray",lw=lws, label=None if i else "immigration flow") - ax2.plot(t[3:], traj[M.SocialSystem.emigration][s][3:],":",color="gray",lw=lws, label=None if i else "emigration flow") -ax1.legend(loc=2) -ax2.legend(loc=1) - -subplot(514) # metabolic: energy mix -for i, s in enumerate(social_systems): - Es = array(traj[M.SocialSystem.secondary_energy_flow][s][3:]) - plot(t[3:], array(traj[M.SocialSystem.biomass_input_flow][s][3:]) * metabolism.biomass_energy_density / Es, color="green", lw=lws, label=None if i else "share of biomass") - plot(t[3:], array(traj[M.SocialSystem.fossil_fuel_input_flow][s][3:]) * metabolism.fossil_energy_density / Es, color="gray", lw=lws, label=None if i else "share of fossils") - plot(t[3:], array(traj[M.SocialSystem.renewable_energy_input_flow][s][3:]) / Es, color="darkorange", lw=lws, label=None if i else "share of renewables") -legend() - -subplot(515) # natural -plot(t[3:], traj[M.World.atmospheric_carbon][worlds[0]][3:], color="cyan", lw=3, label="atmospheric carbon") -plot(t[3:], traj[M.World.upper_ocean_carbon][worlds[0]][3:], color="blue", lw=3, label="upper ocean carbon") -plot(t[3:], traj[M.World.terrestrial_carbon][worlds[0]][3:], color="green", lw=3, label="terrestrial carbon") -plot(t[3:], traj[M.World.fossil_carbon][worlds[0]][3:], color="gray", lw=3, label="fossil carbon") -for i, s in enumerate(social_systems): - plot(t[3:], traj[M.SocialSystem.protected_terrestrial_carbon][s][3:],color="green",lw=lws, label=None if i else "protected biomass") -gca().set_ylabel('gigatonnes carbon') -legend() - -print("\nyr 2000 values (real):") -print("emigration (5e6):",sum(traj[M.SocialSystem.emigration][s][5] for s in social_systems)) # should be ca. 5e6 -print("photo (123):",sum(traj[M.Cell.photosynthesis_carbon_flow][c][5] for c in cells)) -print("resp (118):",sum(traj[M.Cell.terrestrial_respiration_carbon_flow][c][5] for c in cells)) -print("GWP (4e13):",sum(traj[M.SocialSystem.economic_output_flow][s][5] for s in social_systems)) # should be ca. 4e13 -Bglobal = sum(traj[M.SocialSystem.biomass_input_flow][s][5] for s in social_systems) * D.gigatonnes_carbon / D.years -Fglobal = sum(traj[M.SocialSystem.fossil_fuel_input_flow][s][5] for s in social_systems) * D.gigatonnes_carbon / D.years -Rglobal = sum(traj[M.SocialSystem.renewable_energy_input_flow][s][5] for s in social_systems) * D.gigajoules / D.years -print("B (3), F (11), R(100):", - Bglobal.tostr(unit=D.gigatonnes_carbon/D.years), # should be ca. 3 - Fglobal.tostr(unit=D.gigatonnes_carbon/D.years), # should be ca. 11 - Rglobal.tostr(unit=D.gigawatts)) # last should be ca. 100 -#print((Bglobal * metabolism.biomass_energy_density * D.gigajoules/D.gigatonnes_carbon).tostr(unit=D.gigawatts), -# (Fglobal * metabolism.fossil_energy_density * D.gigajoules/D.gigatonnes_carbon).tostr(unit=D.gigawatts), -# Rglobal.tostr(unit=D.gigawatts), "(100)") # last should be ca. 100 -print("life exp. at end:",1/np.mean([traj[M.SocialSystem.mortality][s][-1] for s in social_systems])) -print("cap. deprec. at begin (0.1?):",np.mean([traj[M.SocialSystem.physical_capital_depreciation_rate][s][5] for s in social_systems])) -print("cap. deprec. at end (0.1?):",np.mean([traj[M.SocialSystem.physical_capital_depreciation_rate][s][-1] for s in social_systems])) -print("deaths at begin (>250000?):",sum(traj[M.SocialSystem.deaths][s][5] for s in social_systems)) -print("deaths at end (>250000?):",sum(traj[M.SocialSystem.deaths][s][-1] for s in social_systems)) -print("temp. at begin:",traj[M.World.surface_air_temperature][worlds[0]][5]) -print("temp. at end:",traj[M.World.surface_air_temperature][worlds[0]][-1]) -print("prot. carbon share:",[traj[M.SocialSystem.protected_terrestrial_carbon][s][-1]/sum(traj[M.Cell.terrestrial_carbon][c][-1]for c in s.cells) for s in social_systems]) -print(traj[M.World.terrestrial_carbon][worlds[0]][-1],sum(traj[M.Cell.terrestrial_carbon][c][-1] for c in worlds[0].cells)) - -show() - -# TODO: -# policy shares, env. friendly shares -# transparancy, means -# wellb. abs., renew., pop. log -# total protected -# horiz. -# save dump with codename,uid as key \ No newline at end of file diff --git a/studies/test_our_model.py b/studies/test_our_model.py deleted file mode 100755 index 91d46a3e..00000000 --- a/studies/test_our_model.py +++ /dev/null @@ -1,137 +0,0 @@ -"""Skript to run Anderies carbon cycle.""" - -# This file is part of pycopancore. -# -# Copyright (C) 2016-2017 by COPAN team at Potsdam Institute for Climate -# Impact Research -# -# URL: -# Contact: core@pik-potsdam.de -# License: BSD 2-clause license - -from time import time -from numpy import random -import numpy as np -import pycopancore.models.our_model as M -# import pycopancore.models.only_copan_global_like_carbon_cycle as M -from pycopancore import master_data_model as D -from pycopancore.runners import Runner - -# import plotly.plotly as py -import plotly.offline as py -import plotly.graph_objs as go -from pylab import plot, gca, show - - - -# first thing: set seed so that each execution must return same thing: -random.seed(1) - -# parameters: - -model = M.Model() - -# instantiate process taxa: -environment = M.Environment() -# metabolism = M.Metabolism() - -# generate entities and plug them together at random: -world = M.World(environment=environment, #metabolism=metabolism, - atmospheric_carbon = 0.2 * D.gigatonnes_carbon, #relative values - ocean_carbon = 0.6 * D.gigatonnes_carbon - ) -social_system = M.SocialSystem(world=world) -cell = M.Cell(social_system=social_system) - -# set initial values # only one cell so far -Sigma0 = 1.5e8 * D.square_kilometers -cell.land_area = Sigma0 -# print(M.Cell.land_area.get_values(cells)) - -L0 = 0.2 * D.gigatonnes_carbon # 2480 is yr 2000 -cell.terrestrial_carbon = L0 -# print(M.Cell.terrestrial_carbon.get_values(cells)) - -G0 = 0.5 * D.gigatonnes_carbon # 1125 is yr 2000 -cell.fossil_carbon = G0 -# print(M.Cell.fossil_carbon.get_values(cells)) - -# r = random.uniform(size=nsocs) -# P0 = 6e9 * D.people * r / sum(r) # 500e9 is middle ages, 6e9 would be yr 2000 -# M.SocialSystem.population.set_values(social_systems, P0) -# print(M.SocialSystem.population.get_values(social_systems)) - -# r = random.uniform(size=nsocs) -# in AWS paper: 1e12 (alternatively: 1e13): -# S0 = 1e13 * D.gigajoules * r / sum(r) -# M.SocialSystem.renewable_energy_knowledge.set_values(social_systems, S0) -# print(M.SocialSystem.renewable_energy_knowledge.get_values(social_systems)) - -# r = random.uniform(size=nsocs) -# K0 = sum(P0) * 1e4 * D.dollars/D.people * r / sum(r) # ? -# M.SocialSystem.physical_capital.set_values(social_systems, K0) -# print(M.SocialSystem.physical_capital.get_values(social_systems)) - -# TODO: add noise to parameters - -# from pycopancore.private._expressions import eval -# import pycopancore.model_components.base.interface as B -# import sympy as sp - -runner = Runner(model=model) - -start = time() -traj = runner.run(t_1=100, dt=.1) -print(time()-start, " seconds") - -t = np.array(traj['t']) -print("max. time step", (t[1:]-t[:-1]).max()) - -data_ca = go.Scatter( - x=t, - y=traj[M.World.atmospheric_carbon][world], - mode="lines", - name="atmospheric carbon", - line=dict( - color="lightblue", - width=4 - ) -) -data_ct = go.Scatter( - x=t, - y=traj[M.World.terrestrial_carbon][world], - mode="lines", - name="terrestrial carbon", - line=dict( - color="green", - width=4 - ) -) -data_cm = go.Scatter( - x=t, - y=traj[M.World.ocean_carbon][world], - mode="lines", - name="maritime carbon", - line=dict( - color="blue", - width=4 - ) -) -data_cf = go.Scatter( - x=t, - y=traj[M.World.fossil_carbon][world], - mode="lines", - name="fossil carbon", - line=dict( - color="gray", - width=4 - ) -) -layout = dict(title = 'Our model (Anderies Carbon Cycle)', - xaxis = dict(title = 'time [yr]'), - yaxis = dict(title = 'Carbon [GtC]'), - ) - -fig = dict(data=[data_ca, data_ct, data_cm, data_cf], layout=layout) -py.plot(fig, filename="our-model-result.html") - diff --git a/tests/test_simple_extraction_individual.py b/tests/test_simple_extraction_individual.py deleted file mode 100644 index d60ca152..00000000 --- a/tests/test_simple_extraction_individual.py +++ /dev/null @@ -1,66 +0,0 @@ -"""Test file for the simple extraction module.""" - -# This file is part of pycopancore. -# -# Copyright (C) 2016-2017 by COPAN team at Potsdam Institute for Climate -# Impact Research -# -# URL: -# Contact: core@pik-potsdam.de -# License: BSD 2-clause license - - -import pycopancore.models.exploit as M - -import numpy as np -import unittest - -################################################################### -# Example from https://docs.python.org/3/library/unittest.html -################################################################### -# class TestStringMethods(unittest.TestCase): -# -# def test_upper(self): -# self.assertEqual('foo'.upper(), 'FOO') -# -# def test_isupper(self): -# self.assertTrue('FOO'.isupper()) -# self.assertFalse('Foo'.isupper()) -# # self.assertTrue('Foo'.isupper(), "This test is failing on purpose.") # -# -# def test_split(self): -# s = 'hello world' -# self.assertEqual(s.split(), ['hello', 'world']) -# # check that s.split fails when the separator is not a string -# with self.assertRaises(TypeError): -# s.split(2) - - -class TestSimpleExtraction(unittest.TestCase): - - def setUp(self): - """called before any of the tests in this test case""" - - self.stock = np.random.random() - self.growth_rate = np.random.random() - self.strategy = np.random.random() - - self.culture = M.Culture() - self.world = M.World(culture=self.culture) - self.cell = M.Cell(stock=self.stock, capacity=1, growth_rate=self.growth_rate, world=self.world) - self.individual = M.Individual( - strategy=self.strategy, - imitation_tendency=0, - cell=self.cell - ) - - def test_simple_extractiont(self): - """Check the whole component.""" - ####################################################### - # Put all tests in one method, else you might get - # annoying problems because we have a global list - # of instances for most classes. - ####################################################### - # self.assertTrue(False, "This is definitely wrong") - solution = 0.5 * self.growth_rate * (3 - 2 * self.strategy) * self.stock - self.assertEqual(self.individual.get_harvest_rate(), solution) \ No newline at end of file