Changeset 27878
- Timestamp:
- 08/16/23 21:26:04 (19 months ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
issm/trunk/src/m/contrib/musselman/read_netCDF_commit.py
r27874 r27878 9 9 from m1qn3inversion import m1qn3inversion 10 10 from taoinversion import taoinversion 11 from collections import OrderedDict 12 11 13 12 14 … … 66 68 67 69 def make_results_subclasses(): 70 ''' 71 There are 3 possible subclasses: solution, solutionstep, resultsdakota. 72 In the NetCDF file these are saved as a list of strings. Ie, say there are 2 73 instances of solution under results, StressbalanceSolution and TransientSolution. 74 In the NetCDF file we would see solution = "StressbalanceSolution", "TransientSolution" 75 To deconstruct this, we need to iteratively assign md.results.StressbalanceSolution = solution() 76 and md.results.TransientSolution = solution() and whatever else. 77 ''' 78 # start with the subclasses 68 79 for subclass in NCData.groups['results'].variables.keys(): 69 80 class_instance = subclass + '()' 70 class_instance_name = NCData.groups['results'].variables[subclass][:][...].tobytes().decode() 71 setattr(model_copy.results, class_instance_name, eval(class_instance)) 81 82 # now handle the instances 83 for instance in NCData.groups['results'].variables[subclass][:]: 84 # this is an ndarray of numpy bytes_ that we have to convert to strings 85 class_instance_name = instance.tobytes().decode('utf-8').strip() 86 # from here we can make new subclasses named as they were in the model saved 87 setattr(model_copy.results, class_instance_name, eval(class_instance)) 88 print(f'Successfully created results subclass instance {class_instance} named {class_instance_name}.') 72 89 73 90 … … 90 107 # first, we enter the group by: filename.groups['group_name'] 91 108 # second we search the current level for variables: filename.groups['group_name'].variables.keys() 109 # at this step we check for multidimensional structure arrays and filter them out 92 110 # third we get nested group keys by: filename.groups['group_name'].groups.keys() 93 111 # if a variables exists, copy the data to the model framework by calling copy function … … 95 113 96 114 for variable in eval(group_location_in_file + '.variables.keys()'): 97 location_of_variable_in_file = group_location_in_file + ".variables['" + str(variable) + "']" 98 # group_location_in_file is like filename.groups['group1'].groups['group1.1'].groups['group1.1.1'] 99 # Define the regex pattern to match the groups within brackets 100 pattern = r"\['(.*?)'\]" 101 # Use regex to find all matches and return something like 'group1.group1.1.group1.1.1 ...' where the last value is the name of the variable 102 matches = re.findall(pattern, location_of_variable_in_file) 103 variable_name = matches[-1] 104 location_of_variable_in_model = '.'.join(matches[:-1]) 105 copy_variable_data_to_new_model(location_of_variable_in_file, location_of_variable_in_model, variable_name) 106 107 for nested_group in eval(group_location_in_file + '.groups.keys()'): 108 new_nested_group = group_location_in_file + ".groups['" + str(nested_group) + "']" 109 walk_nested_groups(new_nested_group) 115 if variable == 'this_is_a_nested' and 'results' in group_location_in_file: 116 # have to do some string deconstruction to get the name of the class instance/last group from 'NetCDF.groups['group1'].groups['group1.1']' 117 pattern = r"\['(.*?)'\]" 118 matches = re.findall(pattern, group_location_in_file) 119 name_of_struct = matches[-1] #eval(group_location_in_file + ".variables['solution']") 120 copy_multidimensional_results_struct(group_location_in_file, name_of_struct) 121 istruct = True 122 123 elif variable == 'this_is_a_nested' and 'qmu' in group_location_in_file: 124 print('encountered qmu structure that is not yet supported.') 125 # have to do some string deconstruction to get the name of the class instance/last group from 'NetCDF.groups['group1'].groups['group1.1']' 126 #pattern = r"\['(.*?)'\]" 127 #matches = re.findall(pattern, group_location_in_file) 128 #name_of_struct = matches[-1] #eval(group_location_in_file + ".variables['solution']") 129 #name_of_struct = eval(group_location_in_file + ".variables['']") 130 #copy_multidimensional_qmu_struct(group_location_in_file, name_of_struct) 131 isstruct = True 132 133 else: 134 location_of_variable_in_file = group_location_in_file + ".variables['" + str(variable) + "']" 135 # group_location_in_file is like filename.groups['group1'].groups['group1.1'].groups['group1.1.1'] 136 # Define the regex pattern to match the groups within brackets 137 pattern = r"\['(.*?)'\]" 138 # Use regex to find all matches and return something like 'group1.group1.1.group1.1.1 ...' where the last value is the name of the variable 139 matches = re.findall(pattern, location_of_variable_in_file) 140 variable_name = matches[-1] 141 location_of_variable_in_model = '.'.join(matches[:-1]) 142 copy_variable_data_to_new_model(location_of_variable_in_file, location_of_variable_in_model, variable_name) 143 144 if 'istruct' in locals(): 145 pass 146 else: 147 for nested_group in eval(group_location_in_file + '.groups.keys()'): 148 new_nested_group = group_location_in_file + ".groups['" + str(nested_group) + "']" 149 walk_nested_groups(new_nested_group) 150 151 152 153 ''' 154 MATLAB has Multidimensional Structure Arrays in 2 known classes: results and qmu. 155 The python classes results.py and qmu.py emulate this MATLAB object in their own 156 unique ways. The functions in this script will assign data to either of these 157 classes such that the final structure is compatible with its parent class. 158 ''' 159 160 def copy_multidimensional_results_struct(group_location_in_file, name_of_struct): 161 ''' 162 A common multidimensional array is the 1xn md.results.TransientSolution object. 163 164 The way that this object emulates the MATLAB mutli-dim. struct. array is with 165 the solution().steps attr. which is a list of solutionstep() instances 166 The process to recreate is as follows: 167 1. Get instance of solution() with solution variable (the instance is made in make_results_subclasses) 168 2. For each subgroup, create a solutionstep() class instance 169 2a. Populate the instance with the key:value pairs 170 2b. Append the instance to the solution().steps list 171 ''' 172 # step 1 173 class_instance_name = name_of_struct 174 175 # for some reason steps is not already a list 176 setattr(model_copy.results.__dict__[class_instance_name], 'steps', list()) 177 178 steps = model_copy.results.__dict__[class_instance_name].steps 179 180 # step 2 181 layer = 1 182 for subgroup in eval(group_location_in_file + ".groups.keys()"): 183 solutionstep_instance = solutionstep() 184 # step 2a 185 subgroup_location_in_file = group_location_in_file + ".groups['" + subgroup + "']" 186 for key in eval(subgroup_location_in_file + ".variables.keys()"): 187 value = eval(subgroup_location_in_file + ".variables['" + str(key) + "'][:]") 188 setattr(solutionstep_instance, key, value) 189 # step 2b 190 steps.append(solutionstep_instance) 191 print('Succesfully saved layer ' + str(layer) + ' to results.' + str(class_instance_name) + ' struct.') 192 layer += 1 193 194 print('Successfully recreated results structure ' + str(class_instance_name)) 110 195 111 196 … … 113 198 def copy_variable_data_to_new_model(location_of_variable_in_file, location_of_variable_in_model, variable_name): 114 199 # as simple as navigating to the location_of_variable_in_model and setting it equal to the location_of_variable_in_file 115 116 200 # NetCDF4 has a property called "_FillValue" that sometimes saves empty lists, so we have to catch those 117 201 FillValue = -9223372036854775806 118 119 # results band-aid... 120 if str(location_of_variable_in_model + '.' + variable_name) =='results.solutionstep': 121 pass 122 # qmu band-aid 123 elif 'qmu.statistics.method' in str(location_of_variable_in_model + '.' + variable_name): 124 pass 125 # handle any strings: 126 elif 'char' in eval(location_of_variable_in_file + '.dimensions[0]'): 127 setattr(eval('model_copy.' + location_of_variable_in_model), variable_name, eval(location_of_variable_in_file + '[:][...].tobytes().decode()')) 128 # handle ndarrays + lists 129 elif len(eval(location_of_variable_in_file + '[:]'))>1: 130 # check for bool 131 try: # there is only one datatype assigned the attribute 'units' and that is bool, so anything else will go right to except 132 if eval(location_of_variable_in_file + '.units') == 'bool': 133 setattr(eval('model_copy.' + location_of_variable_in_model), variable_name, np.array(eval(location_of_variable_in_file + '[:]'), dtype = bool)) 134 else: 202 try: 203 # results band-aid... 204 #print(str(location_of_variable_in_model + '.' + variable_name)) 205 if str(location_of_variable_in_model + '.' + variable_name) in ['results.solutionstep', 'results.solution', 'results.resultsdakota']: 206 pass 207 # qmu band-aid 208 elif 'qmu.statistics.method' in str(location_of_variable_in_model + '.' + variable_name): 209 pass 210 # handle any strings: 211 elif 'char' in eval(location_of_variable_in_file + '.dimensions[0]'): 212 setattr(eval('model_copy.' + location_of_variable_in_model), variable_name, eval(location_of_variable_in_file + '[:][...].tobytes().decode()')) 213 # handle ndarrays + lists 214 elif len(eval(location_of_variable_in_file + '[:]'))>1: 215 # check for bool 216 try: # there is only one datatype assigned the attribute 'units' and that is bool, so anything else will go right to except 217 if eval(location_of_variable_in_file + '.units') == 'bool': 218 setattr(eval('model_copy.' + location_of_variable_in_model), variable_name, np.array(eval(location_of_variable_in_file + '[:]'), dtype = bool)) 219 else: 220 setattr(eval('model_copy.' + location_of_variable_in_model), variable_name, eval(location_of_variable_in_file + '[:]')) 221 except: 135 222 setattr(eval('model_copy.' + location_of_variable_in_model), variable_name, eval(location_of_variable_in_file + '[:]')) 136 except: 137 setattr(eval('model_copy.' + location_of_variable_in_model), variable_name, eval(location_of_variable_in_file + '[:]')) 138 # catch everything else 223 # catch everything else 224 else: 225 # check for FillValue. use try/except because try block will only work on datatypes like int64, float, single element lists/arrays ect and not nd-arrays/n-lists etc 226 try: 227 # this try block will only work on single ints/floats/doubles and will skip to the except block for all other cases 228 if FillValue == eval(location_of_variable_in_file + '[:][0]'): 229 setattr(eval('model_copy.' + location_of_variable_in_model), variable_name, []) 230 else: 231 # we have to convert numpy datatypes to native python types with .item() 232 var_to_save = eval(location_of_variable_in_file + '[:][0]') # note the [0] on the end 233 setattr(eval('model_copy.' + location_of_variable_in_model), variable_name, var_to_save.item()) 234 except: 235 setattr(eval('model_copy.' + location_of_variable_in_model), variable_name, eval(location_of_variable_in_file + '[:]')) 236 except AttributeError: 237 copy_variable_data_to_new_model_dict(location_of_variable_in_file, location_of_variable_in_model) 238 239 print('Successfully saved ' + location_of_variable_in_model + '.' + variable_name + ' to model.') 240 241 242 243 244 245 246 def copy_variable_data_to_new_model_dict(location_of_variable_in_file, location_of_variable_in_model): 247 # as simple as navigating to the location_of_variable_in_model and setting it equal to the location_of_variable_in_file 248 249 # NetCDF4 has a property called "_FillValue" that sometimes saves empty lists, so we have to catch those 250 FillValue = -9223372036854775806 251 252 # the key will be the last item in the location 253 key = ''.join(location_of_variable_in_model.split('.')[-1]) 254 255 # update the location to point to the dict instead of the dict key 256 location_of_variable_in_model = '.'.join(location_of_variable_in_model.split('.')[:-1]) 257 258 # verify we're working with a dict: 259 if isinstance(eval('model_copy.' + location_of_variable_in_model), OrderedDict): 260 dict_object = eval('model_copy.' + location_of_variable_in_model) 261 262 # handle any strings: 263 if 'char' in eval(location_of_variable_in_file + '.dimensions[0]'): 264 data = eval(location_of_variable_in_file + '[:][...].tobytes().decode()') 265 dict_object.update({key: data}) 266 267 # handle ndarrays + lists 268 elif len(eval(location_of_variable_in_file + '[:]'))>1: 269 # check for bool 270 try: # there is only one datatype assigned the attribute 'units' and that is bool, so anything else will go right to except 271 if eval(location_of_variable_in_file + '.units') == 'bool': 272 data = np.array(eval(location_of_variable_in_file + '[:]'), dtype = bool) 273 dict_object.update({key: data}) 274 else: 275 data = eval(location_of_variable_in_file + '[:]') 276 dict_object.update({key: data}) 277 except: 278 data = eval(location_of_variable_in_file + '[:]') 279 dict_object.update({key: data}) 280 # catch everything else 281 else: 282 # check for FillValue. use try/except because try block will only work on datatypes like int64, float, single element lists/arrays ect and not nd-arrays/n-lists etc 283 try: 284 # this try block will only work on single ints/floats/doubles and will skip to the except block for all other cases 285 if FillValue == eval(location_of_variable_in_file + '[:][0]'): 286 dict_object.update({key: []}) 287 else: 288 # we have to convert numpy datatypes to native python types with .item() 289 var_to_save = eval(location_of_variable_in_file + '[:][0]') # note the [0] on the end 290 dict_object.update({key: var_to_save.item()}) 291 except: 292 data = eval(location_of_variable_in_file + '[:]') 293 dict_object.update({key: data}) 139 294 else: 140 # check for FillValue. use try/except because try block will only work on datatypes like int64, float, single element lists/arrays ect and not nd-arrays/n-lists etc 141 try: 142 # this try block will only work on single ints/floats/doubles and will skip to the except block for all other cases 143 if FillValue == eval(location_of_variable_in_file + '[:][0]'): 144 setattr(eval('model_copy.' + location_of_variable_in_model), variable_name, []) 145 else: 146 # we have to convert numpy datatypes to native python types with .item() 147 var_to_save = eval(location_of_variable_in_file + '[:][0]') # note the [0] on the end 148 setattr(eval('model_copy.' + location_of_variable_in_model), variable_name, var_to_save.item()) 149 except: 150 setattr(eval('model_copy.' + location_of_variable_in_model), variable_name, eval(location_of_variable_in_file + '[:]')) 151 print('Successfully saved ' + location_of_variable_in_model + '.' + variable_name + ' to model.') 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 295 print(f"Unrecognized object was saved and cannot be reconstructed: {location_of_variable_in_model}") 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316
Note:
See TracChangeset
for help on using the changeset viewer.