1818
1919# Internal imports 
2020import  pipt .misc_tools .analysis_tools  as  at 
21+ import  pipt .misc_tools .extract_tools  as  extract 
2122from  geostat .decomp  import  Cholesky   # Making realizations 
2223from  pipt .misc_tools  import  cov_regularization 
2324from  pipt .misc_tools  import  wavelet_tools  as  wt 
2425from  misc  import  read_input_csv  as  rcsv 
2526from  misc .system_tools .environ_var  import  OpenBlasSingleThread   # Single threaded OpenBLAS runs 
2627
2728
29+ 
2830class  Ensemble :
2931    """ 
3032    Class for organizing misc. variables and simulator for an ensemble-based inversion run. Here, the forecast step 
@@ -56,11 +58,13 @@ def __init__(self, keys_en, sim, redund_sim=None):
5658        self .aux_input  =  None 
5759
5860        # Setup logger 
59-         logging .basicConfig (level = logging .INFO ,
60-                             filename = 'pet_logger.log' ,
61-                             filemode = 'w' ,
62-                             format = '%(asctime)s : %(levelname)s : %(name)s : %(message)s' ,
63-                             datefmt = '%Y-%m-%d %H:%M:%S' )
61+         logging .basicConfig (
62+             level = logging .INFO ,
63+             filename = 'pet_logger.log' ,
64+             filemode = 'w' ,
65+             format = '%(asctime)s : %(levelname)s : %(name)s : %(message)s' ,
66+             datefmt = '%Y-%m-%d %H:%M:%S' 
67+         )
6468        self .logger  =  logging .getLogger ('PET' )
6569
6670        # Check if folder contains any En_ files, and remove them! 
@@ -117,7 +121,7 @@ def __init__(self, keys_en, sim, redund_sim=None):
117121                self .disable_tqdm  =  False 
118122
119123            # extract information that is given for the prior model 
120-             self .prior_info  =  self . _extract_prior_info ( )
124+             self .prior_info  =  extract . extract_prior_info ( self . keys_en )
121125
122126            # Calculate initial ensemble if IMPORTSTATICVAR has not been given in init. file. 
123127            # Prior info. on state variables must be given by PRIOR_<STATICVAR-name> keyword. 
@@ -143,7 +147,11 @@ def __init__(self, keys_en, sim, redund_sim=None):
143147                    print ('\033 [1;33mInput states have different ensemble size\033 [1;m' )
144148                    sys .exit (1 )
145149                self .ne  =  min (tmp_ne )
146-         self ._ext_ml_info ()
150+                 
151+         if  'multilevel'  in  self .keys_en :
152+             ml_info  =  extract .extract_multilevel_info (self .keys_en )
153+             self .multilevel , self .tot_level , self .ml_ne , self .ML_error_corr , self .error_comp_scheme , self .ML_corr_done  =  ml_info 
154+         #self._ext_ml_info() 
147155
148156    def  _ext_ml_info (self ):
149157        ''' 
@@ -172,117 +180,7 @@ def _ext_ml_info(self):
172180                        self .error_comp_scheme  =  self .keys_en ['multilevel' ][i ][2 ]
173181                    self .ML_corr_done  =  False 
174182
175-     def  _extract_prior_info (self ) ->  dict :
176-         ''' 
177-         Extract prior information on STATE from keyword(s) PRIOR_<STATE entries>. 
178-         ''' 
179- 
180-         # Get state names as list 
181-         state_names  =  self .keys_en ['state' ]
182-         if  not  isinstance (state_names , list ): state_names  =  [state_names ]
183- 
184-         # Check if PRIOR_<state names> exists for each entry in state 
185-         for  name  in  state_names :
186-             assert  f'prior_{ name }  '  in  self .keys_en , \
187-                 'PRIOR_{0} is missing! This keyword is needed to make initial ensemble for {0} entered in '  \
188-                 'STATE' .format (name .upper ())
189-         
190-         # define dict to store prior information in  
191-         prior_info  =  {name : None  for  name  in  state_names }
192- 
193-         # loop over state priors 
194-         for  name  in  state_names :
195-             prior  =  self .keys_en [f'prior_{ name }  ' ]
196-             
197-             # Check if is a list (old way) 
198-             if  isinstance (prior , list ):
199-                 # list of lists - old way of inputting prior information 
200-                 prior_dict  =  {}
201-                 for  i , opt  in  enumerate (list (zip (* prior ))[0 ]):
202-                     if  opt  ==  'limits' :
203-                         prior_dict [opt ] =  prior [i ][1 :]
204-                     else :
205-                         prior_dict [opt ] =  prior [i ][1 ]
206-                 prior  =  prior_dict 
207-             else :
208-                 assert  isinstance (prior , dict ), 'PRIOR_{0} must be a dictionary or list of lists!' .format (name .upper ())
209- 
210- 
211-             # load mean if in file 
212-             if  isinstance (prior ['mean' ], str ):
213-                 assert  prior ['mean' ].endswith ('.npz' ), 'File name does not end with \' .npz\' !' 
214-                 load_file  =  np .load (prior ['mean' ])
215-                 assert  len (load_file .files ) ==  1 , \
216-                     'More than one variable located in {0}. Only the mean vector can be stored in the .npz file!'  \
217-                     .format (prior ['mean' ])
218-                 prior ['mean' ] =  load_file [load_file .files [0 ]]
219-             else :  # Single number inputted, make it a list if not already 
220-                 if  not  isinstance (prior ['mean' ], list ):
221-                     prior ['mean' ] =  [prior ['mean' ]]
222- 
223-             # loop over keys in prior 
224-             for  key  in  prior .keys ():
225-                 # ensure that entry is a list 
226-                 if  (not  isinstance (prior [key ], list )) and  (key  !=  'mean' ):
227-                     prior [key ] =  [prior [key ]]
228- 
229-             # change the name of some keys 
230-             prior ['variance' ] =  prior .pop ('var' , None )
231-             prior ['corr_length' ] =  prior .pop ('range' , None )
232- 
233-             # process grid 
234-             if  'grid'  in  prior :
235-                 grid_dim  =  prior ['grid' ]
236- 
237-                 # check if 3D-grid 
238-                 if  (len (grid_dim ) ==  3 ) and  (grid_dim [2 ] >  1 ):
239-                     nz  =  int (grid_dim [2 ])
240-                     prior ['nz' ] =  nz 
241-                     prior ['nx' ] =  int (grid_dim [0 ])
242-                     prior ['ny' ] =  int (grid_dim [1 ])
243-                     
244- 
245-                     # Check mean when values have been inputted directly (not when mean has been loaded) 
246-                     mean  =  prior ['mean' ]
247-                     if  isinstance (mean , list ) and  len (mean ) <  nz :
248-                          # Check if it is more than one entry and give error 
249-                         assert  len (mean ) ==  1 , \
250-                             'Information from MEAN has been given for {0} layers, whereas {1} is needed!'  \
251-                             .format (len (mean ), nz )
252- 
253-                         # Only 1 entry; copy this to all layers 
254-                         print (
255-                             '\033 [1;33mSingle entry for MEAN will be copied to all {0} layers\033 [1;m' .format (nz ))
256-                         prior ['mean' ] =  mean  *  nz 
257- 
258-                     #check if info. has been given on all layers. In the case it has not been given, we just copy the info. given. 
259-                     for  key  in  ['vario' , 'variance' , 'aniso' , 'angle' , 'corr_length' ]:
260-                         if  key  in  prior .keys ():
261-                             val  =  prior [key ]
262-                             if  len (val ) <  nz :
263-                                 # Check if it is more than one entry and give error 
264-                                 assert  len (val ) ==  1 , \
265-                                     'Information from {0} has been given for {1} layers, whereas {2} is needed!'  \
266-                                     .format (key .upper (), len (val ), nz )
267- 
268-                                 # Only 1 entry; copy this to all layers 
269-                                 print (
270-                                     '\033 [1;33mSingle entry for {0} will be copied to all {1} layers\033 [1;m' .format (key .upper (), nz ))
271-                                 prior [key ] =  val  *  nz 
272- 
273-                 else :
274-                     prior ['nx' ] =  int (grid_dim [0 ])
275-                     prior ['ny' ] =  int (grid_dim [1 ])
276-                     prior ['nz' ] =  1 
277- 
278-             prior .pop ('grid' , None )
279- 
280-             # add prior to prior_info 
281-             prior_info [name ] =  prior 
282-             
283-         return  prior_info 
284-                 
285- 
183+     
286184    def  gen_init_ensemble (self ):
287185        """ 
288186        Generate the initial ensemble of (joint) state vectors using the GeoStat class in the "geostat" package. 
@@ -353,6 +251,7 @@ def gen_init_ensemble(self):
353251        # Save the ensemble for later inspection 
354252        np .savez ('prior.npz' , ** self .state )
355253
254+ 
356255    def  get_list_assim_steps (self ):
357256        """ 
358257        Returns list of assimilation steps. Useful in a 'loop'-script. 
0 commit comments