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/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/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..925dcf11 100644 --- a/webapp/apps/dynamic/ogusa_parameters.json +++ b/webapp/apps/dynamic/ogusa_parameters.json @@ -1 +1,51 @@ -{"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" + ], + "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.04, + "irs_ref": "" + }, + "small_open": { + "col_label": [ + "Use 'small open' economy" + ], + "description": "Small open economy assumptionx", + "long_name": "TODO long_name", + "notes": "TODO notes", + "value": true, + "irs_ref": "" + } +} + diff --git a/webapp/apps/dynamic/ogusa_user_modifiable.json b/webapp/apps/dynamic/ogusa_user_modifiable.json index e4ecc1c5..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"]} \ No newline at end of file +{"USER_MODIFIABLE_PARAMS": ["g_y_annual", "frisch", "world_int_rate"]} \ 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', + ), + ]