From 00ebf1fb039f6ae35303e979cfafc0a80c488198 Mon Sep 17 00:00:00 2001 From: Peter Steinberg Date: Thu, 12 Oct 2017 23:00:49 -0700 Subject: [PATCH 1/3] dynamic inputs for small_open boolean and world interest rate --- .../includes/params/inputs/dynamic.html | 3 ++ .../includes/params/inputs/elastic.html | 5 ++ .../migrations/0016_auto_20171012_1733.py | 25 +++++++++ .../migrations/0017_auto_20171012_1826.py | 25 +++++++++ .../migrations/0018_auto_20171013_0131.py | 25 +++++++++ webapp/apps/dynamic/models.py | 7 +++ webapp/apps/dynamic/ogusa_parameters.json | 51 ++++++++++++++++++- .../apps/dynamic/ogusa_user_modifiable.json | 2 +- 8 files changed, 141 insertions(+), 2 deletions(-) create mode 100644 webapp/apps/dynamic/migrations/0016_auto_20171012_1733.py create mode 100644 webapp/apps/dynamic/migrations/0017_auto_20171012_1826.py create mode 100644 webapp/apps/dynamic/migrations/0018_auto_20171013_0131.py diff --git a/templates/dynamic/includes/params/inputs/dynamic.html b/templates/dynamic/includes/params/inputs/dynamic.html index 6b9f5f07..5773bc07 100644 --- a/templates/dynamic/includes/params/inputs/dynamic.html +++ b/templates/dynamic/includes/params/inputs/dynamic.html @@ -13,6 +13,9 @@

Macroeconomic Parameters

{% endblock %} +

Open Economy Assumptions

+{% include 'taxbrain/includes/params/inputs/param.html' with param=params.small_open %} +{% include 'taxbrain/includes/params/inputs/param.html' with param=params.world_int_rate %}

Macroeconomic Parameters

{% include 'taxbrain/includes/params/inputs/param.html' with param=params.g_y_annual %} {% include 'taxbrain/includes/params/inputs/param.html' with param=params.frisch %} diff --git a/templates/dynamic/includes/params/inputs/elastic.html b/templates/dynamic/includes/params/inputs/elastic.html index 36c3a6ac..0ffd0db7 100644 --- a/templates/dynamic/includes/params/inputs/elastic.html +++ b/templates/dynamic/includes/params/inputs/elastic.html @@ -13,6 +13,11 @@

Macroeconomic Parameters

{% endblock %} +

Open Economy Assumptions

+{% include 'taxbrain/includes/params/inputs/param.html' with param=params.small_open %} +{% include 'taxbrain/includes/params/inputs/param.html' with param=params.world_int_rate %} + +

Elasticity of GDP wrt 1 - AMTR

{% include 'taxbrain/includes/params/inputs/param.html' with param=params.elastic_gdp %} diff --git a/webapp/apps/dynamic/migrations/0016_auto_20171012_1733.py b/webapp/apps/dynamic/migrations/0016_auto_20171012_1733.py new file mode 100644 index 00000000..dda0eea4 --- /dev/null +++ b/webapp/apps/dynamic/migrations/0016_auto_20171012_1733.py @@ -0,0 +1,25 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import models, migrations +import webapp.apps.taxbrain.models + + +class Migration(migrations.Migration): + + dependencies = [ + ('dynamic', '0015_auto_20170918_1255'), + ] + + operations = [ + migrations.AddField( + model_name='dynamicsaveinputs', + name='small_open', + field=models.NullBooleanField(default=None), + ), + migrations.AddField( + model_name='dynamicsaveinputs', + name='world_int_rate', + field=webapp.apps.taxbrain.models.CommaSeparatedField(default=None, max_length=200, null=True, blank=True), + ), + ] diff --git a/webapp/apps/dynamic/migrations/0017_auto_20171012_1826.py b/webapp/apps/dynamic/migrations/0017_auto_20171012_1826.py new file mode 100644 index 00000000..d9e66231 --- /dev/null +++ b/webapp/apps/dynamic/migrations/0017_auto_20171012_1826.py @@ -0,0 +1,25 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import models, migrations +import webapp.apps.taxbrain.models + + +class Migration(migrations.Migration): + + dependencies = [ + ('dynamic', '0016_auto_20171012_1733'), + ] + + operations = [ + migrations.AddField( + model_name='dynamicelasticitysaveinputs', + name='small_open', + field=models.NullBooleanField(default=None), + ), + migrations.AddField( + model_name='dynamicelasticitysaveinputs', + name='world_int_rate', + field=webapp.apps.taxbrain.models.CommaSeparatedField(default=None, max_length=200, null=True, blank=True), + ), + ] diff --git a/webapp/apps/dynamic/migrations/0018_auto_20171013_0131.py b/webapp/apps/dynamic/migrations/0018_auto_20171013_0131.py new file mode 100644 index 00000000..708a844e --- /dev/null +++ b/webapp/apps/dynamic/migrations/0018_auto_20171013_0131.py @@ -0,0 +1,25 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import models, migrations +import webapp.apps.taxbrain.models + + +class Migration(migrations.Migration): + + dependencies = [ + ('dynamic', '0017_auto_20171012_1826'), + ] + + operations = [ + migrations.AddField( + model_name='dynamicbehaviorsaveinputs', + name='small_open', + field=models.NullBooleanField(default=None), + ), + migrations.AddField( + model_name='dynamicbehaviorsaveinputs', + name='world_int_rate', + field=webapp.apps.taxbrain.models.CommaSeparatedField(default=None, max_length=200, null=True, blank=True), + ), + ] diff --git a/webapp/apps/dynamic/models.py b/webapp/apps/dynamic/models.py index b782c6e6..3aded5c7 100644 --- a/webapp/apps/dynamic/models.py +++ b/webapp/apps/dynamic/models.py @@ -24,6 +24,8 @@ class DynamicSaveInputs(models.Model): """ # Parameters used for the dynamic model + small_open = models.NullBooleanField(default=None, blank=True, null=True) + world_int_rate = CommaSeparatedField(default=None, null=True, blank=True) g_y_annual = CommaSeparatedField(default=None, null=True, blank=True) g_y_annual_cpi = models.NullBooleanField(default=None, blank=True, null=True) upsilon = CommaSeparatedField(default=None, null=True, blank=True) @@ -62,6 +64,8 @@ class DynamicBehaviorSaveInputs(models.Model): """ # Behavioral Effects + small_open = models.NullBooleanField(default=None, blank=True, null=True) + world_int_rate = CommaSeparatedField(default=None, null=True, blank=True) BE_inc = CommaSeparatedField(default=None, blank=True, null=True) BE_sub = CommaSeparatedField(default=None, blank=True, null=True) BE_cg = CommaSeparatedField(default=None, blank=True, null=True) @@ -99,6 +103,9 @@ class DynamicElasticitySaveInputs(models.Model): """ # Elasticity of GDP w.r.t. average marginal tax rates + small_open = models.NullBooleanField(default=None, blank=True, null=True) + world_int_rate = CommaSeparatedField(default=None, null=True, blank=True) + elastic_gdp = CommaSeparatedField(default=None, blank=True, null=True) # Job IDs when running a job diff --git a/webapp/apps/dynamic/ogusa_parameters.json b/webapp/apps/dynamic/ogusa_parameters.json index 2572d61a..d23f66e0 100644 --- a/webapp/apps/dynamic/ogusa_parameters.json +++ b/webapp/apps/dynamic/ogusa_parameters.json @@ -1 +1,50 @@ -{"g_y_annual": {"col_label": ["Growth rate of technology"], "description": "This parameter gives the underlying growth rate for labor augmenting technological change. The growth rate determines long-run economic growth in OG-USA.", "irs_ref": "", "notes": "", "value": 0.03, "long_name": "Growth rate of technology"}, "frisch": {"col_label": ["Frisch elasticity"], "description": "The Frisch elasticity gives the elasticity of labor supply to changes in the net of tax wage rate, holding wealth constant. This means that the Frisch elasticity captures the substitution effects, but not the income effects, of a change in the net of tax wage rate. A Frisch elasticity of 0.4 would indicate that if the net of tax wage rate increases by 10% then hours worked would increase by 4%, if wealth were held constant. Note that OG-USA uses an elliptical utility function for labor supply. We parameterize this function to fit a constant Frisch elasticity function with a Frisch elasticity as input here.", "irs_ref": "", "notes": "", "validations": {"max": 0.8, "min": 0.1}, "value": 0.4, "long_name": "Frisch elastictiy of labor supply used to fit elliptical utility"}} \ No newline at end of file +{ + "g_y_annual": { + "col_label": [ + "Growth rate of technology" + ], + "description": "This parameter gives the underlying growth rate for labor augmenting technological change. The growth rate determines long-run economic growth in OG-USA.", + "long_name": "Growth rate of technology", + "notes": "", + "value": 0.03, + "irs_ref": "" + }, + "frisch": { + "col_label": [ + "Frisch elasticity" + ], + "description": "The Frisch elasticity gives the elasticity of labor supply to changes in the net of tax wage rate, holding wealth constant. This means that the Frisch elasticity captures the substitution effects, but not the income effects, of a change in the net of tax wage rate. A Frisch elasticity of 0.4 would indicate that if the net of tax wage rate increases by 10% then hours worked would increase by 4%, if wealth were held constant. Note that OG-USA uses an elliptical utility function for labor supply. We parameterize this function to fit a constant Frisch elasticity function with a Frisch elasticity as input here.", + "long_name": "Frisch elastictiy of labor supply used to fit elliptical utility", + "notes": "", + "validations": { + "max": 0.8, + "min": 0.1 + }, + "value": 0.4, + "irs_ref": "" + }, + "world_int_rate": { + "col_label": [ + "World interest rate if using 'small open' economy" + ], + "description": "TODO description", + "long_name": "TODO long_name", + "notes": "TODO notes", + "validations": { + "max": 0.8, + "min": -0.8 + }, + "value": 0.4, + "irs_ref": "" + }, + "small_open": { + "col_label": [ + "Use 'small open' economy" + ], + "description": "TODO description", + "long_name": "TODO long_name", + "notes": "TODO notes", + "value": true, + "irs_ref": "" + } +} \ No newline at end of file diff --git a/webapp/apps/dynamic/ogusa_user_modifiable.json b/webapp/apps/dynamic/ogusa_user_modifiable.json index e4ecc1c5..66cbafc5 100644 --- a/webapp/apps/dynamic/ogusa_user_modifiable.json +++ b/webapp/apps/dynamic/ogusa_user_modifiable.json @@ -1 +1 @@ -{"USER_MODIFIABLE_PARAMS": ["g_y_annual", "frisch"]} \ No newline at end of file +{"USER_MODIFIABLE_PARAMS": ["g_y_annual", "frisch", "word_int_rate"]} \ No newline at end of file From a57bae1cd7e8188b8958a58efdfb30a277ef05bb Mon Sep 17 00:00:00 2001 From: Peter Steinberg Date: Fri, 13 Oct 2017 14:32:01 -0700 Subject: [PATCH 2/3] changes to parameters --- webapp/apps/dynamic/ogusa_parameters.json | 15 ++++++++------- .../0055_remove_taxsaveinputs_reform_style.py | 18 ++++++++++++++++++ 2 files changed, 26 insertions(+), 7 deletions(-) create mode 100644 webapp/apps/taxbrain/migrations/0055_remove_taxsaveinputs_reform_style.py diff --git a/webapp/apps/dynamic/ogusa_parameters.json b/webapp/apps/dynamic/ogusa_parameters.json index d23f66e0..925dcf11 100644 --- a/webapp/apps/dynamic/ogusa_parameters.json +++ b/webapp/apps/dynamic/ogusa_parameters.json @@ -25,26 +25,27 @@ }, "world_int_rate": { "col_label": [ - "World interest rate if using 'small open' economy" + "World interest rate" ], - "description": "TODO description", - "long_name": "TODO long_name", - "notes": "TODO notes", + "description": "World interest rate", + "long_name": "World interest rate if using 'small open' economy", + "notes": "World interest rate if using 'small open' economy", "validations": { "max": 0.8, "min": -0.8 }, - "value": 0.4, + "value": 0.04, "irs_ref": "" }, "small_open": { "col_label": [ "Use 'small open' economy" ], - "description": "TODO description", + "description": "Small open economy assumptionx", "long_name": "TODO long_name", "notes": "TODO notes", "value": true, "irs_ref": "" } -} \ No newline at end of file +} + diff --git a/webapp/apps/taxbrain/migrations/0055_remove_taxsaveinputs_reform_style.py b/webapp/apps/taxbrain/migrations/0055_remove_taxsaveinputs_reform_style.py new file mode 100644 index 00000000..afa875f0 --- /dev/null +++ b/webapp/apps/taxbrain/migrations/0055_remove_taxsaveinputs_reform_style.py @@ -0,0 +1,18 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import models, migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('taxbrain', '0054_outputurl_webapp_vers'), + ] + + operations = [ + migrations.RemoveField( + model_name='taxsaveinputs', + name='reform_style', + ), + ] From bf9e7b4c007e27c126dca7c07767529b72ace410 Mon Sep 17 00:00:00 2001 From: Peter Steinberg Date: Tue, 17 Oct 2017 17:11:07 -0700 Subject: [PATCH 3/3] fixes in forms.py corresponding to models.py --- webapp/apps/dynamic/forms.py | 110 +++++------------- webapp/apps/dynamic/helpers.py | 4 +- .../apps/dynamic/ogusa_user_modifiable.json | 2 +- 3 files changed, 34 insertions(+), 82 deletions(-) diff --git a/webapp/apps/dynamic/forms.py b/webapp/apps/dynamic/forms.py index 8f3fc37d..23ab43f7 100644 --- a/webapp/apps/dynamic/forms.py +++ b/webapp/apps/dynamic/forms.py @@ -185,34 +185,40 @@ class Meta: exclude = ['creation_date'] widgets = {} labels = {} - for param in ELASTICITY_DEFAULT_PARAMS.values(): - for field in param.col_fields: - attrs = { - 'class': 'form-control', - 'placeholder': field.default_value, - } - - if param.coming_soon: - attrs['disabled'] = True - attrs['checked'] = False - widgets[field.id] = forms.CheckboxInput(attrs=attrs, check_test=bool_like) - else: - widgets[field.id] = forms.TextInput(attrs=attrs) + _update_widgets(widgets, OGUSA_DEFAULT_PARAMS) + + +def _update_widgets(widgets, defaults): + boolean_fields = [ + "world_int_rate" + ] + + for param in defaults.values(): + for field in param.col_fields: + attrs = { + 'class': 'form-control', + 'placeholder': field.default_value, + } - labels[field.id] = field.label + if param.tc_id in boolean_fields: + checkbox = forms.CheckboxInput(attrs=attrs, check_test=bool_like) + widgets[field.id] = checkbox + else: + widgets[field.id] = forms.TextInput(attrs=attrs) - if param.inflatable: - field = param.cpi_field - attrs = { - 'class': 'form-control sr-only', - 'placeholder': bool(field.default_value), - } + labels[field.id] = field.label - if param.coming_soon: - attrs['disabled'] = True + if param.inflatable: + field = param.cpi_field + attrs = { + 'class': 'form-control sr-only', + 'placeholder': bool(field.default_value), + } - widgets[field.id] = forms.NullBooleanSelect(attrs=attrs) + if param.coming_soon: + attrs['disabled'] = True + widgets[field.id] = forms.NullBooleanSelect(attrs=attrs) class DynamicBehavioralInputsModelForm(ModelForm): @@ -380,33 +386,7 @@ class Meta: exclude = ['creation_date'] widgets = {} labels = {} - for param in BEHAVIOR_DEFAULT_PARAMS.values(): - for field in param.col_fields: - attrs = { - 'class': 'form-control', - 'placeholder': field.default_value, - } - - if param.coming_soon: - attrs['disabled'] = True - attrs['checked'] = False - widgets[field.id] = forms.CheckboxInput(attrs=attrs, check_test=bool_like) - else: - widgets[field.id] = forms.TextInput(attrs=attrs) - - labels[field.id] = field.label - - if param.inflatable: - field = param.cpi_field - attrs = { - 'class': 'form-control sr-only', - 'placeholder': bool(field.default_value), - } - - if param.coming_soon: - attrs['disabled'] = True - - widgets[field.id] = forms.NullBooleanSelect(attrs=attrs) + _update_widgets(widgets, BEHAVIOR_DEFAULT_PARAMS) class DynamicInputsModelForm(ModelForm): @@ -568,40 +548,12 @@ def do_taxcalc_validations(self): int_to_nth(i + 1), source, mins[i])) - - class Meta: model = DynamicSaveInputs exclude = ['creation_date'] widgets = {} labels = {} - for param in OGUSA_DEFAULT_PARAMS.values(): - for field in param.col_fields: - attrs = { - 'class': 'form-control', - 'placeholder': field.default_value, - } - - if param.coming_soon: - attrs['disabled'] = True - attrs['checked'] = False - widgets[field.id] = forms.CheckboxInput(attrs=attrs, check_test=bool_like) - else: - widgets[field.id] = forms.TextInput(attrs=attrs) - - labels[field.id] = field.label - - if param.inflatable: - field = param.cpi_field - attrs = { - 'class': 'form-control sr-only', - 'placeholder': bool(field.default_value), - } - - if param.coming_soon: - attrs['disabled'] = True - - widgets[field.id] = forms.NullBooleanSelect(attrs=attrs) + _update_widgets(widgets, OGUSA_DEFAULT_PARAMS) def has_field_errors(form): diff --git a/webapp/apps/dynamic/helpers.py b/webapp/apps/dynamic/helpers.py index 7a9f9d85..f03fe6db 100644 --- a/webapp/apps/dynamic/helpers.py +++ b/webapp/apps/dynamic/helpers.py @@ -257,8 +257,8 @@ def dynamic_params_from_model(model): "ogusa_parameters.json") with open(ogusa_params_path, "r") as f: OGUSA_PARAMS = json.load(f) - - params = {k:inputs[k] for k in USER_MODIFIABLE_PARAMS} + defaults = {'world_int_rate': 0.4} + params = {k:inputs.get(k, defaults[k]) for k in USER_MODIFIABLE_PARAMS} for k, v in params.items(): if v == '': diff --git a/webapp/apps/dynamic/ogusa_user_modifiable.json b/webapp/apps/dynamic/ogusa_user_modifiable.json index 66cbafc5..cde7a931 100644 --- a/webapp/apps/dynamic/ogusa_user_modifiable.json +++ b/webapp/apps/dynamic/ogusa_user_modifiable.json @@ -1 +1 @@ -{"USER_MODIFIABLE_PARAMS": ["g_y_annual", "frisch", "word_int_rate"]} \ No newline at end of file +{"USER_MODIFIABLE_PARAMS": ["g_y_annual", "frisch", "world_int_rate"]} \ No newline at end of file