Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Updates for compatibility with latest OG-Core #54

Merged
merged 41 commits into from
Jun 19, 2024

Conversation

jdebacker
Copy link
Collaborator

This PR makes updates to OG-ZAF to work with the latest OG-Core.

Copy link

codecov bot commented May 3, 2024

Codecov Report

Attention: Patch coverage is 77.58621% with 13 lines in your changes missing coverage. Please review.

Project coverage is 57.06%. Comparing base (3aaaad5) to head (0a43488).
Report is 2 commits behind head on main.

Files Patch % Lines
ogzaf/income.py 22.22% 7 Missing ⚠️
ogzaf/calibrate.py 25.00% 3 Missing ⚠️
setup.py 0.00% 3 Missing ⚠️
Additional details and impacted files
@@             Coverage Diff             @@
##             main      #54       +/-   ##
===========================================
+ Coverage   36.64%   57.06%   +20.41%     
===========================================
  Files           4       12        +8     
  Lines         191      361      +170     
===========================================
+ Hits           70      206      +136     
- Misses        121      155       +34     
Flag Coverage Δ
unittests 57.06% <77.58%> (+20.41%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@jdebacker
Copy link
Collaborator Author

@SeaCelo in making these updates, I'm not longer able to retrieve the labor share data from the UN portal:

    """
    This retrieves labour share data from the United Nations Data Portal API
    (see https://data.un.org)
    """

    target = (
        "https://data.un.org/ws/rest/data/IAEG-SDGs,DF_SDG_GLH/"
        + "..SL_EMP_GTOTL.710..........."
        + "?startPeriod="
        + str(start.year)
        + "&"
        + "endPeriod="
        + str(end.year)
        + "&format=csv"
    )

I'm having trouble tracking down where this is in the UN API. Can you point me in the right direction or provide an updated link?

Thanks!

@SeaCelo
Copy link
Collaborator

SeaCelo commented May 4, 2024

@jdebacker it will take me a couple of days. I’m traveling to look at colleges all weekend. I’ll dig into this and the other UN API issues when I return

@SeaCelo
Copy link
Collaborator

SeaCelo commented May 6, 2024

@jdebacker Not sure if FRED will be the source going forward. I checked the UN data and there is an issue with their latest update (the previous version has the data, but since April it is missing). I reached out to confirm what to expect and to find a permanent solution.

@jdebacker
Copy link
Collaborator Author

@SeaCelo Thanks for following up. I did update to pull from FRED. Shall we just use that until the UN data become reliable again?

@SeaCelo
Copy link
Collaborator

SeaCelo commented May 7, 2024

@jdebacker I’ve confirmed that the series will no longer be available in the UN API after the ILO changed its criteria for reporting it. Let’s use FRED and I will explore using the ILO directly in the future.

@jdebacker jdebacker marked this pull request as ready for review May 7, 2024 14:17
@jdebacker jdebacker requested a review from SeaCelo May 7, 2024 14:17
@SeaCelo
Copy link
Collaborator

SeaCelo commented May 7, 2024

@jdebacker FRED has older data (2019) while ILO publishes 2021. ILO no longer publishes that specific country-indicator in the UN SDG data portal, but we can get it directly from the ILO site. The direct download url looks like this:
https://rplumber.ilo.org/data/indicator/?id=LAP_2GDP_NOC_RT_A&ref_area=ZAF&timefrom=2016&timeto=2021&type=code&format=.csv

and to get every year available by omitting the time variables:
https://rplumber.ilo.org/data/indicator/?id=LAP_2GDP_NOC_RT_A&ref_area=ZAF&type=both&format=.csv

I can make changes to this PR to get the right value

Changed the source of labor share of income (gamma) to ILOSTAT. This gets us the latest year available (currently 2021). Removed FRED as a source because it only gives us up to 2019.
@SeaCelo
Copy link
Collaborator

SeaCelo commented May 8, 2024

@jdebacker I've added a suggested change for your review jdebacker#1

@SeaCelo
Copy link
Collaborator

SeaCelo commented May 9, 2024

@jdebacker I just tested it and it fails in two places. First it requires the line import requests in macro_params.py (I forgot to add it in my last PR).

Second, it fails to get UN demographics data in ogcore:

Failed to retrieve population data. HTTP status code: 404
Traceback (most recent call last):
  File "/Users/mlafleur/Projects/OG-ZAF/examples/run_og_zaf.py", line 134, in <module>
    main()
  File "/Users/mlafleur/Projects/OG-ZAF/examples/run_og_zaf.py", line 54, in main
    c = Calibration(p, estimate_pop=True)
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/mlafleur/Projects/OG-ZAF/ogzaf/calibrate.py", line 96, in __init__
    self.demographic_params = demographics.get_pop_objs(
                              ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/mlafleur/opt/anaconda3/envs/ogzaf-dev/lib/python3.11/site-packages/ogcore/demographics.py", line 730, in get_pop_objs
    fert_rates = get_fert(
                 ^^^^^^^^^
  File "/Users/mlafleur/opt/anaconda3/envs/ogzaf-dev/lib/python3.11/site-packages/ogcore/demographics.py", line 141, in get_fert
    df = get_un_data("68", country_id=country_id, start_year=y, end_year=y)
         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/mlafleur/opt/anaconda3/envs/ogzaf-dev/lib/python3.11/site-packages/ogcore/demographics.py", line 99, in get_un_data
    assert False
           ^^^^^
AssertionError

I'm going to spend some time looking at that code and the UN API

@SeaCelo
Copy link
Collaborator

SeaCelo commented May 9, 2024

The UN Population API is not returning any results. I've contacted them asking for an explanation and solution, but for now it isn't working.

@SeaCelo
Copy link
Collaborator

SeaCelo commented May 13, 2024

@jdebacker The UN population API is under maintenance and I don't have an ETA. I can merge this PR but it isn't getting past the issue in demographics.py. Let me know if you think we should wait or just move ahead.

@jdebacker
Copy link
Collaborator Author

@SeaCelo Since things will not be working with or without this PR until the API is fixed, we can just let it sit here until then.

@SeaCelo
Copy link
Collaborator

SeaCelo commented May 16, 2024

@jdebacker

The UN API is moving to require bearer tokens. This will need to be changed in OG-CORE (PSLmodels/OG-Core#931). Once the API and registration system is live I will implement the changes as a PR in OG-CORE, and this will inherit the fix.

@jdebacker
Copy link
Collaborator Author

@SeaCelo The most recent commits to this PR set the default to download data if estimate_pop is True.

I don't have an API token, so I can't test, but you could do the following within the ogzaf-dev environment to test:

from ogcore.parameters import Specification
from ogzaf.calibrate import Calibration
p = Specifications()
c =Calibration(p, estimate_pop=True)

You can then check that the downloaded data is in OG-ZAF/ogzaf/data/demographic. If so, you can make a PR to this branch with those files (assuming they are less than 100MB -- IF they are larger than this, please let me know and we can readjust -- don't try to commit large files!)

After that, I can adjust the code a bit to have an option to use these cached data, with some flexibility to allow users to pull different year windows from it (FYI, if this works for you, it'll be downloaded the full series out to 2100).

Let me know how this works for you.

@SeaCelo
Copy link
Collaborator

SeaCelo commented May 17, 2024

@jdebacker I will test this soon. In the meantime I have requested tokens for you and @rickecon.

@SeaCelo
Copy link
Collaborator

SeaCelo commented May 20, 2024

@jdebacker Good news that I was able to run this code and get results from the API. But this required other adjustments to OG-Core's demographics.py and even then I eventually ran into an assertion error.

This is the draft PR in OG-Core with more information (PSLmodels/OG-Core#934).

I created a PR to upload the files here: jdebacker#2

Let me know if you need me to test anything else until you get your own token.

@jdebacker
Copy link
Collaborator Author

@SeaCelo and @rickecon this PR is ready to review and merge. It gets OG-ZAF working with the latest OG-Core and removes a bunch of unused lines of code.

Before replicating these files to other country repos it would be good to work on 'macro_params.py'. I'll open an issue later outlining suggested changes there.

@rickecon
Copy link
Collaborator

@jdebacker. I am working on this PR right now. Doing a deep dive. Should have comments to you by 1:30p ET.

@rickecon
Copy link
Collaborator

@jdebacker. I just submitted a PR to your branch for this PR. There is an issue in run_og_zaf.py call to the Calibration class from ./ogzaf/calibrate.py, which should be easy to fix. And I made some changes that make OG-ZAF more parallel to OG-USA. I recommend you review and merge the changes I submitted as a PR to your branch, then you fix the issue in the run_og_zaf.py script.

@rickecon
Copy link
Collaborator

@jdebacker. I get the same error as you now running run_og_zaf.py. It is an issue in line 88 of txfunc.py. It is an array that is not the same shape as the other arrays in this multidimensional array object params. Here is my traceback output.

  File "/Users/richardevans/Docs/Economics/OSE/OG-ZAF/tests/../examples/run_og_zaf.py", line 77, in main
    runner(p, time_path=True, client=client)
  File "/opt/anaconda3/envs/ogzaf-dev/lib/python3.11/site-packages/ogcore/execute.py", line 46, in runner
    ss_outputs = SS.run_SS(p, client=client)
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/anaconda3/envs/ogzaf-dev/lib/python3.11/site-packages/ogcore/SS.py", line 1232, in run_SS
    sol = opt.root(
          ^^^^^^^^^
  File "/opt/anaconda3/envs/ogzaf-dev/lib/python3.11/site-packages/scipy/optimize/_root.py", line 236, in root
    sol = _root_hybr(fun, x0, args=args, jac=jac, **options)
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/anaconda3/envs/ogzaf-dev/lib/python3.11/site-packages/scipy/optimize/_minpack_py.py", line 228, in _root_hybr
    shape, dtype = _check_func('fsolve', 'func', func, x0, args, n, (n,))
                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/anaconda3/envs/ogzaf-dev/lib/python3.11/site-packages/scipy/optimize/_minpack_py.py", line 25, in _check_func
    res = atleast_1d(thefunc(*((x0[:numinputs],) + args)))
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/anaconda3/envs/ogzaf-dev/lib/python3.11/site-packages/ogcore/SS.py", line 1080, in SS_fsolve
    ) = inner_loop(outer_loop_vars, p, client)
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/anaconda3/envs/ogzaf-dev/lib/python3.11/site-packages/ogcore/SS.py", line 262, in inner_loop
    results = client.gather(futures)
              ^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/anaconda3/envs/ogzaf-dev/lib/python3.11/site-packages/distributed/client.py", line 2374, in gather
    return self.sync(
           ^^^^^^^^^^
  File "/opt/anaconda3/envs/ogzaf-dev/lib/python3.11/site-packages/scipy/optimize/_root.py", line 236, in root
    sol = _root_hybr(fun, x0, args=args, jac=jac, **options)
    ^^^^^^^^^^^^^^^^^
  File "/opt/anaconda3/envs/ogzaf-dev/lib/python3.11/site-packages/scipy/optimize/_minpack_py.py", line 228, in _root_hybr
    shape, dtype = _check_func('fsolve', 'func', func, x0, args, n, (n,))
      ^^^^^^^^^^^^^^^^^
  File "/opt/anaconda3/envs/ogzaf-dev/lib/python3.11/site-packages/scipy/optimize/_minpack_py.py", line 25, in _check_func
    res = atleast_1d(thefunc(*((x0[:numinputs],) + args)))
      ^^^^^^^^^^^^^^^^^
  File "/opt/anaconda3/envs/ogzaf-dev/lib/python3.11/site-packages/ogcore/SS.py", line 76, in euler_equation_solver
    error1 = household.FOC_savings(
      ^^^^^^^^^^^^^^^^^
  File "/opt/anaconda3/envs/ogzaf-dev/lib/python3.11/site-packages/ogcore/household.py", line 434, in FOC_savings
    taxes = tax.net_taxes(
      ^^^^^^^^^^^^^^^^^
  File "/opt/anaconda3/envs/ogzaf-dev/lib/python3.11/site-packages/ogcore/tax.py", line 339, in net_taxes
    T_I = income_tax_liab(r, w, b, n, factor, t, j, method, e, etr_params, p)
      ^^^^^^^^^^^^^^^^^
  File "/opt/anaconda3/envs/ogzaf-dev/lib/python3.11/site-packages/ogcore/tax.py", line 411, in income_tax_liab
    ETR_income(
  File "/opt/anaconda3/envs/ogzaf-dev/lib/python3.11/site-packages/ogcore/tax.py", line 162, in ETR_income
    tau = get_tax_rates(
      ^^^^^^^^^^^^^^^^^
  File "/opt/anaconda3/envs/ogzaf-dev/lib/python3.11/site-packages/ogcore/txfunc.py", line 88, in get_tax_rates
    params = np.array(
    ^^^^^^^^^^^^^^^^^
ValueError: setting an array element with a sequence. The requested array has an inhomogeneous shape after 1 dimensions. The detected shape was (80,) + inhomogeneous part.

@rickecon
Copy link
Collaborator

@jdebacker. I think I've ruled out the issue resulting from an updated version of NumPy. I ran OG-USA on my ogusa-dev conda environment, which I had updated last week. My baseline run solved the steady-state equilibrium and finished 1 iteration of the time path equilibrium before I interrupted it. I then created a new environment2.yml file and used it to create an updated conda environment ogusa-dev2. This updated environment had the same NumPy version (1.26.4) as my environment from last week. And the run_og_usa.py script had the same result. It ran well through steady state and 1 iteration of the time path iteration.

So I think we need to look directly at what this script is doing at line 88 of txfunc.py in OG-Core. Potentially some of the recent updates to OG-Core might be messing up these OG-ZAF runs.

@jdebacker
Copy link
Collaborator Author

@rickecon I still don't understand why, but it has to do with how I was trying to update the tax function parameters in the OG-ZAF run script:

    p.update_specifications(
        {
            "cit_rate": [[0.27]],
            "tax_func_type": "linear",
            "age_specific": False,
            "etr_params": [[[0.22]]],
            "mtrx_params": [[[0.31]]],
            "mtry_params": [[[0.25]]],
            "tau_c": [[0.15]],
        }
    )

When I comment out the ETR and MTR parameters in the dictionary above, run_og_zaf.py works for me. I get the same successful results you do with OG-USA.

Those ETR and MTR parameters go through validation and it looks like they are in the Specifications object in the correct shape, but they raise that error. I've also tried HSV functions and get the same error.

For now, perhaps we just go with the current run script, but in another PR we'll need to update the IIT tax rates for ZAF.

@rickecon
Copy link
Collaborator

@jdebacker. All good. Everything passing on my machine. Let's circle back to fix the tax functions. Merging now.

@rickecon rickecon merged commit 8958699 into EAPD-DRB:main Jun 19, 2024
10 checks passed
@rickecon
Copy link
Collaborator

@jdebacker. BTW. The GH Action CI tests after merge (on push) were failing on the Linux tests at the CodeCov stage. It looks like we just had a bad CODECOV_TOKEN in the settings. I reset that token, and everything has now passed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants