modelflowib 2.73__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- modelBLfunk.py +180 -0
- model_Excel.py +332 -0
- model_cvx.py +139 -0
- model_dynare.py +173 -0
- model_financial_stability.py +88 -0
- model_latex.py +497 -0
- model_latex_class.py +808 -0
- model_parquet_mixin.py +424 -0
- modelclass.py +9828 -0
- modelconstruct.py +1496 -0
- modelconstruct_estimation.py +2872 -0
- modeldash.py +265 -0
- modeldashboot.py +202 -0
- modeldashsidebar.py +456 -0
- modeldekom.py +651 -0
- modeldiff.py +561 -0
- modeldisplay.py +550 -0
- modelestimation.py +1776 -0
- modelestimator_new.py +2613 -0
- modelflowib-2.73.dist-info/METADATA +156 -0
- modelflowib-2.73.dist-info/RECORD +44 -0
- modelflowib-2.73.dist-info/WHEEL +5 -0
- modelflowib-2.73.dist-info/licenses/license.md +10 -0
- modelflowib-2.73.dist-info/top_level.txt +39 -0
- modelgrab.py +318 -0
- modelgrabgdx.py +584 -0
- modelgrabwf2.py +1107 -0
- modelhelp.py +543 -0
- modelhtml.py +606 -0
- modelinvert.py +250 -0
- modeljupyter.py +824 -0
- modeljupytermagic.py +813 -0
- modelmacrograb.py +98 -0
- modelmanipulation.py +1461 -0
- modelmf.py +349 -0
- modelnet.py +114 -0
- modelnewton.py +2178 -0
- modelnormalize.py +430 -0
- modelpattern.py +428 -0
- modelreport.py +2187 -0
- modeluserfunk.py +97 -0
- modelvis.py +1038 -0
- modelwidget.py +718 -0
- modelwidget_input.py +1933 -0
modelgrabwf2.py
ADDED
|
@@ -0,0 +1,1107 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
"""
|
|
3
|
+
Created on Wed Mar 30 10:06:26 2022
|
|
4
|
+
|
|
5
|
+
@author: ibhan
|
|
6
|
+
|
|
7
|
+
Module to handle models in wf1 files
|
|
8
|
+
|
|
9
|
+
#. Eviews is started and the wf1 file is loaded.
|
|
10
|
+
|
|
11
|
+
#. Some transformations are performed on data.
|
|
12
|
+
#. The model is unlinked.
|
|
13
|
+
#. The workspace is saved as a wf2 file. Same name with _modelflow appended.
|
|
14
|
+
#. Eviews is closed
|
|
15
|
+
#. The wf2 file is read as a json file.
|
|
16
|
+
#. Relevant objects are extracted.
|
|
17
|
+
#. The MFMSA variable is extracted, to be saved in the dumpfile.
|
|
18
|
+
#. The equations are transformed and normalized to modelflow format and classified into identities and stochastic
|
|
19
|
+
#. Stochastic equations are enriched by add_factor and fixing terms (dummy + fixing value)
|
|
20
|
+
#. For Stochastic equations new fitted variables are generated - without add add_factors and dummies.
|
|
21
|
+
#. A model to generate fitted variables is created
|
|
22
|
+
#. A model to generate add_factors is created.
|
|
23
|
+
#. A model encompassing the original equations, the model for fitted variables and for add_factors is created.
|
|
24
|
+
#. The data series and scalars are shoveled into a Pandas dataframe
|
|
25
|
+
|
|
26
|
+
#. Some special series are generated as the expression can not be incorporated into modelflow model specifications
|
|
27
|
+
#. The model for fitted values is simulated in the specified timespan
|
|
28
|
+
#. The model for add_factors is simulated in the timespan set in MFMSA
|
|
29
|
+
#. The data descriptions are extracted into a dictionary.
|
|
30
|
+
#. Data descriptions for dummies, fixed values, fitted values and add_factors are derived.
|
|
31
|
+
#. Now we have a model and a dataframe with all variables which are needed.
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
"""
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
import pandas as pd
|
|
38
|
+
import re
|
|
39
|
+
from dataclasses import dataclass, field
|
|
40
|
+
import functools
|
|
41
|
+
from tqdm import tqdm
|
|
42
|
+
import json
|
|
43
|
+
from pathlib import Path
|
|
44
|
+
import gzip
|
|
45
|
+
import warnings
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
from modelclass import model
|
|
49
|
+
import modelmf
|
|
50
|
+
import modelmanipulation as mp
|
|
51
|
+
|
|
52
|
+
import modelnormalize as nz
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def remove_url_and_replace_nbsp(s):
|
|
56
|
+
# Regular expression for matching URLs
|
|
57
|
+
url_pattern = r'http[s]?://(?:[a-zA-Z]|[0-9]|[$-_@.&+]|[!*(),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+'
|
|
58
|
+
# Replace the URL with an empty string and \xa0 with a space
|
|
59
|
+
return re.sub(url_pattern, '', s).replace('\xa0', ' ').strip()
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def wf1_to_wf2(filename,modelname='',eviews_run_lines= []):
|
|
63
|
+
'''
|
|
64
|
+
- Opens a eviews workfile in wf1 format
|
|
65
|
+
- calculates the eviews_trend
|
|
66
|
+
- unlink a model and
|
|
67
|
+
- writes the workspace back to a wf2 file
|
|
68
|
+
|
|
69
|
+
Args:
|
|
70
|
+
filename (TYPE): DESCRIPTION.
|
|
71
|
+
modelname (TYPE): default '' then the three first letters of the filenames stem are asumed to be the modelname.
|
|
72
|
+
|
|
73
|
+
Returns:
|
|
74
|
+
None.
|
|
75
|
+
|
|
76
|
+
'''
|
|
77
|
+
try:
|
|
78
|
+
import py2eviews as evp
|
|
79
|
+
except:
|
|
80
|
+
try:
|
|
81
|
+
import pyeviews as evp
|
|
82
|
+
print('You have installed pyewiews not py2eviews it may works but try:\n'+
|
|
83
|
+
'!conda install py2eviews -c -c eviews -y')
|
|
84
|
+
except:
|
|
85
|
+
raise Exception('You have not py2eviews installed try:\n'+
|
|
86
|
+
'!conda install py2eviews -c -c eviews -y')
|
|
87
|
+
from pathlib import Path
|
|
88
|
+
wfpath = Path(filename)
|
|
89
|
+
if wfpath.suffix not in {'.wf1','.wf2'} :
|
|
90
|
+
raise Exception(f'wf1_to_wf2 expects a .wf1 file as input\nOffending:{wfpath} {wfpath.suffix} ')
|
|
91
|
+
else:
|
|
92
|
+
wf1= wfpath.absolute()
|
|
93
|
+
# wf2 = wf1.with_suffix('.wf2')
|
|
94
|
+
wf2 = (wf1.resolve().parent / (wf1.stem + '_modelflow')).with_suffix('.wf2')
|
|
95
|
+
# breakpoint()
|
|
96
|
+
eviewsapp = evp.GetEViewsApp(instance='new',showwindow=True)
|
|
97
|
+
print(f'\nReading {wf1}')
|
|
98
|
+
if modelname == '':
|
|
99
|
+
modelname = wf1.stem[:3].upper()
|
|
100
|
+
print(f'Assummed model name: {modelname}')
|
|
101
|
+
|
|
102
|
+
evp.Run(fr'wfopen "{wf1}"',eviewsapp)
|
|
103
|
+
evp.Run( r'smpl @all',eviewsapp)
|
|
104
|
+
evp.Run( r'series eviews_trend = @TREND',eviewsapp)
|
|
105
|
+
for eviewsline in eviews_run_lines:
|
|
106
|
+
print(f'Eviewsline to run :{eviewsline}')
|
|
107
|
+
evp.Run(eviewsline,eviewsapp)
|
|
108
|
+
evp.Run(f'{modelname}.unlink @all',eviewsapp)
|
|
109
|
+
print(f'The model: {modelname} is unlinked ')
|
|
110
|
+
evp.Run(fr'wfsave(jf) "{wf2}"',eviewsapp)
|
|
111
|
+
print(f'Writing {wf2}')
|
|
112
|
+
|
|
113
|
+
eviewsapp.hide()
|
|
114
|
+
eviewsapp = None
|
|
115
|
+
evp.Cleanup()
|
|
116
|
+
return wf2,modelname
|
|
117
|
+
|
|
118
|
+
def wf2_to_clean(wf2name,modelname='',save_file = False,freq='A'):
|
|
119
|
+
'''
|
|
120
|
+
Takes a eviews .wf2 file - which is in JSON format - and place a
|
|
121
|
+
dictionary
|
|
122
|
+
|
|
123
|
+
Args:
|
|
124
|
+
wf2name (TYPE): name of wf2 file .
|
|
125
|
+
modelname (TYPE, optional): Name og model. Defaults to ''.
|
|
126
|
+
save_file (TYPE, optional): save the specification, data and description in a dictionary. Defaults to False.
|
|
127
|
+
|
|
128
|
+
Returns:
|
|
129
|
+
model_all_about (dict): the content of the wf2 file as a dict .
|
|
130
|
+
|
|
131
|
+
'''
|
|
132
|
+
model_all_about = {}
|
|
133
|
+
|
|
134
|
+
if modelname == '':
|
|
135
|
+
modelname = wf2name.stem[:3]
|
|
136
|
+
print(f'Assummed model name: {modelname}')
|
|
137
|
+
else:
|
|
138
|
+
print(f'Model name: {modelname}')
|
|
139
|
+
# with open(wf2name) as f:
|
|
140
|
+
with gzip.open(wf2name, mode="rt") as f:
|
|
141
|
+
|
|
142
|
+
gen0 = f.read()
|
|
143
|
+
# gen0 = gen0.decode("ISO-8859-1")
|
|
144
|
+
all_dict = json.loads(gen0)
|
|
145
|
+
pages = all_dict['_pages']
|
|
146
|
+
matched_page = [page for page in pages
|
|
147
|
+
if page["frequency"]["value"]== freq]
|
|
148
|
+
|
|
149
|
+
if (len_matched_page := len(matched_page)) != 1:
|
|
150
|
+
raise Exception(f'{len_matched_page} pages in the workfile with frequence {freq}. Precise one is allowed')
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
first_page = matched_page[0]
|
|
154
|
+
object_all = [o for o in first_page['_objects']]
|
|
155
|
+
types_set = {o['_type'] for o in object_all}
|
|
156
|
+
object_dict = {_type : [o for o in object_all if o['_type'] == _type ] for _type in types_set}
|
|
157
|
+
object_namecounts = {_type: [o['_name'] for o in this_object] for _type,this_object in object_dict.items() }
|
|
158
|
+
# breakpoint()
|
|
159
|
+
# Now extract the model
|
|
160
|
+
try:
|
|
161
|
+
thismodel_dict = object_dict['model'][0]
|
|
162
|
+
thismodel_raw = thismodel_dict['data'][0]
|
|
163
|
+
# breakpoint()
|
|
164
|
+
thismodel_raw_list = [l for l in thismodel_raw.split('\n') if len(l) > 1]
|
|
165
|
+
|
|
166
|
+
this_clean = [l for l in thismodel_raw_list if l[:4] not in {'@INN','@ADD'}] # The original frmls
|
|
167
|
+
this_add_vars = [l.split()[1] for l in thismodel_raw_list if l[:4] in {'@ADD'}] # variable with add factors
|
|
168
|
+
this_frml = '\n'.join(this_clean)
|
|
169
|
+
except:
|
|
170
|
+
this_frml = ''
|
|
171
|
+
# Take all series and make a dataframe
|
|
172
|
+
series_list = object_dict['series_double']
|
|
173
|
+
|
|
174
|
+
if freq == 'A':
|
|
175
|
+
index = [int(d[:4]) for d in object_dict['index'][0]['data']]
|
|
176
|
+
elif freq == 'Q':
|
|
177
|
+
datetime_index = pd.to_datetime( object_dict['index'][0]['data'])
|
|
178
|
+
index = datetime_index.to_period('Q')
|
|
179
|
+
|
|
180
|
+
series_data = [pd.Series(s['data'],name=s['_name'],index=index) for s in series_list]
|
|
181
|
+
|
|
182
|
+
wf_df = pd.concat(series_data,axis=1)
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
var_description = {s['_name']: lab2 for s in series_list
|
|
186
|
+
if (lab2 := s.get('_labels',{}).get('description',''))
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
var_description = {k: remove_url_and_replace_nbsp(v) for k,v in var_description.items() }
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
scalar_list = object_dict['scalar']
|
|
193
|
+
# for scalar in scalar_list:
|
|
194
|
+
# if 'value' in scalar.keys():
|
|
195
|
+
# wf_df.loc[:,scalar['_name']] = scalar['value']
|
|
196
|
+
scalar_data = [pd.Series(s['value'],name=s['_name'],index=index)
|
|
197
|
+
for s in scalar_list if 'value' in s.keys()]
|
|
198
|
+
# breakpoint()
|
|
199
|
+
wf_df = pd.concat([wf_df]+scalar_data,axis=1)
|
|
200
|
+
string_list = object_dict['stringobj']
|
|
201
|
+
# breakpoint()
|
|
202
|
+
mfmsa_dict = {o['_name']:o.get('value','empty') for o in string_list if o.get('_name','').startswith('MFMSA') }
|
|
203
|
+
mfmsa_options = mfmsa_dict.get('MFMSAOPTIONS','')
|
|
204
|
+
|
|
205
|
+
try:
|
|
206
|
+
estimates = {eq['_name'].upper()+f'.@COEF({idata+1})': str(data)
|
|
207
|
+
for eq in object_dict['equation7'] for idata,data in enumerate(eq['results']['data']) }
|
|
208
|
+
except:
|
|
209
|
+
estimates = {}
|
|
210
|
+
|
|
211
|
+
# breakpoint()
|
|
212
|
+
model_all_about['modelname'] = modelname
|
|
213
|
+
model_all_about['frml'] = this_frml
|
|
214
|
+
model_all_about['mfmsa_options'] = mfmsa_options
|
|
215
|
+
model_all_about['var_description'] = var_description
|
|
216
|
+
model_all_about['data'] = wf_df
|
|
217
|
+
model_all_about['object_dict_from_wf'] = object_dict
|
|
218
|
+
model_all_about['estimates'] = estimates
|
|
219
|
+
|
|
220
|
+
|
|
221
|
+
if save_file:
|
|
222
|
+
with open(f'{wf2name.parent / modelname}_clean.frm','wt') as f:
|
|
223
|
+
f.writelines(this_clean)
|
|
224
|
+
with open(f'{wf2name.parent / modelname}_mfmsa_options','wt') as f:
|
|
225
|
+
f.write(mfmsa_options)
|
|
226
|
+
with open(f'{wf2name.parent / modelname}_var_descriptions.json','wt') as f:
|
|
227
|
+
json.dump(var_description,f,indent=4)
|
|
228
|
+
wf_df.to_excel(f'{wf2name.parent / modelname}soln.xlsx')
|
|
229
|
+
print(f'{wf2name.parent / modelname}.... files are saved')
|
|
230
|
+
|
|
231
|
+
return model_all_about
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
|
|
235
|
+
@dataclass
|
|
236
|
+
class GrabWfModel():
|
|
237
|
+
"""
|
|
238
|
+
This class takes a World Bank model specification, variable data, and variable description,
|
|
239
|
+
and transforms it into ModelFlow business language.
|
|
240
|
+
|
|
241
|
+
Args:
|
|
242
|
+
filename : any = '' # wf1 name
|
|
243
|
+
modelname : any = ''
|
|
244
|
+
freq : str = 'A'
|
|
245
|
+
eviews_run_lines : list = field(default_factory=list)
|
|
246
|
+
model_all_about : dict = field(default_factory=dict)
|
|
247
|
+
start : any = None # start of testing if not overruled by mfmsa
|
|
248
|
+
end : any = None # end of testing if not overruled by mfmsa
|
|
249
|
+
country_trans : any = lambda x:x[:] # function which transforms model specification
|
|
250
|
+
country_df_trans : any = lambda x:x # function which transforms initial dataframe
|
|
251
|
+
make_fitted : bool = False # if True, a clean equation for fitted variables is created
|
|
252
|
+
fit_start : any = 2000 # start of fitted model
|
|
253
|
+
fit_end : any = None # end of fitted model unless overruled by mfmsa
|
|
254
|
+
do_add_factor_calc : bool = True # calculate the add factors
|
|
255
|
+
test_frml : str = '' # a test model as string; if used, no wf processing
|
|
256
|
+
disable_progress : bool = False # disable progress bar
|
|
257
|
+
save_file : bool = False # save information to file
|
|
258
|
+
model_description : str = '' # model description
|
|
259
|
+
cty : str = '' # country ISO code like PAK, defaults to first 3 letters of modelname
|
|
260
|
+
cty_name : str = '' # country name like Pakistan, default via ISO mapping
|
|
261
|
+
var_groups : dict = field(default_factory=dict, init=False) # variable groups
|
|
262
|
+
extra_var_descriptions : dict = field(default_factory=dict) # extra variable descriptions
|
|
263
|
+
|
|
264
|
+
Methods:
|
|
265
|
+
__post_init__():
|
|
266
|
+
Initialize and process the model, transform equations, perform syntax checks,
|
|
267
|
+
and set up the model and data for simulation and analysis.
|
|
268
|
+
|
|
269
|
+
print_frml(pat='*', eviews=''):
|
|
270
|
+
Print model equations matching a wildcard pattern and optional EViews content filter.
|
|
271
|
+
|
|
272
|
+
trans_eviews(rawmodel):
|
|
273
|
+
(staticmethod) Convert EViews-style equations into ModelFlow syntax.
|
|
274
|
+
|
|
275
|
+
var_description (property):
|
|
276
|
+
Return enriched variable descriptions combining WF1 file, WB defaults, and extras.
|
|
277
|
+
|
|
278
|
+
wb_default_descriptions (property):
|
|
279
|
+
Load default World Bank variable descriptions from an online repository.
|
|
280
|
+
|
|
281
|
+
mfmsa_options (property):
|
|
282
|
+
Return the raw MFMSA options XML string.
|
|
283
|
+
|
|
284
|
+
mfmsa_options_dict (property):
|
|
285
|
+
Parse and return MFMSA options as a nested dictionary.
|
|
286
|
+
|
|
287
|
+
mfmsa_start_end (property):
|
|
288
|
+
Retrieve start and end periods from MFMSA metadata.
|
|
289
|
+
|
|
290
|
+
mfmsa_country (property):
|
|
291
|
+
Retrieve the country ISO code from MFMSA metadata.
|
|
292
|
+
|
|
293
|
+
mfmsa_quasiIdentities (property):
|
|
294
|
+
Return a set of quasi-identity variable names from MFMSA.
|
|
295
|
+
|
|
296
|
+
var_groups_default (property):
|
|
297
|
+
Provide default variable groupings for World Bank models.
|
|
298
|
+
|
|
299
|
+
dfmodel (property):
|
|
300
|
+
Return the transformed and enriched dataframe for model calculation.
|
|
301
|
+
|
|
302
|
+
__call__():
|
|
303
|
+
Return the processed model object and base input dataframe.
|
|
304
|
+
|
|
305
|
+
test_model(start=None, end=None, maxvar=1_000_000, maxerr=100, tol=0.0001,
|
|
306
|
+
showall=False, showinput=False, nofit=True):
|
|
307
|
+
Compare model calculations against input data to validate model fidelity.
|
|
308
|
+
|
|
309
|
+
iso_countries (property):
|
|
310
|
+
Return a dictionary mapping ISO country codes to country names.
|
|
311
|
+
"""
|
|
312
|
+
|
|
313
|
+
filename : any = '' #wf1 name
|
|
314
|
+
modelname : any = ''
|
|
315
|
+
freq : str = 'A'
|
|
316
|
+
eviews_run_lines : list =field(default_factory=list)
|
|
317
|
+
start : any = None # start of testing if not overruled by mfmsa
|
|
318
|
+
end : any = None # end of testing if not overruled by mfmsa
|
|
319
|
+
country_trans : any = lambda x:x[:] # function which transform model specification
|
|
320
|
+
country_df_trans : any = lambda x:x # function which transforms initial dataframe
|
|
321
|
+
make_fitted : bool = False # if True, a clean equation for fittet variables is created
|
|
322
|
+
fit_start : any = 2000 # start of fittet model
|
|
323
|
+
fit_end : any = None # end of fittet model unless overruled by mfmsa
|
|
324
|
+
do_add_factor_calc : bool = True # calculate the add factors
|
|
325
|
+
test_frml : str ='' # a testmodel as string if used no wf processing
|
|
326
|
+
disable_progress : bool = False # Disable progress bar
|
|
327
|
+
save_file : bool = False # save information to file
|
|
328
|
+
model_description : str = '' # model description
|
|
329
|
+
cty : str = '' # country prefix like PAK
|
|
330
|
+
cty_name : str = '' # country name like Pakistan
|
|
331
|
+
var_groups : dict = field(default_factory=dict)
|
|
332
|
+
extra_var_descriptions : dict = field(default_factory=dict)
|
|
333
|
+
|
|
334
|
+
model_all_about : dict = field(default_factory=dict,init=False)
|
|
335
|
+
|
|
336
|
+
def __post_init__(self):
|
|
337
|
+
'''Process the model'''
|
|
338
|
+
|
|
339
|
+
if self.test_frml:
|
|
340
|
+
self.rawmodel_org =self.test_frml
|
|
341
|
+
self.modelname = self.modelname if self.modelname else 'Test'
|
|
342
|
+
self.cty = self.cty if self.cty else 'XXX'
|
|
343
|
+
self.cty_name = self.cty_name if self.cty_name else 'Text country'
|
|
344
|
+
else:
|
|
345
|
+
# breakpoint()
|
|
346
|
+
wf2name,self.modelname = wf1_to_wf2(self.filename ,modelname=self.modelname,eviews_run_lines= self.eviews_run_lines)
|
|
347
|
+
self.model_all_about = wf2_to_clean(wf2name,modelname=self.modelname,save_file= self.save_file,freq=self.freq)
|
|
348
|
+
|
|
349
|
+
print(f'\nProcessing the model:{self.modelname}',flush=True)
|
|
350
|
+
self.rawmodel_org = self.model_all_about['frml']
|
|
351
|
+
|
|
352
|
+
|
|
353
|
+
eviewsline = [l.strip() for l in self.rawmodel_org.split('\n')[:] ]
|
|
354
|
+
|
|
355
|
+
if '.@coef(' in self.rawmodel_org :
|
|
356
|
+
print('Estimated coifficients are substituted')
|
|
357
|
+
self.rawmodel_org = self.rawmodel_org.upper()
|
|
358
|
+
for k,v in self.model_all_about['estimates'].items():
|
|
359
|
+
self.rawmodel_org = self.rawmodel_org.replace(k,v)
|
|
360
|
+
|
|
361
|
+
self.rawmodel = self.country_trans(self.rawmodel_org)
|
|
362
|
+
rawmodel6 = self.trans_eviews(self.rawmodel)
|
|
363
|
+
bars = '{desc}: {percentage:3.0f}%|{bar}|{n_fmt}/{total_fmt}'
|
|
364
|
+
|
|
365
|
+
orgline = rawmodel6.split('\n')
|
|
366
|
+
line_type = ['ident' if l.strip().startswith('@IDENTITY') else 'stoc' for l in orgline]
|
|
367
|
+
line = [l.replace('@IDENTITY ','').replace(' ','') for l in orgline]
|
|
368
|
+
|
|
369
|
+
# breakpoint()
|
|
370
|
+
print('Check for Eviews @ which are not caught in the translation')
|
|
371
|
+
errline1 = [(l,o,e) for l,o,e in zip(line,orgline,eviewsline) if '@' in l or '.coef' in l ]
|
|
372
|
+
if errline1:
|
|
373
|
+
print('Probably errors as @ in lines:')
|
|
374
|
+
for l,o,e in errline1:
|
|
375
|
+
print(f'\nEviews line :{e}')
|
|
376
|
+
print(f'Original line :{o}')
|
|
377
|
+
print(f'New modelflow line:{l}')
|
|
378
|
+
raise Exception('@ in lines ')
|
|
379
|
+
|
|
380
|
+
self.all_frml = [nz.normal(l,add_add_factor=(typ=='stoc'),make_fitted=(typ=='stoc'),make_fixable =(typ=='stoc'),eviews=e)
|
|
381
|
+
for l,typ,e in tqdm(zip(line,line_type,eviewsline),
|
|
382
|
+
desc='Normalizing model',total=len(line),bar_format=bars,disable=self.disable_progress)]
|
|
383
|
+
|
|
384
|
+
syntaxlines = [f for f in tqdm(self.all_frml,
|
|
385
|
+
desc='Syntax check',total=len(self.all_frml),bar_format=bars,disable=self.disable_progress)
|
|
386
|
+
if not mp.check_syntax_udtryk_new(f.normalized)[0]]
|
|
387
|
+
if len(syntaxlines):
|
|
388
|
+
print(f'{len(syntaxlines)} Syntax errors. In these equations: ')
|
|
389
|
+
for l in syntaxlines:
|
|
390
|
+
err,text = mp.check_syntax_udtryk_new(l.normalized)
|
|
391
|
+
print(text)
|
|
392
|
+
l.fprint
|
|
393
|
+
raise Exception('Syntax error in frml ')
|
|
394
|
+
# print(' ',flush=True)
|
|
395
|
+
|
|
396
|
+
# print([ f.normalized for f in self.all_frml ])
|
|
397
|
+
self.all_frml_dict = {f.endo_var: f for f in self.all_frml}
|
|
398
|
+
lfname = ["<QUASIIDENT> " if typ == 'stoc' and endo_var in self.mfmsa_quasiIdentities else
|
|
399
|
+
"<DAMP,STOC> " if typ == 'stoc' else '<IDENT> '
|
|
400
|
+
for typ,endo_var in zip( line_type,self.all_frml_dict.keys()) ]
|
|
401
|
+
self.rorg = [fname + f.normalized for f,fname in zip(self.all_frml,lfname) ]
|
|
402
|
+
# breakpoint()
|
|
403
|
+
if self.make_fitted:
|
|
404
|
+
self.rfitmodel = ['<FIT> ' + f.fitted for f in self.all_frml if len(f.fitted)]
|
|
405
|
+
self.mfitmodel = model('\n'.join(self.rfitmodel))
|
|
406
|
+
self.mfitmodel.modelname = self.modelname + ' calc fittet values'
|
|
407
|
+
else:
|
|
408
|
+
self.rfitmodel = []
|
|
409
|
+
|
|
410
|
+
self.rres = [f'{f.calc_add_factor}' for f in self.all_frml if len(f.calc_add_factor)]
|
|
411
|
+
self.rres_tomodel ='\n'.join([f'FRML <CALC_ADD_FACTOR> {f.calc_add_factor}$' for f in self.all_frml if len(f.calc_add_factor)])
|
|
412
|
+
# self.fmodel = mp.exounroll(mp.tofrml ('\n'.join(self.rorg+self.rfitmodel)))+self.rres_tomodel
|
|
413
|
+
self.fmodel = mp.tofrml ('\n'.join(self.rorg+self.rfitmodel))+self.rres_tomodel
|
|
414
|
+
# breakpoint()
|
|
415
|
+
self.fres = ('\n'.join(self.rres))
|
|
416
|
+
|
|
417
|
+
var_groups = self.var_groups if self.var_groups else self.var_groups_default
|
|
418
|
+
|
|
419
|
+
self.mmodel = model(self.fmodel,modelname =self.modelname,
|
|
420
|
+
var_groups = var_groups,
|
|
421
|
+
)
|
|
422
|
+
self.mmodel.eviews_dict = {v: f.eviews for v,f in self.all_frml_dict.items()}
|
|
423
|
+
|
|
424
|
+
|
|
425
|
+
if self.cty:
|
|
426
|
+
cty = self.cty
|
|
427
|
+
|
|
428
|
+
else:
|
|
429
|
+
try:
|
|
430
|
+
cty = self.mfmsa_country
|
|
431
|
+
except:
|
|
432
|
+
|
|
433
|
+
cty = self.modelname[:min(len(self.modelname),3)]
|
|
434
|
+
|
|
435
|
+
cty_name = ( self.cty_name if self.cty_name else
|
|
436
|
+
self.iso_countries.get(cty,'No Name') )
|
|
437
|
+
self.mmodel.substitution= {'cty' :cty,
|
|
438
|
+
'cty_name' : cty_name }
|
|
439
|
+
|
|
440
|
+
self.cty = cty
|
|
441
|
+
self.cty_name = cty_name
|
|
442
|
+
|
|
443
|
+
print(f'Country {cty}:{cty_name}')
|
|
444
|
+
self.mmodel.var_description = self.var_description
|
|
445
|
+
self.mmodel.model_description = self.model_description
|
|
446
|
+
|
|
447
|
+
# self.mmodel.set_var_description(self.model_all_about['var_description'])
|
|
448
|
+
|
|
449
|
+
self.mres = model(self.fres,modelname = f'Calculation of add factors for {self.modelname}')
|
|
450
|
+
# breakpoint()
|
|
451
|
+
if self.test_frml:
|
|
452
|
+
...
|
|
453
|
+
print('inspect the test model')
|
|
454
|
+
else:
|
|
455
|
+
try:
|
|
456
|
+
temp_start,temp_end = self.mfmsa_start_end
|
|
457
|
+
except:
|
|
458
|
+
if type(self.start) == type(None) or type(self.end) == type(None):
|
|
459
|
+
raise Exception('Can not read start and end from MFMSA. Provide start and end in call ')
|
|
460
|
+
|
|
461
|
+
self.missing_descriptions = [v for v in sorted(self.mmodel.allvar) if v == self.mmodel.var_description[v]]
|
|
462
|
+
self.start = temp_start if type(self.start) == type(None) else self.start
|
|
463
|
+
self.end = temp_end if type(self.end) == type(None) else self.end
|
|
464
|
+
|
|
465
|
+
try:
|
|
466
|
+
if self.do_add_factor_calc:
|
|
467
|
+
self.base_input = self.mres.res(self.dfmodel,self.start,self.end)
|
|
468
|
+
else:
|
|
469
|
+
self.base_input = self.dfmodel
|
|
470
|
+
except Exception as e:
|
|
471
|
+
import traceback
|
|
472
|
+
...
|
|
473
|
+
print(f'We have a problem {e}')
|
|
474
|
+
traceback.print_exc()
|
|
475
|
+
|
|
476
|
+
|
|
477
|
+
def print_frml(self,pat='*',eviews=''):
|
|
478
|
+
"""
|
|
479
|
+
Print the formatted representation of equations in the model whose endogenous variable
|
|
480
|
+
names match the specified pattern and optionally filter them based on the EViews formula specification.
|
|
481
|
+
|
|
482
|
+
Parameters:
|
|
483
|
+
-----------
|
|
484
|
+
pat : str, optional
|
|
485
|
+
A shell-style wildcard pattern used to filter keys in the `all_frml_dict`.
|
|
486
|
+
Defaults to '*' (matches all keys).
|
|
487
|
+
|
|
488
|
+
eviews : str, optional
|
|
489
|
+
A string used to filter equations based on their EViews formula specification.
|
|
490
|
+
Only equations containing the specified `eviews` string (case-insensitive) will be displayed.
|
|
491
|
+
If not provided, all equations matching the `pat` pattern will be shown.
|
|
492
|
+
|
|
493
|
+
Behavior:
|
|
494
|
+
---------
|
|
495
|
+
- Retrieves endogenous variable names from the `all_frml_dict` dictionary that match the `pat` pattern.
|
|
496
|
+
- If the `eviews` parameter is specified, further filters equations whose EViews formula
|
|
497
|
+
specification contains the `eviews` string (case-insensitive).
|
|
498
|
+
- Calls the `fprint` method for each matching equation to display its transformations.
|
|
499
|
+
|
|
500
|
+
Output:
|
|
501
|
+
-------
|
|
502
|
+
- Prints the equations matching the specified pattern and EViews filter.
|
|
503
|
+
- Displays a message if no matching equations are found.
|
|
504
|
+
"""
|
|
505
|
+
|
|
506
|
+
variables = model.list_names([k for k in self.all_frml_dict.keys()] , pat, sort=True)
|
|
507
|
+
|
|
508
|
+
if eviews:
|
|
509
|
+
variables = [v for v in variables if eviews.upper() in self.all_frml_dict[v].eviews.upper() ]
|
|
510
|
+
|
|
511
|
+
if len(variables):
|
|
512
|
+
print(f'\nEquations in the model matching :{pat}')
|
|
513
|
+
print(f'And where eviews eq contains :{eviews}')
|
|
514
|
+
for v in variables:
|
|
515
|
+
if v in self.var_description:
|
|
516
|
+
print(self.var_description[v])
|
|
517
|
+
self.all_frml_dict[v].fprint
|
|
518
|
+
print('\n')
|
|
519
|
+
else:
|
|
520
|
+
print(f'\nNo Equations in the model matching {pat}')
|
|
521
|
+
|
|
522
|
+
|
|
523
|
+
|
|
524
|
+
|
|
525
|
+
@staticmethod
|
|
526
|
+
def trans_eviews(rawmodel):
|
|
527
|
+
'''
|
|
528
|
+
Takes Eviews specifications and wrangle them into modelflow specifications
|
|
529
|
+
|
|
530
|
+
Args:
|
|
531
|
+
rawmodel (TYPE): a raw model .
|
|
532
|
+
|
|
533
|
+
Returns:
|
|
534
|
+
rawmodel6 (TYPE): a model with the appropiate eviews transformations.
|
|
535
|
+
|
|
536
|
+
'''
|
|
537
|
+
rawmodel0 = '\n'.join(l for l in rawmodel.upper().split('\n') if len(l.strip()) >=2)
|
|
538
|
+
# trailing and leading "
|
|
539
|
+
rawmodel1 = '\n'.join(l[1:-1] if l.startswith('"') else l for l in rawmodel0.split('\n'))
|
|
540
|
+
# powers
|
|
541
|
+
rawmodel2 = rawmodel1.replace('^','**').replace('""',' ').replace('"',' ').\
|
|
542
|
+
replace('@EXP','exp').replace('@RECODE','recode').replace('@MOVAV','movavg').replace('@LOGIT','logit_inverse') \
|
|
543
|
+
.replace('@MEAN(@PC(','@AVERAGE_GROWTH((').replace('@PCY','PCT_GROWTH').replace('@PC','PCT_GROWTH')\
|
|
544
|
+
.replace('@PMAX','MAX').replace('@TREND','EVIEWS_TREND').replace('@ABS','ABS').replace('@SQRT(','SQRT(')\
|
|
545
|
+
.replace('@PMAX(','MAX(') .replace('@CNORM(','NORMCDF(')
|
|
546
|
+
# @ELEM and @DURING
|
|
547
|
+
# @ELEM and @DURING
|
|
548
|
+
rawmodel3 = nz.elem_trans(rawmodel2)
|
|
549
|
+
rawmodel4 = re.sub(r'@DURING\( *([0-9Q]+) *\)', r'during_\1',rawmodel3)
|
|
550
|
+
rawmodel50 = re.sub(r'@DURING\( *([0-9Q]+) *([0-9Q]+) *\)', r'during_\1_\2',rawmodel4)
|
|
551
|
+
rawmodel5 = re.sub(
|
|
552
|
+
r"@BETWEEN\(\s*(\w+)\s*,\s*([^,]+)\s*,\s*([^)]+)\s*\)",
|
|
553
|
+
r"(1.0*float(\2 <= \1 <= \3))",
|
|
554
|
+
rawmodel50
|
|
555
|
+
)
|
|
556
|
+
#rawmodel5 = rawmodel50
|
|
557
|
+
# during check
|
|
558
|
+
ldur = '\n'.join(l for l in rawmodel5.split('\n') if '@DURING' in l)
|
|
559
|
+
ldur2 = '\n'.join(l for l in rawmodel5.split('\n') if 'during' in l)
|
|
560
|
+
|
|
561
|
+
# check D(
|
|
562
|
+
ld = '\n'.join(l for l in rawmodel5.split('\n') if re.search(r'([^A-Z]|^)D\(',l) )
|
|
563
|
+
ld1 = '\n'.join(l for l in rawmodel5.split('\n') if re.search(r'([^A-Z0-9_]|^)D\(',l) )
|
|
564
|
+
# breakpoint()
|
|
565
|
+
rawmodel6 = nz.funk_replace('D','DIFF',rawmodel5)
|
|
566
|
+
# did we get all the lines
|
|
567
|
+
ldif = '\n'.join(l for l in rawmodel6.split('\n') if 'DIFF(' in l )
|
|
568
|
+
return rawmodel6
|
|
569
|
+
|
|
570
|
+
@functools.cached_property
|
|
571
|
+
def var_description(self):
|
|
572
|
+
'''
|
|
573
|
+
Adds var descriptions for add factors, exogenizing dummies and exoggenizing values
|
|
574
|
+
'''
|
|
575
|
+
|
|
576
|
+
|
|
577
|
+
|
|
578
|
+
try:
|
|
579
|
+
this = {k:v for k,v in self.model_all_about['var_description'].items()
|
|
580
|
+
if v!='TEMP' and k in (self.mmodel.endogene | self.mmodel.exogene) }
|
|
581
|
+
print('Variable description in wf1 file read')
|
|
582
|
+
except:
|
|
583
|
+
print(' ')
|
|
584
|
+
print('*** No variable description in wf1 file',flush=True)
|
|
585
|
+
this = {}
|
|
586
|
+
generic = self.wb_default_descriptions
|
|
587
|
+
print(f'var_description loaded from WF {len(this)=}')
|
|
588
|
+
|
|
589
|
+
# breakpoint()
|
|
590
|
+
this_both = this | generic | self.extra_var_descriptions
|
|
591
|
+
out = self.mmodel.enrich_var_description(this_both)
|
|
592
|
+
return out
|
|
593
|
+
|
|
594
|
+
@property
|
|
595
|
+
def wb_default_descriptions(self):
|
|
596
|
+
import urllib.request
|
|
597
|
+
try:
|
|
598
|
+
|
|
599
|
+
default_url=r'https://raw.githubusercontent.com/IbHansen/modelflow-manual/main/model_repo/'
|
|
600
|
+
urlfile = (Path(default_url) / Path('wbvarnames.txt').name).as_posix().replace('https:/','https://')
|
|
601
|
+
|
|
602
|
+
with urllib.request.urlopen(urlfile) as f:
|
|
603
|
+
lines_all = f.read().decode("utf-8")
|
|
604
|
+
|
|
605
|
+
|
|
606
|
+
lines = lines_all.split('\n')
|
|
607
|
+
alldes = {line.split(' ',1)[0] : line.split(' ',1)[1] for line in lines }
|
|
608
|
+
var_description_this = {resvar: des for desvar, des in alldes.items() if ((resvar:= f'{self.cty}{desvar}') in self.mmodel.allvar.keys()) }
|
|
609
|
+
var_description_wld = {desvar: des for desvar, des in alldes.items() if desvar in self.mmodel.allvar.keys()}
|
|
610
|
+
|
|
611
|
+
var_description = {**var_description_this, **var_description_wld}
|
|
612
|
+
print(f'Default WB var_description loaded {self.cty=} {len(var_description)=}')
|
|
613
|
+
return var_description
|
|
614
|
+
except:
|
|
615
|
+
print('No default WB var_description loaded')
|
|
616
|
+
return {}
|
|
617
|
+
|
|
618
|
+
@property
|
|
619
|
+
def mfmsa_options(self):
|
|
620
|
+
'''Grab the mfmsa options, a world bank speciality'''
|
|
621
|
+
options = self.model_all_about.get('mfmsa_options','')
|
|
622
|
+
|
|
623
|
+
return options
|
|
624
|
+
|
|
625
|
+
@property
|
|
626
|
+
def mfmsa_options_dict(self):
|
|
627
|
+
import xml
|
|
628
|
+
def xml_to_dict(element):
|
|
629
|
+
if len(element) == 0: # If the element has no children
|
|
630
|
+
return element.text
|
|
631
|
+
return {child.tag: xml_to_dict(child) for child in element}
|
|
632
|
+
root = xml.etree.ElementTree.fromstring(self.mfmsa_options)
|
|
633
|
+
|
|
634
|
+
return xml_to_dict(root)
|
|
635
|
+
|
|
636
|
+
|
|
637
|
+
|
|
638
|
+
|
|
639
|
+
|
|
640
|
+
@property
|
|
641
|
+
def mfmsa_start_end(self):
|
|
642
|
+
'''Finds the start and end from the MFMSA entry'''
|
|
643
|
+
import xml
|
|
644
|
+
root = xml.etree.ElementTree.fromstring(self.mfmsa_options)
|
|
645
|
+
start = (root.find('.//SolveStart').text)
|
|
646
|
+
end = (root.find('.//SolveEnd').text)
|
|
647
|
+
return start,end
|
|
648
|
+
|
|
649
|
+
@property
|
|
650
|
+
def mfmsa_country(self):
|
|
651
|
+
'''Finds the start and end from the MFMSA entry'''
|
|
652
|
+
import xml
|
|
653
|
+
root = xml.etree.ElementTree.fromstring(self.mfmsa_options)
|
|
654
|
+
country = (root.find('.//iFace/country').text)
|
|
655
|
+
return country
|
|
656
|
+
|
|
657
|
+
|
|
658
|
+
|
|
659
|
+
@functools.cached_property
|
|
660
|
+
def mfmsa_quasiIdentities(self):
|
|
661
|
+
'''Finds the a set containing quasiidendities'''
|
|
662
|
+
import xml
|
|
663
|
+
try:
|
|
664
|
+
root = xml.etree.ElementTree.fromstring(self.mfmsa_options)
|
|
665
|
+
quasi = root.find(".//quasiIdentities").text
|
|
666
|
+
quasiset = {f'{self.modelname}{stem}' for stem in quasi.split()}.union(
|
|
667
|
+
{f'{stem}' for stem in quasi.split()})
|
|
668
|
+
except:
|
|
669
|
+
print(f'No quasiIdentities in {self.modelname}')
|
|
670
|
+
quasiset = set()
|
|
671
|
+
return quasiset
|
|
672
|
+
|
|
673
|
+
@property
|
|
674
|
+
def var_groups_default(self):
|
|
675
|
+
print('Default WB var_group loaded')
|
|
676
|
+
|
|
677
|
+
return {'Headline': '{cty}NYGDPMKTPXN {cty}NRTOTLCN {cty}LMUNRTOTL_ {cty}BFFINCABDCD {cty}BFBOPTOTLCD {cty}GGBALEXGRCN {cty}GGDBTTOTLCN {cty}BNCABLOCLCD_ {cty}FPCPITOTLXN',
|
|
678
|
+
'National income accounts': '{cty}NY*',
|
|
679
|
+
'National expenditure accounts': '{cty}NE*',
|
|
680
|
+
'Value added accounts': '{cty}NV*',
|
|
681
|
+
'Balance of payments exports': '{cty}BX*',
|
|
682
|
+
'Balance of payments exports and value added ': '{cty}BX* {cty}NV*',
|
|
683
|
+
'Balance of Payments Financial Account': '{cty}BF*',
|
|
684
|
+
'General government fiscal accounts': '{cty}GG*',
|
|
685
|
+
'World all': 'WLD*',
|
|
686
|
+
'All variables' : '*'}
|
|
687
|
+
|
|
688
|
+
|
|
689
|
+
@functools.cached_property
|
|
690
|
+
def dfmodel(self):
|
|
691
|
+
'''The original input data enriched with during variablees, variables containing
|
|
692
|
+
values for specific historic years and model specific transformation '''
|
|
693
|
+
per_transform = lambda p: int(p) if self.freq== 'A' else p
|
|
694
|
+
|
|
695
|
+
|
|
696
|
+
# Now the data
|
|
697
|
+
df = self.model_all_about['data']
|
|
698
|
+
# breakpoint()
|
|
699
|
+
|
|
700
|
+
|
|
701
|
+
#% Now set the vars with fixedvalues
|
|
702
|
+
import warnings
|
|
703
|
+
with warnings.catch_warnings():
|
|
704
|
+
warnings.simplefilter(action='ignore')
|
|
705
|
+
|
|
706
|
+
value_vars = self.mmodel.vlist('*_value_*')
|
|
707
|
+
# print(f'{value_vars=}')
|
|
708
|
+
for var,val,per in (v.rsplit('_',2) for v in value_vars) :
|
|
709
|
+
# print(f' {var=} {val=} {per=} {int(per)=} var= {var}_{val}_{per}')
|
|
710
|
+
df.loc[:,f'{var}_{val}_{per}'] = df.loc[int(per) if self.freq== 'A' else per ,var]
|
|
711
|
+
|
|
712
|
+
|
|
713
|
+
self.showvaluevars = df[value_vars]
|
|
714
|
+
|
|
715
|
+
|
|
716
|
+
|
|
717
|
+
#% now set the values of the dummies
|
|
718
|
+
# breakpoint()
|
|
719
|
+
during_vars = self.mmodel.vlist('*during_*')
|
|
720
|
+
with warnings.catch_warnings():
|
|
721
|
+
warnings.simplefilter(action='ignore', category=pd.errors.PerformanceWarning)
|
|
722
|
+
for varname,(dur,per) in ((v,v.split('_',1)) for v in during_vars):
|
|
723
|
+
df.loc[:,varname]=0
|
|
724
|
+
# print(varname,dur,per)
|
|
725
|
+
pers = per.split('_')
|
|
726
|
+
if len(pers) == 1:
|
|
727
|
+
df.loc[per_transform(pers[0]),varname] = 1
|
|
728
|
+
else:
|
|
729
|
+
df.loc[per_transform(pers[0]):per_transform(pers[1]),varname]=1.
|
|
730
|
+
self.showduringvars = df[during_vars]
|
|
731
|
+
|
|
732
|
+
if self.make_fitted:
|
|
733
|
+
# try:
|
|
734
|
+
# temp_start,temp_end = self.mfmsa_start_end
|
|
735
|
+
# except:
|
|
736
|
+
# if type(self.fit_end) == type(None):
|
|
737
|
+
# raise Exception('Can not read end period from MFMSA. Provide fit_end in call ')
|
|
738
|
+
|
|
739
|
+
if type(self.fit_end) == type(None):
|
|
740
|
+
self.fit_end = self.end
|
|
741
|
+
if type(self.fit_start) == type(None):
|
|
742
|
+
self.fit_start = self.start
|
|
743
|
+
df = self.mfitmodel.res(df,self.fit_start,self.fit_end)
|
|
744
|
+
|
|
745
|
+
# breakpoint()
|
|
746
|
+
df = df.loc[:,[c for c in df.columns if c in self.mmodel.allvar_set]]
|
|
747
|
+
df_out = self.mmodel.insertModelVar(df).pipe(self.country_df_trans).astype('float64').fillna(0.0)
|
|
748
|
+
|
|
749
|
+
|
|
750
|
+
return df_out
|
|
751
|
+
|
|
752
|
+
def __call__(self):
|
|
753
|
+
'''returns the model and the base input'''
|
|
754
|
+
return self.mmodel,self.base_input
|
|
755
|
+
|
|
756
|
+
def test_model(self,start=None,end=None,maxvar=1_000_000, maxerr=100,tol=0.0001,showall=False,showinput=False,nofit=True):
|
|
757
|
+
'''
|
|
758
|
+
Compares a straight calculation with the input dataframe.
|
|
759
|
+
|
|
760
|
+
shows which variables dont have the same value
|
|
761
|
+
|
|
762
|
+
Args:
|
|
763
|
+
df (TYPE): dataframe to run.
|
|
764
|
+
start (TYPE, optional): start period. Defaults to None.
|
|
765
|
+
end (TYPE, optional): end period. Defaults to None.
|
|
766
|
+
maxvar (TYPE, optional): how many variables are to be chekked. Defaults to 1_000_000.
|
|
767
|
+
maxerr (TYPE, optional): how many errors to check Defaults to 100.
|
|
768
|
+
tol (TYPE, optional): check for absolute value of difference. Defaults to 0.0001.
|
|
769
|
+
showall (TYPE, optional): show more . Defaults to False.
|
|
770
|
+
showinput (TYPE, optional): show the input values Defaults to False.
|
|
771
|
+
nofit : if True dont show the fitted values.default True
|
|
772
|
+
|
|
773
|
+
Returns:
|
|
774
|
+
None.
|
|
775
|
+
|
|
776
|
+
'''
|
|
777
|
+
_start = start if start else self.start
|
|
778
|
+
_end = end if end else self.end
|
|
779
|
+
# breakpoint()
|
|
780
|
+
|
|
781
|
+
resresult = self.mmodel(self.base_input,_start,_end,reset_options=True,silent=0,solver='res')
|
|
782
|
+
self.mmodel.basedf = self.dfmodel
|
|
783
|
+
pd.options.display.float_format = '{:.10f}'.format
|
|
784
|
+
err=0
|
|
785
|
+
pd.set_option('display.max_columns', None)
|
|
786
|
+
pd.set_option("display.width", 1000)
|
|
787
|
+
print(f'\nChekking residuals for {self.mmodel.name} {_start} to {_end}')
|
|
788
|
+
for i,v in enumerate(self.mmodel.solveorder):
|
|
789
|
+
# if v.endswith('_FITTED'): continue
|
|
790
|
+
if i > maxvar : break
|
|
791
|
+
if err > maxerr : break
|
|
792
|
+
# print(f'{v=} {nofit=} {nofit and v.endswith("_FITTED")=}' )
|
|
793
|
+
if nofit and v.endswith('_FITTED'): continue
|
|
794
|
+
check = self.mmodel.get_values(v,pct=True).T
|
|
795
|
+
check.columns = ['Before check','After calculation','Difference','Pct']
|
|
796
|
+
# breakpoint()
|
|
797
|
+
if (check.Difference.abs() >= tol).any():
|
|
798
|
+
err=err+1
|
|
799
|
+
maxdiff = check.Difference.abs().max()
|
|
800
|
+
maxpct = check.Pct.abs().max()
|
|
801
|
+
# breakpoint()
|
|
802
|
+
if err==1 :
|
|
803
|
+
print('\nVariable with residuals above threshold')
|
|
804
|
+
print(f"{v:{self.mmodel.maxnavlen}}, Max difference:{maxdiff:15.8f} Max Pct {maxpct:15.10f}% It is number {i:5} in the solveorder and error number {err}")
|
|
805
|
+
if showall:
|
|
806
|
+
print(f'{self.mmodel.allvar[v]["frml"]}')
|
|
807
|
+
print(f'{self.mmodel.var_description[v]}')
|
|
808
|
+
|
|
809
|
+
print(f'\nResult of equation \n {check}\n')
|
|
810
|
+
if showinput:
|
|
811
|
+
print(f'\nEquation values before calculations: \n {self.mmodel.get_eq_values(v,last=False,showvar=1)} \n')
|
|
812
|
+
self.mmodel.oldkwargs = {}
|
|
813
|
+
pd.reset_option('max_columns')
|
|
814
|
+
pd.reset_option('max_columns')
|
|
815
|
+
|
|
816
|
+
|
|
817
|
+
@property
|
|
818
|
+
def iso_countries(self):
|
|
819
|
+
return {
|
|
820
|
+
"AFG": "Afghanistan",
|
|
821
|
+
"AGO": "Angola",
|
|
822
|
+
"ALB": "Albania",
|
|
823
|
+
"ARE": "United Arab Emirates",
|
|
824
|
+
"ARG": "Argentina",
|
|
825
|
+
"ARM": "Armenia",
|
|
826
|
+
"AS4": "ASEAN-4",
|
|
827
|
+
"ASN": "ASEAN",
|
|
828
|
+
"ATG": "Antigua and Barbuda",
|
|
829
|
+
"AUS": "Australia",
|
|
830
|
+
"AUT": "Austria",
|
|
831
|
+
"AZE": "Azerbaijan",
|
|
832
|
+
"BDI": "Burundi",
|
|
833
|
+
"BEL": "Belgium",
|
|
834
|
+
"BEN": "Benin",
|
|
835
|
+
"BFA": "Burkina Faso",
|
|
836
|
+
"BGD": "Bangladesh",
|
|
837
|
+
"BGR": "Bulgaria",
|
|
838
|
+
"BHR": "Bahrain",
|
|
839
|
+
"BHS": "Bahamas",
|
|
840
|
+
"BIH": "Bosnia and Herzegovina",
|
|
841
|
+
"BLR": "Belarus",
|
|
842
|
+
"BLZ": "Belize",
|
|
843
|
+
"BOL": "Bolivia",
|
|
844
|
+
"BRA": "Brazil",
|
|
845
|
+
"BRB": "Barbados",
|
|
846
|
+
"BWA": "Botswana",
|
|
847
|
+
"CAF": "Central African Republic",
|
|
848
|
+
"CAN": "Canada",
|
|
849
|
+
"CEE": "Central and Eastern Europe",
|
|
850
|
+
"CET": "Central and European Transition",
|
|
851
|
+
"CHE": "Switzerland",
|
|
852
|
+
"CHL": "Chile",
|
|
853
|
+
"CHN": "China",
|
|
854
|
+
"CIS": "Commonwealth of Independent States",
|
|
855
|
+
"CIV": "Cote d'Ivoire",
|
|
856
|
+
"CMR": "Cameroon",
|
|
857
|
+
"COG": "Congo, Rep.",
|
|
858
|
+
"COL": "Colombia",
|
|
859
|
+
"COM": "Comoros",
|
|
860
|
+
"CPV": "Cabo Verde",
|
|
861
|
+
"CRI": "Costa Rica",
|
|
862
|
+
"CYP": "Cyprus",
|
|
863
|
+
"CZE": "Czech Republic",
|
|
864
|
+
"DEU": "Germany",
|
|
865
|
+
"DEV": "Developing Countries",
|
|
866
|
+
"DJI": "Djibouti",
|
|
867
|
+
"DMA": "Dominica",
|
|
868
|
+
"DNK": "Denmark",
|
|
869
|
+
"DOM": "Dominican Republic",
|
|
870
|
+
"DZA": "Algeria",
|
|
871
|
+
"E10": "Euro-Area (10)",
|
|
872
|
+
"E27": "Euro-Area (28)",
|
|
873
|
+
"EAM": "EAP: Oil Importers",
|
|
874
|
+
"EAO": "EAP excl. China",
|
|
875
|
+
"EAP": "East Asia and Pacific",
|
|
876
|
+
"EAX": "EAP: Oil Exporters",
|
|
877
|
+
"ECA": "Europe and Central Asia",
|
|
878
|
+
"ECM": "ECA: Oil Importers",
|
|
879
|
+
"ECU": "Ecuador",
|
|
880
|
+
"ECX": "ECA: Oil Exporters",
|
|
881
|
+
"EGY": "Egypt, Arab Rep.",
|
|
882
|
+
"EMU": "Euro Area (19)",
|
|
883
|
+
"ERI": "Eritrea",
|
|
884
|
+
"ESP": "Spain",
|
|
885
|
+
"EST": "Estonia",
|
|
886
|
+
"ESU": "ECA Transition Countries",
|
|
887
|
+
"ETH": "Ethiopia",
|
|
888
|
+
"FIN": "Finland",
|
|
889
|
+
"FRA": "France",
|
|
890
|
+
"GAB": "Gabon",
|
|
891
|
+
"GBR": "United Kingdom",
|
|
892
|
+
"GCC": "MENA: GCC Countries",
|
|
893
|
+
"GEO": "Georgia",
|
|
894
|
+
"GHA": "Ghana",
|
|
895
|
+
"GIN": "Guinea",
|
|
896
|
+
"GMB": "Gambia, The",
|
|
897
|
+
"GNB": "Guinea-Bissau",
|
|
898
|
+
"GNQ": "Equatorial Guinea",
|
|
899
|
+
"GRC": "Greece",
|
|
900
|
+
"GTM": "Guatemala",
|
|
901
|
+
"GUY": "Guyana",
|
|
902
|
+
"HIY": "High Income Countries",
|
|
903
|
+
"HKG": "Hong Kong SAR, China",
|
|
904
|
+
"HND": "Honduras",
|
|
905
|
+
"HRV": "Croatia",
|
|
906
|
+
"HTI": "Haiti",
|
|
907
|
+
"HUN": "Hungary",
|
|
908
|
+
"HYO": "High Income (OECD)",
|
|
909
|
+
"IDN": "Indonesia",
|
|
910
|
+
"IND": "India",
|
|
911
|
+
"IRL": "Ireland",
|
|
912
|
+
"IRN": "Iran, Islamic Rep.",
|
|
913
|
+
"IRQ": "Iraq",
|
|
914
|
+
"ISL": "Iceland",
|
|
915
|
+
"ISR": "Israel",
|
|
916
|
+
"ITA": "Italy",
|
|
917
|
+
"JAM": "Jamaica",
|
|
918
|
+
"JOR": "Jordan",
|
|
919
|
+
"JPN": "Japan",
|
|
920
|
+
"KAZ": "Kazakhstan",
|
|
921
|
+
"KEN": "Kenya",
|
|
922
|
+
"KGZ": "Kyrgyz Republic",
|
|
923
|
+
"KHM": "Cambodia",
|
|
924
|
+
"KOR": "Korea, Rep.",
|
|
925
|
+
"KSV": "Kosovo (KSV)",
|
|
926
|
+
"XKX": "Kosovo (XKX)",
|
|
927
|
+
"KWT": "Kuwait",
|
|
928
|
+
"LAA": "LAC: Central America",
|
|
929
|
+
"LAC": "Latin America & Carribean",
|
|
930
|
+
"LAI": "LAC: Caribbean",
|
|
931
|
+
"LAM": "LAC: Oil Importers",
|
|
932
|
+
"LAO": "Lao, PDR",
|
|
933
|
+
"LAX": "LAC: Oil Exporters",
|
|
934
|
+
"LBN": "Lebanon",
|
|
935
|
+
"LBR": "Liberia",
|
|
936
|
+
"LBY": "Libya",
|
|
937
|
+
"LCA": "St. Lucia",
|
|
938
|
+
"LIC": "Low Income Countries",
|
|
939
|
+
"LKA": "Sri Lanka",
|
|
940
|
+
"LML": "Low and Middle Income: excl. China/India",
|
|
941
|
+
"LMX": "Low and Middle Income: excl. CEE & CIS",
|
|
942
|
+
"LSO": "Lesotho",
|
|
943
|
+
"LTD": "Limited data countries",
|
|
944
|
+
"LTU": "Lithuania",
|
|
945
|
+
"LUX": "Luxembourg",
|
|
946
|
+
"LVA": "Latvia",
|
|
947
|
+
"LXA": "LAC excl. Argentina",
|
|
948
|
+
"MAC": "Macau",
|
|
949
|
+
"MAR": "Morocco",
|
|
950
|
+
"MDA": "Moldova, Rep.",
|
|
951
|
+
"MDG": "Madagascar",
|
|
952
|
+
"MDV": "Maldives",
|
|
953
|
+
"MEX": "Mexico",
|
|
954
|
+
"MGR": "MENA: Maghreb",
|
|
955
|
+
"MIC": "Middle Income Countries",
|
|
956
|
+
"MKD": "North Macedonia", # "Macedonia, FYR",
|
|
957
|
+
"MLI": "Mali",
|
|
958
|
+
"MLT": "Malta",
|
|
959
|
+
"MNA": "Middle East and North Africa",
|
|
960
|
+
"MNE": "Montenegro",
|
|
961
|
+
"MNG": "Mongolia",
|
|
962
|
+
"MNX": "Middle East and North Africa: excl. Syria and",
|
|
963
|
+
"MOM": "MNA: Oil Importers",
|
|
964
|
+
"MOX": "MNA: Oil Exporters",
|
|
965
|
+
"MOZ": "Mozambique",
|
|
966
|
+
"MRT": "Mauritania",
|
|
967
|
+
"MSH": "MENA: Mashreq",
|
|
968
|
+
"MMR": "Myanmar",
|
|
969
|
+
"MUS": "Mauritius",
|
|
970
|
+
"MWI": "Malawi",
|
|
971
|
+
"MYS": "Malaysia",
|
|
972
|
+
"NAM": "Namibia",
|
|
973
|
+
"NER": "Niger",
|
|
974
|
+
"NGA": "Nigeria",
|
|
975
|
+
"NIC": "Nicaragua",
|
|
976
|
+
"NIE": "Asian High Income Non-EU",
|
|
977
|
+
"NLD": "Netherlands",
|
|
978
|
+
"NOR": "Norway",
|
|
979
|
+
"NPL": "Nepal",
|
|
980
|
+
"NZL": "New Zealand",
|
|
981
|
+
"OHX": "HIY: Oil Exporters",
|
|
982
|
+
"OHY": "HIY: Non-OECD",
|
|
983
|
+
"OLM": "DEV: Oil Importers",
|
|
984
|
+
"OLX": "DEV: Oil Exporters",
|
|
985
|
+
"OMN": "Oman",
|
|
986
|
+
"OSS": "SST excl. ZAF/NGA",
|
|
987
|
+
"PAK": "Pakistan",
|
|
988
|
+
"PAN": "Panama",
|
|
989
|
+
"PER": "Peru",
|
|
990
|
+
"PHL": "Philippines",
|
|
991
|
+
"PNG": "Papua New Guinea",
|
|
992
|
+
"POL": "Poland",
|
|
993
|
+
"PRT": "Portugal",
|
|
994
|
+
"PRY": "Paraguay",
|
|
995
|
+
"ROM": "Romania (ROM)",
|
|
996
|
+
"ROU": "Romania (ROU)",
|
|
997
|
+
"RUS": "Russian Federation",
|
|
998
|
+
"RWA": "Rwanda",
|
|
999
|
+
"QAT": "Qatar",
|
|
1000
|
+
"SAO": "Other South Asia",
|
|
1001
|
+
"SAS": "South Asia",
|
|
1002
|
+
"SAU": "Saudi Arabia",
|
|
1003
|
+
"SDN": "Sudan",
|
|
1004
|
+
"SEN": "Senegal",
|
|
1005
|
+
"SFA": "Sub-Saharan Africa CFA",
|
|
1006
|
+
"SGP": "Singapore",
|
|
1007
|
+
"SLB": "Solomon Islands",
|
|
1008
|
+
"SLE": "Sierra Leone",
|
|
1009
|
+
"SLV": "El Salvador",
|
|
1010
|
+
"SOX": "SST: Oil Exporters",
|
|
1011
|
+
"SRB": "Serbia",
|
|
1012
|
+
"SSA": "SST excl. ZAF",
|
|
1013
|
+
"SSM": "SST: Oil Importers",
|
|
1014
|
+
"SST": "Sub-Saharan Africa",
|
|
1015
|
+
"STP": "Sao Tome & Principe",
|
|
1016
|
+
"SUR": "Suriname",
|
|
1017
|
+
"SVK": "Slovakia",
|
|
1018
|
+
"SVN": "Slovenia",
|
|
1019
|
+
"SWE": "Sweden",
|
|
1020
|
+
"SWZ": "Swaziland",
|
|
1021
|
+
"SYC": "Seychelles",
|
|
1022
|
+
"SYR": "Syrian Arab Republic",
|
|
1023
|
+
"TCC": "Turkish Cyprus",
|
|
1024
|
+
"TCD": "Chad",
|
|
1025
|
+
"TGO": "Togo",
|
|
1026
|
+
"THA": "Thailand",
|
|
1027
|
+
"TJK": "Tajikistan",
|
|
1028
|
+
"TTO": "Trinidad and Tobago",
|
|
1029
|
+
"TUN": "Tunisia",
|
|
1030
|
+
"TLS": "Timor l'Este",
|
|
1031
|
+
"TUR": "Türkiye", # "Turkey",
|
|
1032
|
+
"TZA": "Tanzania, United Rep.",
|
|
1033
|
+
"UGA": "Uganda",
|
|
1034
|
+
"UKR": "Ukraine",
|
|
1035
|
+
"URY": "Uruguay",
|
|
1036
|
+
"USA": "United States",
|
|
1037
|
+
"UZB": "Uzbekistan",
|
|
1038
|
+
"VCT": "St. Vincent and the Grenadines",
|
|
1039
|
+
"VEN": "Venezuela, RB",
|
|
1040
|
+
"VNM": "Vietnam",
|
|
1041
|
+
"VUT": "Vanuatu",
|
|
1042
|
+
"WBG": "West Bank and Gaza (WBG)",
|
|
1043
|
+
"PSE": "West Bank and Gaza (PSE)",
|
|
1044
|
+
"WLT": "World (WBG Members)",
|
|
1045
|
+
"YEM": "Yemen, Rep.",
|
|
1046
|
+
"ZAF": "South Africa",
|
|
1047
|
+
"ZAR": "Congo, Dem. Rep. (ZAR)",
|
|
1048
|
+
"COD": "Congo, Dem. Rep. (COD)",
|
|
1049
|
+
"ZMB": "Zambia",
|
|
1050
|
+
"ZWE": "Zimbabwe",
|
|
1051
|
+
}
|
|
1052
|
+
|
|
1053
|
+
|
|
1054
|
+
|
|
1055
|
+
if __name__ == '__main__':
|
|
1056
|
+
|
|
1057
|
+
|
|
1058
|
+
#%% Testing
|
|
1059
|
+
if 1:
|
|
1060
|
+
pak_trans = lambda input : input.replace('- 01*D(','-1*D(')
|
|
1061
|
+
|
|
1062
|
+
|
|
1063
|
+
ago_trans = lambda input : input.replace('@MEAN(AGOBNCABFUNDCD/AGONYGDPMKTPCD,"2000 2020")','MEAN_AGOBNCABFUNDCD_DIV_AGONYGDPMKTPCD')
|
|
1064
|
+
ago_eviews_run_lines = ['smpl @ALL','series MEAN_AGOBNCABFUNDCD_DIV_AGONYGDPMKTPCD = @MEAN(AGOBNCABFUNDCD/AGONYGDPMKTPCD,"2000 2020")']
|
|
1065
|
+
|
|
1066
|
+
mda_trans = lambda input: input.replace('_MDAsbbrev.@coef(2)','_MDASBBREV_at_COEF_2')
|
|
1067
|
+
mda_eviews_run_lines = ['Scalar _MDASBBREV_at_COEF_2 = _MDASBBREV.@COEF(+2)']
|
|
1068
|
+
|
|
1069
|
+
|
|
1070
|
+
filedict = {f.stem[:3].lower():f for f in Path(r'C:\wb new\Modelflow\ib\developement\original').glob('*.wf1')}
|
|
1071
|
+
filedict = {f.stem[:3].lower():f for f in Path(r'C:\wb new\Modelflow\ib\developement\original').glob('*.wf2')}
|
|
1072
|
+
modelname = 'pak'
|
|
1073
|
+
filename = filedict[modelname]
|
|
1074
|
+
|
|
1075
|
+
|
|
1076
|
+
eviews_run_lines= globals().get(f'{modelname}_eviews_run_lines',[])
|
|
1077
|
+
country_trans = globals().get(f'{modelname}_trans' ,lambda x : x[:])
|
|
1078
|
+
country_df_trans = globals().get(f'{modelname}_df_trans',lambda x : x)
|
|
1079
|
+
|
|
1080
|
+
|
|
1081
|
+
cmodel = GrabWfModel(filename,
|
|
1082
|
+
# eviews_run_lines= eviews_run_lines,
|
|
1083
|
+
freq='A',
|
|
1084
|
+
country_trans = country_trans,
|
|
1085
|
+
country_df_trans = country_df_trans,
|
|
1086
|
+
make_fitted = True,
|
|
1087
|
+
do_add_factor_calc=True,
|
|
1088
|
+
start = 2020,
|
|
1089
|
+
end = 2100,
|
|
1090
|
+
fit_start = 2000, # Start of calculation of fittet model in baseline
|
|
1091
|
+
fit_end = 2030 # end of calc for fittted model, if None taken from mdmfsa options
|
|
1092
|
+
)
|
|
1093
|
+
# assert 1==2
|
|
1094
|
+
if 0:
|
|
1095
|
+
cmodel.test_model(cmodel.start,cmodel.end,maxerr=100,tol=0.001,showall=0)
|
|
1096
|
+
|
|
1097
|
+
|
|
1098
|
+
grab_lookat = cmodel
|
|
1099
|
+
mlookat = grab_lookat.mmodel
|
|
1100
|
+
lookat_des = mlookat.var_description
|
|
1101
|
+
lookat_equations = mlookat.equations
|
|
1102
|
+
lookat_all_frml_dict = grab_lookat.all_frml_dict
|
|
1103
|
+
base_input = cmodel.base_input
|
|
1104
|
+
mlookat(base_input,2020,2022)
|
|
1105
|
+
|
|
1106
|
+
#%%
|
|
1107
|
+
re.sub(r'@DURING\( *([0-9q]+) *\)', r'during_\1','0.755095546689654*@DURING("2020q4")'.replace('"',' '))
|