Changeset 27900
- Timestamp:
- 09/06/23 20:20:00 (19 months ago)
- Location:
- issm/trunk-jpl/src/m/netcdf
- Files:
-
- 4 edited
Legend:
- Unmodified
- Added
- Removed
-
issm/trunk-jpl/src/m/netcdf/read_netCDF.m
r27891 r27900 130 130 % keep an eye out for nested structs: 131 131 if strcmp(varname, 'this_is_a_nested') 132 is_ nested= true;132 is_object = true; 133 133 model_copy = copy_nested_struct(group_location_in_file, model_copy, NCData, verbose); 134 elseif strcmp(varname, 'name_of_cell_array') 135 is_object = true; 136 model_copy = copy_cell_array_of_objects(variables, group_location_in_file, model_copy, NCData, verbose); 134 137 elseif strcmp(varname, 'solution') 135 138 % band-aid pass.. 136 139 else 137 model_copy = copy_variable_data_to_new_model(group_location_in_file, varname, xtype, model_copy, NCData, verbose); 140 if logical(exist('is_object', 'var')) 141 % already handled 142 else 143 model_copy = copy_variable_data_to_new_model(group_location_in_file, varname, xtype, model_copy, NCData, verbose); 144 end 138 145 end 139 146 end … … 142 149 %try 143 150 % if it's a nested struct the function copy_nested_struct has already been called 144 if logical(exist('is_ nested', 'var'))151 if logical(exist('is_object', 'var')) 145 152 % do nothing 146 153 else … … 159 166 end 160 167 168 169 % to read cell arrays with objects: 170 function model_copy = copy_cell_array_of_objects(variables, group_location_in_file, model_copy, NCData, verbose); 171 %{ 172 The structure in netcdf for groups with the name_of_cell_array variable is like: 173 174 group: 2x6_cell_array_of_objects { 175 name_of_cell_array = <name_of_cell_array> 176 177 group: Row_1_of_2 { 178 group: Col_1_of_6 { 179 ... other groups can be here that refer to objects 180 } // group Col_6_of_6 181 } // group Row_1_of_2 182 183 group: Row_2_of_2 { 184 group: Col_1_of_6 { 185 ... other groups can be here that refer to objects 186 } // group Col_6_of_6 187 } // group Row_2_of_2 188 } // group 2x6_cell_array_of_objects 189 190 We have to navigate this structure to extract all the data and recreate the 191 original structure when the model was saved 192 %} 193 194 % get the name_of_cell_array, rows and cols vars 195 name_of_cell_array_varID = netcdf.inqVarID(group_location_in_file, 'name_of_cell_array'); 196 rows_varID = netcdf.inqVarID(group_location_in_file, 'rows'); 197 cols_varID = netcdf.inqVarID(group_location_in_file, 'cols'); 198 199 name_of_cell_array = netcdf.getVar(group_location_in_file, name_of_cell_array_varID).'; % transpose 200 rows = netcdf.getVar(group_location_in_file, rows_varID); 201 cols = netcdf.getVar(group_location_in_file, cols_varID); 202 203 % now we work backwards: make the cell array, fill it in, and assign it to the model 204 205 % make the cell array 206 cell_array_placeholder = cell(rows, cols); 207 208 % get subgroups which are elements of the cell array 209 subgroups = netcdf.inqGrps(group_location_in_file); % numerical cell array with ID's of subgroups 210 211 % enter each subgroup, get the data, assign it to the corresponding index of cell array 212 if rows > 1 213 % we go over rows 214 % set index for cell array rows 215 row_idx = 1; 216 for row = subgroups 217 % now columns 218 columns = netcdf.inqGrps(group_location_in_file); 219 220 % set index for cell array cols 221 col_idx = 1; 222 for column = columns 223 % now variables 224 current_column_varids = netcdf.inqVarIDs(column); 225 226 % if 'class_is_a' or 'this_is_a_nested' variables is present at this level we have to handle them accordingly 227 try 228 class_is_aID = netcdf.inqVarID(column, 'class_is_a'); 229 col_data = deserialize_class(column, NCData, verbose); 230 is_object = true; 231 catch 232 end 233 234 try 235 this_is_a_nestedID = netcdf.inqVarID(column, 'this_is_a_nested'); 236 % functionality not supported 237 disp('Error: Cell Arrays of structs not yet supported!') 238 % copy_nested_struct(column, model_copy, NCData, verbose) 239 is_object = true; 240 catch 241 end 242 243 if logical(exist('is_object', 'var')) 244 % already taken care of 245 else 246 % store the variables as normal -- to be added later 247 disp('Error: Cell Arrays of mixed objects not yet supported!') 248 for var = current_column_varids 249 % not supported 250 end 251 end 252 253 cell_array_placeholder{row_idx, col_idx} = col_data; 254 col_idx = col_idx + 1; 255 end 256 row_idx = row_idx + 1; 257 end 258 else 259 % set index for cell array 260 col_idx = 1; 261 for column = subgroups 262 % now variables 263 current_column_varids = netcdf.inqVarIDs(column); 264 265 % if 'class_is_a' or 'this_is_a_nested' variables is present at this level we have to handle them accordingly 266 try 267 classID = netcdf.inqVarID(column, 'class_is_a'); 268 col_data = deserialize_class(classID, column, NCData, verbose); 269 is_object = true; 270 catch ME 271 rethrow(ME) 272 end 273 274 try 275 this_is_a_nestedID = netcdf.inqVarID(column, 'this_is_a_nested'); 276 % functionality not supported 277 disp('Error: Cell Arrays of structs not yet supported!') 278 % col_data = copy_nested_struct(column, model_copy, NCData, verbose); 279 is_object = true; 280 catch 281 end 282 if logical(exist('is_object', 'var')) 283 % already taken care of 284 else 285 % store the variables as normal -- to be added later 286 disp('Error: Cell Arrays of mixed objects not yet supported!') 287 for var = current_column_varids 288 % col_data = not supported 289 end 290 end 291 292 cell_array_placeholder{col_idx} = col_data; 293 col_idx = col_idx + 1; 294 295 end 296 end 297 298 299 % Like in copy_nested_struct, we can only handle things 1 layer deep. 300 % assign cell array to model 301 address_to_attr_list = split(netcdf.inqGrpNameFull(group_location_in_file), '/'); 302 address_to_attr = address_to_attr_list{2}; 303 if isprop(model_copy.(address_to_attr), name_of_cell_array); 304 model_copy.(address_to_attr).(name_of_cell_array) = cell_array_placeholder; 305 else 306 model_copy = addprop(model_copy.(address_to_attr), name_of_cell_array, cell_array_placeholder); 307 end 308 309 if verbose 310 fprintf("Successfully loaded cell array %s to %s\n", name_of_cell_array,address_to_attr_list{2}) 311 end 312 end 313 314 315 316 317 function output = deserialize_class(classID, group, NCData, verbose) 318 %{ 319 This function will recreate a class 320 %} 321 322 % get the name of the class 323 name = netcdf.getVar(group, classID).'; 324 325 % instantiate it 326 class_instance = eval([name, '()']); 327 328 % get and assign properties 329 subgroups = netcdf.inqGrps(group); % numerical cell array with ID's of subgroups 330 331 if numel(subgroups) == 1 332 % get properties 333 varIDs = netcdf.inqVarIDs(subgroups); 334 for varID = varIDs 335 % var metadata 336 [varname, xtype, dimids, numatts] = netcdf.inqVar(subgroups, varID); 337 % data 338 data = netcdf.getVar(subgroups, varID); 339 340 % netcdf uses Row Major Order but MATLAB uses Column Major Order so we need to transpose all arrays w/ more than 1 dim 341 if all(size(data)~=1) || xtype == 2 342 data = data.'; 343 end 344 345 % some classes have permissions... so we skip those 346 try 347 % if property already exists, assign new value 348 if isprop(class_instance, varname) 349 class_instance.(varname) = data; 350 else 351 addprop(class_instance, varname, data); 352 end 353 catch 354 end 355 end 356 else 357 % not supported 358 end 359 output = class_instance; 360 end 161 361 162 362 … … 192 392 % and not pointers to the same memory address 193 393 % this means that if address_in_model has more than 1 layer, we need to modify the code. For now, 194 % we just hope this will do. An example of a no-solution would be model().abc.def.ghi.field 394 % we just hope this will do. An example of a no-solution would be model().abc.def.ghi.field whereas we're only assuming model().abc.field now 195 395 196 396 model_copy.(address_in_model).(name_of_struct) = struct(); -
issm/trunk-jpl/src/m/netcdf/read_netCDF.py
r27891 r27900 10 10 from taoinversion import taoinversion 11 11 from collections import OrderedDict 12 import sys 13 from massfluxatgate import massfluxatgate 14 12 15 13 16 … … 25 28 def read_netCDF(filename, verbose = False): 26 29 if verbose: 27 print('NetCDF42C v1.1.13') 28 29 # check if path exists 30 if path.exists(filename): 30 print('NetCDF42C v1.2.0') 31 32 ''' 33 filename = path and name to save file under 34 verbose = T/F = show or muted log statements. Naturally muted 35 ''' 36 37 # this is a precaution so that data is not lost 38 try: 39 # check if path exists 40 if path.exists(filename): 41 if verbose: 42 print('Opening {} for reading'.format(filename)) 43 else: pass 44 45 # open the given netCDF4 file 46 NCData = Dataset(filename, 'r') 47 # remove masks from numpy arrays for easy conversion 48 NCData.set_auto_mask(False) 49 else: 50 return 'The file you entered does not exist or cannot be found in the current directory' 51 52 # in order to handle some subclasses in the results class, we have to utilize this band-aid 53 # there will likely be more band-aids added unless a class name library is created with all class names that might be added to a md 54 try: 55 # if results has meaningful data, save the name of the subclass and class instance 56 NCData.groups['results'] 57 make_results_subclasses(NCData, verbose) 58 except: 59 pass 60 61 # similarly, we need to check and see if we have an m1qn3inversion class instance 62 try: 63 NCData.groups['inversion'] 64 check_inversion_class(NCData, verbose) 65 except: 66 pass 67 68 # walk through each group looking for subgroups and variables 69 for group in NCData.groups.keys(): 70 if 'debris' in group: 71 pass 72 else: 73 # have to send a custom name to this function: filename.groups['group'] 74 name = "NCData.groups['" + str(group) + "']" 75 walk_nested_groups(name, NCData, verbose) 76 31 77 if verbose: 32 print('Opening {} for reading'.format(filename)) 33 else: pass 34 35 # open the given netCDF4 file 36 NCData = Dataset(filename, 'r') 37 # remove masks from numpy arrays for easy conversion 38 NCData.set_auto_mask(False) 39 else: 40 print('The file you entered does not exist or cannot be found in the current directory') 41 return print() 42 43 # continuation of band-aid for results class 44 try: 45 NCData.groups['results'] 46 make_results_subclasses(NCData, verbose) 47 except: 48 pass 49 50 # similarly, we need to check and see if we have an m1qn3inversion class instance 51 try: 52 NCData.groups['inversion'] 53 check_inversion_class(NCData, verbose) 54 except: 55 pass 56 57 # walk through each group looking for subgroups and variables 58 for group in NCData.groups.keys(): 59 if 'debris' in group: 60 pass 61 else: 62 # have to send a custom name to this function: filename.groups['group'] 63 name = "NCData.groups['" + str(group) + "']" 64 walk_nested_groups(name, NCData, verbose) 65 66 if verbose: 67 print("Model Successfully Loaded.") 68 return model_copy 69 78 print("Model Successfully Loaded.") 79 80 NCData.close() 81 82 return model_copy 83 84 # just in case something unexpected happens 85 except Exception as e: 86 if 'NCData' in locals(): 87 NCData.close() 88 raise e 70 89 71 90 def make_results_subclasses(NCData, verbose = False): … … 111 130 # first, we enter the group by: filename.groups['group_name'] 112 131 # second we search the current level for variables: filename.groups['group_name'].variables.keys() 113 # at this step we check for multidimensional structure arrays and filter them out132 # at this step we check for multidimensional structure arrays/ arrays of objects and filter them out 114 133 # third we get nested group keys by: filename.groups['group_name'].groups.keys() 115 # if a variables exists, copy the data to the model framework by calling copy function116 134 # if a nested groups exist, repeat all 117 135 118 136 for variable in eval(group_location_in_file + '.variables.keys()'): 119 if variable == 'this_is_a_nested' and 'results' in group_location_in_file: 120 # have to do some string deconstruction to get the name of the class instance/last group from 'NetCDF.groups['group1'].groups['group1.1']' 121 pattern = r"\['(.*?)'\]" 122 matches = re.findall(pattern, group_location_in_file) 123 name_of_struct = matches[-1] #eval(group_location_in_file + ".variables['solution']") 124 copy_multidimensional_results_struct(group_location_in_file, name_of_struct, NCData) 125 istruct = True 126 127 elif variable == 'this_is_a_nested' and 'qmu' in group_location_in_file: 128 print('encountered qmu structure that is not yet supported.') 129 # have to do some string deconstruction to get the name of the class instance/last group from 'NetCDF.groups['group1'].groups['group1.1']' 130 #pattern = r"\['(.*?)'\]" 131 #matches = re.findall(pattern, group_location_in_file) 132 #name_of_struct = matches[-1] #eval(group_location_in_file + ".variables['solution']") 133 #name_of_struct = eval(group_location_in_file + ".variables['']") 134 #copy_multidimensional_qmu_struct(group_location_in_file, name_of_struct) 135 isstruct = True 136 137 else: 138 location_of_variable_in_file = group_location_in_file + ".variables['" + str(variable) + "']" 139 # group_location_in_file is like filename.groups['group1'].groups['group1.1'].groups['group1.1.1'] 140 # Define the regex pattern to match the groups within brackets 141 pattern = r"\['(.*?)'\]" 142 # 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 143 matches = re.findall(pattern, location_of_variable_in_file) 144 variable_name = matches[-1] 145 location_of_variable_in_model = '.'.join(matches[:-1]) 146 copy_variable_data_to_new_model(location_of_variable_in_file, location_of_variable_in_model, variable_name, NCData, verbose=verbose) 147 148 if 'istruct' in locals(): 137 if 'is_object' not in locals(): 138 if variable == 'this_is_a_nested' and 'results' in group_location_in_file and 'qmu' not in group_location_in_file: 139 # have to do some string deconstruction to get the name of the class instance/last group from 'NetCDF.groups['group1'].groups['group1.1']' 140 pattern = r"\['(.*?)'\]" 141 matches = re.findall(pattern, group_location_in_file) 142 name_of_struct = matches[-1] #eval(group_location_in_file + ".variables['solution']") 143 deserialize_nested_results_struct(group_location_in_file, name_of_struct, NCData) 144 is_object = True 145 146 elif variable == 'name_of_cell_array': 147 # reconstruct an array of elements 148 deserialize_array_of_objects(group_location_in_file, model_copy, NCData, verbose) 149 is_object = True 150 151 elif variable == 'this_is_a_nested' and 'qmu' in group_location_in_file: 152 if verbose: 153 print('encountered qmu structure that is not yet supported.') 154 else: pass 155 156 is_object = True 157 158 else: 159 location_of_variable_in_file = group_location_in_file + ".variables['" + str(variable) + "']" 160 # group_location_in_file is like filename.groups['group1'].groups['group1.1'].groups['group1.1.1'] 161 # Define the regex pattern to match the groups within brackets 162 pattern = r"\['(.*?)'\]" 163 # 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 164 matches = re.findall(pattern, location_of_variable_in_file) 165 variable_name = matches[-1] 166 location_of_variable_in_model = '.'.join(matches[:-1]) 167 deserialize_data(location_of_variable_in_file, location_of_variable_in_model, variable_name, NCData, verbose=verbose) 168 169 # if one of the variables above was an object, further subclasses will be taken care of when reconstructing it 170 if 'is_object' in locals(): 149 171 pass 150 172 else: … … 162 184 ''' 163 185 164 def copy_multidimensional_results_struct(group_location_in_file, name_of_struct, NCData, verbose = False):186 def deserialize_nested_results_struct(group_location_in_file, name_of_struct, NCData, verbose = False): 165 187 ''' 166 188 A common multidimensional array is the 1xn md.results.TransientSolution object. … … 202 224 203 225 204 def copy_variable_data_to_new_model(location_of_variable_in_file, location_of_variable_in_model, variable_name, NCData, verbose = False): 226 227 def deserialize_array_of_objects(group_location_in_file, model_copy, NCData, verbose): 228 ''' 229 The structure in netcdf for groups with the name_of_cell_array variable is like: 230 231 group: 2x6_cell_array_of_objects { 232 name_of_cell_array = <name_of_cell_array> 233 234 group: Row_1_of_2 { 235 group: Col_1_of_6 { 236 ... other groups can be here that refer to objects 237 } // group Col_6_of_6 238 } // group Row_1_of_2 239 240 group: Row_2_of_2 { 241 group: Col_1_of_6 { 242 ... other groups can be here that refer to objects 243 } // group Col_6_of_6 244 } // group Row_2_of_2 245 } // group 2x6_cell_array_of_objects 246 247 We have to navigate this structure to extract all the data and recreate the 248 original structure when the model was saved 249 ''' 250 251 if verbose: 252 print(f"Loading array of objects.") 253 254 # get the name_of_cell_array, rows and cols vars 255 name_of_cell_array_varID = eval(group_location_in_file + ".variables['name_of_cell_array']") 256 rows_varID = eval(group_location_in_file + ".variables['rows']") 257 cols_varID = eval(group_location_in_file + ".variables['cols']") 258 259 name_of_cell_array = name_of_cell_array_varID[:][...].tobytes().decode() 260 rows = rows_varID[:] 261 cols = cols_varID[:] 262 263 # now we work backwards: make the array, fill it in, and assign it to the model 264 265 # make the array 266 array = list() 267 268 subgroups = eval(group_location_in_file + ".groups") #.keys()") 269 270 # enter each subgroup, get the data, assign it to the corresponding index of cell array 271 if rows > 1: 272 # we go over rows 273 # set index for rows 274 row_idx = 0 275 for row in list(subgroups): 276 # make list for each row 277 current_row = list() 278 columns = subgroups[str(row)].groups.keys() 279 280 # set index for columns 281 col_idx = 0 282 283 # iterate over columns 284 for col in list(columns): 285 # now get the variables 286 current_col_vars = columns.groups[str(col)].variables 287 288 # check for special datastructures 289 if "class_is_a" in current_col_vars: 290 class_name = subgroups[str(col)].variables['class_is_a'][:][...].tobytes().decode() 291 col_data = deserialize_class_instance(class_name, columns.groups[str(col)], NCData, verbose) 292 is_object = True 293 elif "this_is_a_nested" in current_col_vars: 294 # functionality not yet supported 295 print('Error: Cell Arrays of structs not yet supported!') 296 is_object = True 297 else: 298 if 'is_object_' in locals(): 299 pass 300 # already taken care of 301 else: 302 # store the variables as normal -- to be added later 303 print('Error: Arrays of mixed objects not yet supported!') 304 for var in current_col_vars: 305 # this is where that functionality would be handled 306 pass 307 col_idx += 1 308 # add the entry to our row list 309 current_row.append(col_data) 310 311 # add the list of columns to the array 312 array.append(current_row) 313 row_idx += 1 314 315 else: 316 # set index for columns 317 col_idx = 0 318 319 # iterate over columns 320 for col in list(subgroups): 321 # now get the variables 322 current_col_vars = subgroups[str(col)].variables 323 324 # check for special datastructures 325 if "class_is_a" in current_col_vars: 326 class_name = subgroups[str(col)].variables['class_is_a'][:][...].tobytes().decode() 327 col_data = deserialize_class_instance(class_name, subgroups[str(col)], NCData, verbose) 328 is_object = True 329 elif "this_is_a_nested" in current_col_vars: 330 # functionality not yet supported 331 print('Error: Cell Arrays of structs not yet supported!') 332 is_object = True 333 else: 334 if 'is_object_' in locals(): 335 pass 336 # already taken care of 337 else: 338 # store the variables as normal -- to be added later 339 print('Error: Arrays of mixed objects not yet supported!') 340 for var in current_col_vars: 341 # this is where that functionality would be handled 342 pass 343 col_idx += 1 344 # add the list of columns to the array 345 array.append(col_data) 346 347 # finally, add the attribute to the model 348 pattern = r"\['(.*?)'\]" 349 matches = re.findall(pattern, group_location_in_file) 350 variable_name = matches[0] 351 setattr(model_copy.__dict__[variable_name], name_of_cell_array, array) 352 353 if verbose: 354 print(f"Successfully loaded array of objects: {name_of_cell_array} to {variable_name}") 355 356 357 358 def deserialize_class_instance(class_name, group, NCData, verbose=False): 359 360 if verbose: 361 print(f"Loading class: {class_name}") 362 363 # this function requires the class module to be imported into the namespace of this file. 364 # we make a custom error in case the class module is not in the list of imported classes. 365 # most ISSM classes are imported by from <name> import <name> 366 class ModuleError(Exception): 367 pass 368 369 if class_name not in sys.modules: 370 raise ModuleError(str('Model requires the following class to be imported from a module: ' + class_name + ". Please add the import to read_netCDF.py in order to continue.")) 371 372 # Instantiate the class 373 class_instance = eval(class_name + "()") 374 375 # Get and assign properties 376 subgroups = list(group.groups.keys()) 377 378 if len(subgroups) == 1: 379 # Get properties 380 subgroup = group[subgroups[0]] 381 varIDs = subgroup.variables.keys() 382 for varname in varIDs: 383 # Variable metadata 384 var = subgroup[varname] 385 386 # Data 387 if 'char' in var.dimensions[0]: 388 data = var[:][...].tobytes().decode() 389 else: 390 data = var[:] 391 392 # Some classes may have permissions, so we skip those 393 try: 394 setattr(class_instance, varname, data) 395 except: 396 pass 397 else: 398 # Not supported 399 pass 400 401 if verbose: 402 print(f"Successfully loaded class instance {class_name} to model") 403 return class_instance 404 405 406 407 def deserialize_data(location_of_variable_in_file, location_of_variable_in_model, variable_name, NCData, verbose = False): 205 408 # as simple as navigating to the location_of_variable_in_model and setting it equal to the location_of_variable_in_file 206 409 # NetCDF4 has a property called "_FillValue" that sometimes saves empty lists, so we have to catch those … … 208 411 try: 209 412 # results band-aid... 210 #print(str(location_of_variable_in_model + '.' + variable_name))211 413 if str(location_of_variable_in_model + '.' + variable_name) in ['results.solutionstep', 'results.solution', 'results.resultsdakota']: 212 414 pass … … 240 442 else: 241 443 # we have to convert numpy datatypes to native python types with .item() 242 setattr(eval('model_copy.' + location_of_variable_in_model), variable_name, var_to_save.item()) 444 setattr(eval('model_copy.' + location_of_variable_in_model), variable_name, var_to_save.item()) 243 445 except: 244 446 setattr(eval('model_copy.' + location_of_variable_in_model), variable_name, eval(location_of_variable_in_file + '[:]')) 245 447 except AttributeError: 246 copy_variable_data_to_new_model_dict(location_of_variable_in_file, location_of_variable_in_model, NCData, verbose=verbose)448 deserialize_dict(location_of_variable_in_file, location_of_variable_in_model, NCData, verbose=verbose) 247 449 248 450 if verbose: … … 250 452 251 453 252 def copy_variable_data_to_new_model_dict(location_of_variable_in_file, location_of_variable_in_model, NCData, verbose = False): 253 # as simple as navigating to the location_of_variable_in_model and setting it equal to the location_of_variable_in_file 254 255 # NetCDF4 has a property called "_FillValue" that sometimes saves empty lists, so we have to catch those 454 455 def deserialize_dict(location_of_variable_in_file, location_of_variable_in_model, NCData, verbose = False): 256 456 FillValue = -9223372036854775806 257 457 -
issm/trunk-jpl/src/m/netcdf/write_netCDF.m
r27891 r27900 159 159 if numel(quality_control) ~= numel(class_instance_names) 160 160 disp('Error: The class instance within your model.results class is not currently supported by this application'); 161 disp(class(results_var.(class_instance_name)));162 161 else 163 162 if verbose … … 299 298 300 299 function create_group(location_of_child, list_of_layers, NetCDF, verbose) 300 %disp(list_of_layers) 301 301 % location_of_child is an object 302 302 % list_of_layers is a list like {'inversion', 'StressbalanceSolution','cost_functions_coefficients'} … … 324 324 end 325 325 end 326 % we may be dealing with an object326 % sometimes objects are passed through twice so we account for that with this try/catch 327 327 try 328 % if this line works, we're still dealing with a struct and need lower levels 329 if isempty(fieldnames(location_of_child)) 330 % do nothing 331 elseif isstruct(location_of_child) && any(size(location_of_child) > 1) 332 % we have a nested struct 333 copy_nested_struct(variable_name, location_of_child, group, NetCDF, verbose) 328 % we may be dealing with an object 329 % first we screen for structs 330 if isstruct(location_of_child) % && any(size(location_of_child) > 1) -- this is being tested 331 % we have a struct 332 copy_nested_struct(variable_name, location_of_child, group, NetCDF, verbose); 333 334 % now for cell arrays of datastructures: 335 elseif logical(~isstruct(location_of_child) && iscell(location_of_child) && isobject(location_of_child{1})) 336 copy_cell_array_of_objects(variable_name, location_of_child, group, NetCDF, verbose); 337 else 338 if ~isobject(location_of_child) && ~isstruct(location_of_child) 339 % we're dealing with raw data 340 create_var(variable_name, location_of_child, group, NetCDF, verbose); 341 end 334 342 end 335 343 catch 336 % if that line doesn't work, it means we're dealing with raw data 337 % not a nested struct, so we can pass 338 create_var(variable_name, location_of_child, group, NetCDF, verbose); 339 end 340 end 341 344 % do nothing 345 end 346 end 347 348 349 350 function copy_cell_array_of_objects(variable_name, address_of_child, group, NetCDF, verbose) 351 % make subgroup to represent the array 352 [rows, cols] = size(address_of_child); 353 name_of_subgroup = [num2str(rows), 'x', num2str(cols), '_cell_array_of_objects']; 354 subgroup = netcdf.defGrp(group, name_of_subgroup); 355 356 % save the name of the cell array 357 write_string_to_netcdf('name_of_cell_array', variable_name, subgroup, NetCDF, verbose); 358 359 % save the dimensions of the cell array 360 create_var('rows', rows, subgroup, NetCDF, verbose); 361 create_var('cols', cols, subgroup, NetCDF, verbose); 362 363 % if this is a multidimensional cell array, iterate over rows here and cols in copy_objects 364 if rows>1 365 for row = 1:rows 366 % make a subgroup for each row 367 name_of_subgroup = ['Row_', num2str(row), '_of_', num2str(rows)]; 368 subgroup = netcdf.defGrp(group, name_of_subgroup); 369 copy_objects(address_of_child, subgroup, NetCDF, cols, verbose); 370 end 371 else 372 copy_objects(address_of_child, subgroup, NetCDF, cols, verbose); 373 end 374 end 375 376 377 378 function copy_objects(address_of_child, group, NetCDF, cols, verbose) 379 for col = 1:cols 380 % make subgroup to contain each col of array 381 name_of_subgroup = ['Col_', num2str(col), '_of_', num2str(cols)]; 382 subgroup = netcdf.defGrp(group, name_of_subgroup); 383 384 % get the kind of object we're working with: 385 if isstruct(address_of_child{col}) 386 % handle structs 387 name_raw = fields(address_of_child{col}); 388 variable_name = name_raw{1}; 389 copy_nested_struct(variable_name, address_of_child, subgroup, NetCDF, verbose); 390 391 elseif numel(properties(address_of_child{col})) > 0 392 % handle class instances 393 copy_class_instance(address_of_child{col}, subgroup, NetCDF, verbose); 394 else 395 disp('ERROR: Cell arrays of mixed types are not yet supported in read_netCDF!\n Deserialization will not be able to complete!') 396 % handle regular datastructures that are already supported 397 name_raw = fields(address_of_child); 398 variable_name = name_raw{col}; 399 create_var(variable_name, address_of_child, subgroup, NetCDF, verbose); 400 end 401 end 402 end 403 404 405 function copy_class_instance(address_of_child, subgroup, NetCDF, verbose) 406 % get parent class name 407 name = class(address_of_child); 408 409 % save the name of the class 410 write_string_to_netcdf('class_is_a', name, subgroup, NetCDF, verbose); 411 412 % make subgroup to contain properties 413 name_of_subgroup = ['Properties_of_', name]; 414 subgroup = netcdf.defGrp(subgroup, name_of_subgroup); 415 416 % get properties 417 props = properties(address_of_child); 418 419 for property = 1:length(props) 420 variable_name = props{property}; 421 create_var(variable_name, address_of_child.(variable_name), subgroup, NetCDF, verbose); 422 end 423 424 end 342 425 343 426 … … 345 428 %{ 346 429 This function takes a struct of structs and saves them to netcdf. 430 431 It also works with single structs. 347 432 348 433 To do this, we get the number of dimensions (substructs) of the parent struct. … … 352 437 %} 353 438 354 if verbose355 disp("Beginning transfer of nested MATLAB struct to the NetCDF")356 end357 439 % make a new subgroup to contain all the others: 358 440 group = netcdf.defGrp(group, parent_struct_name); … … 386 468 end 387 469 if verbose 388 fprintf( 'Succesfully transferred nested MATLAB struct %s to the NetCDF\n', parent_struct_name)470 fprintf(["Succesfully transferred nested MATLAB struct ", parent_struct_name, " to the NetCDF\n"]) 389 471 end 390 472 end … … 583 665 584 666 function write_numeric_array_to_netcdf(variable_name, address_of_child, group, NetCDF, verbose) 667 585 668 % get the dimensions we'll need 586 669 intdim = netcdf.inqDimID(NetCDF,'int'); -
issm/trunk-jpl/src/m/netcdf/write_netCDF.py
r27891 r27900 15 15 ''' 16 16 Given a md, this set of functions will perform the following: 17 1. Enter each nested class of the md. 18 2. View each attribute of each nested class. 19 3. Compare state of attribute in the model to an empty model class. 20 4. If states are identical, pass. 21 5. Otherwise, create nested groups named after class structure. 22 6. Create variable named after class attribute and assign value to it. 17 1. View each attribute of each nested class. 18 2. Compare state of attribute in the model to an empty model. 19 3. If states are identical, pass. (except for np arrays which will always be saved) 20 4. Otherwise, create nested groups named after class structure. 21 5. Create variable named after class attribute and assign value to it. 23 22 ''' 24 23 … … 26 25 def write_netCDF(md, filename: str, verbose = False): 27 26 if verbose: 28 print('Python C2NetCDF4 v1. 1.14')27 print('Python C2NetCDF4 v1.2.0') 29 28 else: pass 30 29 ''' 31 md = model ()class instance to be saved30 md = model class instance to be saved 32 31 filename = path and name to save file under 33 verbose = T/F muted or showlog statements. Naturally muted32 verbose = T/F = show or muted log statements. Naturally muted 34 33 ''' 35 36 # Create a NetCDF file to write to 37 NetCDF = make_NetCDF(filename, verbose) 38 39 # Create an instance of an empty md class to compare md_var against 40 empty_model = model() 41 42 # Walk through the md class and compare subclass states to empty_model 43 walk_through_model(md, empty_model, NetCDF, verbose) 44 45 # in order to handle some subclasses in the results class, we have to utilize this band-aid 46 # there will likely be more band-aids added unless a class name library is created with all class names that might be added to a md 34 # this is a precaution so that data is not lost 47 35 try: 48 # if results has meaningful data, save the name of the subclass and class instance 49 NetCDF.groups['results'] 50 results_subclasses_bandaid(md, NetCDF, verbose) 51 # otherwise, ignore 52 except KeyError: 53 pass 36 # Create a NCData file to write to 37 NCData = create_NetCDF(filename, verbose) 54 38 55 NetCDF.close() 56 if verbose: 57 print('Model successfully saved as NetCDF4') 58 else: pass 59 60 61 def results_subclasses_bandaid(md, NetCDF, verbose = False): 39 # Create an instance of an empty md class to compare md_var against 40 empty_model = model() 41 42 # Walk through the md class and compare subclass states to empty_model 43 walk_through_model(md, empty_model, NCData, verbose) 44 45 # in order to handle some subclasses in the results class, we have to utilize this band-aid 46 # there will likely be more band-aids added unless a class name library is created with all class names that might be added to a md 47 try: 48 # if results has meaningful data, save the name of the subclass and class instance 49 NCData.groups['results'] 50 results_subclasses_bandaid(md, NCData, verbose) 51 # otherwise, ignore 52 except KeyError: 53 pass 54 55 NCData.close() 56 if verbose: 57 print('Model successfully saved as NetCDF4') 58 else: pass 59 60 # just in case something unexpected happens 61 except Exception as e: 62 if 'NCData' in locals(): 63 NCData.close() 64 raise e 65 66 67 def results_subclasses_bandaid(md, NCData, verbose = False): 62 68 # since the results class may have nested classes within it, we need to record the name of the 63 69 # nested class instance variable as it appears in the md that we're trying to save 64 70 quality_control = [] 65 71 66 # we save lists of instances to the netcdf72 # we save lists of instances to the NCData 67 73 solutions = [] 68 74 solutionsteps = [] … … 72 78 if verbose: 73 79 print(class_instance_name) 74 # for each class instance in results, see which class its from and record that info in the netcdfto recreate structure later80 # for each class instance in results, see which class its from and record that info in the NCData to recreate structure later 75 81 # check to see if there is a solutionstep class instance 76 82 if isinstance(md.results.__dict__[class_instance_name],solutionstep): … … 89 95 90 96 if solutionsteps != []: 91 write_string_to_netcdf(variable_name=str('solutionstep'), address_of_child=solutionsteps, group=NetCDF.groups['results'], list=True, NetCDF=NetCDF, verbose=verbose)97 serialize_string(variable_name=str('solutionstep'), address_of_child=solutionsteps, group=NCData.groups['results'], list=True, NCData=NCData, verbose=verbose) 92 98 93 99 if solutions != []: 94 write_string_to_netcdf(variable_name=str('solution'), address_of_child=solutions, group=NetCDF.groups['results'], list=True, NetCDF=NetCDF, verbose=verbose)100 serialize_string(variable_name=str('solution'), address_of_child=solutions, group=NCData.groups['results'], list=True, NCData=NCData, verbose=verbose) 95 101 96 102 if resultsdakotas != []: 97 write_string_to_netcdf(variable_name=str('resultsdakota'), address_of_child=resultsdakotas, group=NetCDF.groups['results'], list=True, NetCDF=NetCDF, verbose=verbose)103 serialize_string(variable_name=str('resultsdakota'), address_of_child=resultsdakotas, group=NCData.groups['results'], list=True, NCData=NCData, verbose=verbose) 98 104 99 105 … … 107 113 108 114 109 def make_NetCDF(filename: str, verbose = False):115 def create_NetCDF(filename: str, verbose = False): 110 116 # If file already exists delete / rename it 111 117 if os.path.exists(filename): … … 122 128 else: 123 129 # Otherwise create the file and define it globally so other functions can call it 124 N etCDF= Dataset(filename, 'w', format='NETCDF4')125 N etCDF.history = 'Created ' + time.ctime(time.time())126 N etCDF.createDimension('Unlim', None) # unlimited dimension127 N etCDF.createDimension('float', 1) # single integer dimension128 N etCDF.createDimension('int', 1) # single float dimension130 NCData = Dataset(filename, 'w', format='NETCDF4') 131 NCData.history = 'Created ' + time.ctime(time.time()) 132 NCData.createDimension('Unlim', None) # unlimited dimension 133 NCData.createDimension('float', 1) # single integer dimension 134 NCData.createDimension('int', 1) # single float dimension 129 135 130 136 if verbose: 131 137 print('Successfully created ' + filename) 132 138 133 return N etCDF134 135 136 def walk_through_model(md, empty_model, N etCDF, verbose= False):137 # Iterate over first layer of md _varattributes and assume this first layer is only classes139 return NCData 140 141 142 def walk_through_model(md, empty_model, NCData, verbose= False): 143 # Iterate over first layer of md attributes and assume this first layer is only classes 138 144 for group in md.__dict__.keys(): 139 145 address = md.__dict__[group] 140 146 empty_address = empty_model.__dict__[group] 141 # we need to record the layers of the md so we can save them to the netcdffile147 # we need to record the layers of the md so we can save them to the NCData file 142 148 layers = [group] 143 149 144 150 # Recursively walk through subclasses 145 walk_through_subclasses(address, empty_address, layers, N etCDF, empty_model, verbose)146 147 148 def walk_through_subclasses(address, empty_address, layers: list, N etCDF, empty_model, verbose = False):151 walk_through_subclasses(address, empty_address, layers, NCData, empty_model, verbose) 152 153 154 def walk_through_subclasses(address, empty_address, layers: list, NCData, empty_model, verbose = False): 149 155 # See if we have an object with keys or a not 150 156 try: … … 155 161 if is_object: 156 162 # enter the subclass, see if it has nested classes and/or attributes 157 # then compare attributes between mds and write to netCDFif they differ163 # then compare attributes between mds and write to NCData if they differ 158 164 # if subclass found, walk through it and repeat 159 165 for child in address.__dict__.keys(): … … 165 171 address_of_child = address.__dict__[child] 166 172 167 # if the current object is a results.<solution> object and has thesteps attr it needs special treatment173 # if the current object is a results.<solution> object and has nonzero steps attr it needs special treatment 168 174 if isinstance(address_of_child, solution) and len(address_of_child.steps) != 0: 169 create_group(address_of_child, current_layer, is_struct = True, NetCDF=NetCDF, verbose = verbose) 175 create_group(address_of_child, current_layer, is_struct = True, is_special_list = False, NCData=NCData, verbose = verbose) 176 177 # if the current object is a list of objects (currently only filters for lists/arrays of classes) 178 elif isinstance(address_of_child, list) and len(address_of_child) > 0 and hasattr(address_of_child[0], '__dict__'): 179 create_group(address_of_child, current_layer, is_struct = False, is_special_list = True, NCData=NCData, verbose = verbose) 170 180 171 181 # if the variable is an array, assume it has relevant data (this is because the next line cannot evaluate "==" with an array) 172 182 elif isinstance(address_of_child, np.ndarray): 173 create_group(address_of_child, current_layer, is_struct = False, NetCDF=NetCDF, verbose = verbose)183 create_group(address_of_child, current_layer, is_struct = False, is_special_list = False, NCData=NCData, verbose = verbose) 174 184 175 # see if the child exists in the empty md. If not, record it in the netcdf185 # see if the child exists in the empty md. If not, record it in the NCData 176 186 else: 177 187 try: … … 181 191 # if the attributes are identical we don't need to save anything 182 192 if address_of_child == address_of_child_in_empty_class: 183 walk_through_subclasses(address_of_child, address_of_child_in_empty_class, current_layer, N etCDF, empty_model, verbose)184 185 # If it has been modified, record it in the N etCDFfile193 walk_through_subclasses(address_of_child, address_of_child_in_empty_class, current_layer, NCData, empty_model, verbose) 194 195 # If it has been modified, record it in the NCData file 186 196 else: 187 create_group(address_of_child, current_layer, is_struct = False, NetCDF=NetCDF, verbose = verbose)188 walk_through_subclasses(address_of_child, address_of_child_in_empty_class, current_layer, N etCDF, empty_model, verbose)189 190 except KeyError: # record in netcdfand continue to walk thru md191 walk_through_subclasses(address_of_child, empty_address, current_layer, N etCDF, empty_model, verbose)192 create_group(address_of_child, current_layer, is_struct = False, NetCDF=NetCDF, verbose = verbose)197 create_group(address_of_child, current_layer, is_struct = False, is_special_list = False, NCData=NCData, verbose = verbose) 198 walk_through_subclasses(address_of_child, address_of_child_in_empty_class, current_layer, NCData, empty_model, verbose) 199 200 except KeyError: # record in NCData and continue to walk thru md 201 walk_through_subclasses(address_of_child, empty_address, current_layer, NCData, empty_model, verbose) 202 create_group(address_of_child, current_layer, is_struct = False, is_special_list = False, NCData=NCData, verbose = verbose) 193 203 else: pass 194 204 195 205 196 def create_group(address_of_child, layers, is_struct = False, NetCDF=None, verbose = False):206 def create_group(address_of_child, layers, is_struct = False, is_special_list = False, NCData=None, verbose = False): 197 207 198 208 # Handle the first layer of the group(s) 199 209 group_name = layers[0] 210 211 # try to make a group unless the group is already made 200 212 try: 201 group = N etCDF.createGroup(str(group_name))213 group = NCData.createGroup(str(group_name)) 202 214 except: 203 group = N etCDF.groups[str(group_name)]215 group = NCData.groups[str(group_name)] 204 216 205 217 # need to check if inversion or m1qn3inversion class 206 218 if group_name == 'inversion': 207 check_inversion_class(address_of_child, N etCDF, verbose)219 check_inversion_class(address_of_child, NCData, verbose) 208 220 else: pass 209 221 210 # if the data is nested , create nested groups to match class structure222 # if the data is nested in md, create nested groups to match class structure 211 223 if len(layers) > 2: 212 224 for name in layers[1:-1]: … … 214 226 group = group.createGroup(str(name)) 215 227 except: 216 group = N etCDF.groups[str(name)]228 group = NCData.groups[str(name)] 217 229 else: pass 218 230 … … 220 232 if is_struct: 221 233 parent_struct_name = layers[-1] 222 copy_nested_results_struct(parent_struct_name, address_of_child, group, NetCDF, verbose) 234 serialize_nested_results_struct(parent_struct_name, address_of_child, group, NCData, verbose) 235 236 elif is_special_list: 237 list_name = layers[-1] 238 serialize_array_of_objects(list_name, address_of_child, group, NCData, verbose) 223 239 224 240 else: 225 241 variable_name = layers[-1] 226 create_var(variable_name, address_of_child, group, NetCDF, verbose)242 serialize_var(variable_name, address_of_child, group, NCData, verbose) 227 243 228 244 … … 242 258 243 259 @singleton 244 def check_inversion_class(address_of_child, N etCDF, verbose = False):260 def check_inversion_class(address_of_child, NCData, verbose = False): 245 261 # need to make sure that we have the right inversion class: inversion, m1qn3inversion, taoinversion 246 262 if isinstance(address_of_child, m1qn3inversion): 247 write_string_to_netcdf(variable_name=str('inversion_class_name'), address_of_child=str('m1qn3inversion'), group=NetCDF.groups['inversion'], NetCDF=NetCDF, verbose = verbose)263 serialize_string(variable_name=str('inversion_class_name'), address_of_child=str('m1qn3inversion'), group=NCData.groups['inversion'], NCData=NCData, verbose = verbose) 248 264 if verbose: 249 265 print('Successfully saved inversion class instance ' + 'm1qn3inversion') 250 266 elif isinstance(address_of_child, taoinversion): 251 write_string_to_netcdf(variable_name=str('inversion_class_name'), address_of_child=str('taoinversion'), group=NetCDF.groups['inversion'], NetCDF=NetCDF, verbose = verbose)267 serialize_string(variable_name=str('inversion_class_name'), address_of_child=str('taoinversion'), group=NCData.groups['inversion'], NCData=NCData, verbose = verbose) 252 268 if verbose: 253 269 print('Successfully saved inversion class instance ' + 'taoinversion') 254 270 else: 255 write_string_to_netcdf(variable_name=str('inversion_class_name'), address_of_child=str('inversion'), group=NetCDF.groups['inversion'], NetCDF=NetCDF, verbose = verbose)271 serialize_string(variable_name=str('inversion_class_name'), address_of_child=str('inversion'), group=NCData.groups['inversion'], NCData=NCData, verbose = verbose) 256 272 if verbose: 257 273 print('Successfully saved inversion class instance ' + 'inversion') 258 274 259 275 260 def copy_nested_results_struct(parent_struct_name, address_of_struct, group, NetCDF, verbose = False):276 def serialize_nested_results_struct(parent_struct_name, address_of_struct, group, NCData, verbose = False): 261 277 ''' 262 This function takes a solution class instance and saves the solutionstep instances from <solution>.steps to the netcdf.263 264 To do this, we get the number of dimensions (substructs) of the parent struct .278 This function takes a results.solution class instance and saves the solutionstep instances from <solution>.steps to the NCData. 279 280 To do this, we get the number of dimensions (substructs) of the parent struct (list). 265 281 Next, we iterate through each substruct and record the data. 266 282 For each substruct, we create a subgroup of the main struct. … … 268 284 ''' 269 285 if verbose: 270 print("Beginning transfer of nested MATLAB struct to the N etCDF")286 print("Beginning transfer of nested MATLAB struct to the NCData") 271 287 272 288 # make a new subgroup to contain all the others: … … 274 290 275 291 # make sure other systems can flag the nested struct type 276 write_string_to_netcdf('this_is_a_nested', 'struct', group, list=False, NetCDF=NetCDF, verbose = verbose)292 serialize_string('this_is_a_nested', 'struct', group, list=False, NCData=NCData, verbose = verbose) 277 293 278 294 # other systems know the name of the parent struct because it's covered by the results/qmu functions above … … 290 306 for variable in substruct_fields: 291 307 address_of_child = current_substruct.__dict__[variable] 292 create_var(variable, address_of_child, subgroup, NetCDF, verbose = verbose)308 serialize_var(variable, address_of_child, subgroup, NCData, verbose = verbose) 293 309 294 310 if verbose: 295 print(f'Successfully transferred struct {parent_struct_name} to the NetCDF\n') 296 311 print(f'Successfully transferred struct {parent_struct_name} to the NCData\n') 312 313 314 315 316 def serialize_array_of_objects(list_name, address_of_child, group, NCData, verbose): 317 if verbose: 318 print(f"Serializing array of objects.") 319 320 # Get the dimensions of the cell array 321 if len(np.shape(address_of_child)) > 1: 322 rows, cols = np.shape(address_of_child) 323 else: rows, cols = 1, np.shape(address_of_child)[0] 324 325 # Make subgroup to represent the array 326 name_of_subgroup = f"{str(rows)}x{str(cols)}_cell_array_of_objects" 327 subgroup = group.createGroup(name_of_subgroup) 328 329 # Save the name of the cell array 330 serialize_string('name_of_cell_array', list_name, subgroup, NCData, verbose) 331 332 # Save the dimensions of the cell array 333 rowsID = subgroup.createVariable('rows', int, ('int',)) 334 colsID = subgroup.createVariable('cols', int, ('int',)) 335 rowsID[:] = rows 336 colsID[:] = cols 337 338 339 # If this is a multidimensional cell array, iterate over rows here and cols in serialize_objects 340 if rows > 1: 341 for row in range(rows): 342 # Make a subgroup for each row 343 name_of_subgroup = f"Row_{row+1}_of_{rows}" 344 subgroup = group.createGroup(name_of_subgroup) 345 serialize_objects(address_of_child, subgroup, NCData, cols, verbose) 346 else: 347 serialize_objects(address_of_child, subgroup, NCData, cols, verbose) 297 348 298 def create_var(variable_name, address_of_child, group, NetCDF, verbose = False): 349 if verbose: 350 print(f"Successfully serialized array of objects: {list_name}") 351 352 353 def serialize_objects(address_of_child, group, NCData, cols, verbose): 354 for col in range(cols): 355 # Make subgroup to contain each col of array 356 name_of_subgroup = f'Col_{col+1}_of_{cols}' 357 subgroup = group.createGroup(name_of_subgroup) 358 359 # index the current item 360 variable = address_of_child[col] 361 362 # Get the kind of object we're working with: 363 # see if it's a solution instance 364 if isinstance(variable, solution) and len(variable.steps) != 0: 365 pass 366 # this needs more work... 367 368 # see if it's a general class -- assume ISSM classes all have __dict__ 369 elif hasattr(variable, '__dict__'): 370 # Handle class instances 371 serialize_class_instance(variable, subgroup, NCData, verbose) 372 else: 373 print('ERROR: Cell arrays of mixed types are not yet supported in read_NCData!') 374 print('Deserialization will not be able to complete!') 375 # Handle regular data structures that are already supported 376 serialize_var(variable_name, variable, subgroup, NCData, verbose) 377 378 379 def serialize_class_instance(instance, group, NCData, verbose): 380 # get parent class name: 381 name = instance.__class__.__name__ 382 383 # save the name of the class 384 serialize_string(variable_name='class_is_a', address_of_child=name, group=group, NCData=NCData, verbose = verbose) 385 386 # make subgroup to contain attributes 387 name_of_subgroup = 'Properties_of_' + name 388 subgroup = group.createGroup(name_of_subgroup) 389 390 # get attributes 391 keys = instance.__dict__.keys() 392 393 for name in keys: 394 serialize_var(name, instance.__dict__[name], subgroup, NCData, verbose) 395 396 397 398 399 def serialize_var(variable_name, address_of_child, group, NCData, verbose = False): 299 400 # There are lots of different variable types that we need to handle from the md class 300 401 301 402 # This first conditional statement will catch numpy arrays of any dimension and save them 302 403 if isinstance(address_of_child, np.ndarray): 303 write_numpy_array_to_netcdf(variable_name, address_of_child, group, NetCDF, verbose=verbose)404 serialize_numpy_array(variable_name, address_of_child, group, NCData, verbose=verbose) 304 405 305 406 # check if it's an int … … 315 416 # or a string 316 417 elif isinstance(address_of_child, str): 317 write_string_to_netcdf(variable_name, address_of_child, group, NetCDF, verbose=verbose)418 serialize_string(variable_name, address_of_child, group, NCData, verbose=verbose) 318 419 319 420 #or a bool 320 421 elif isinstance(address_of_child, bool) or isinstance(address_of_child, np.bool_): 321 # netcdf4can't handle bool types like True/False so we convert all to int 1/0 and add an attribute named units with value 'bool'422 # NetCDF can't handle bool types like True/False so we convert all to int 1/0 and add an attribute named units with value 'bool' 322 423 variable = group.createVariable(variable_name, int, ('int',)) 323 424 variable[:] = int(address_of_child) … … 331 432 elif isinstance(address_of_child,list) and isinstance(address_of_child[0],str): 332 433 for string in address_of_child: 333 write_string_to_netcdf(variable_name, string, group, list=True, NetCDF=NetCDF, verbose=verbose)434 serialize_string(variable_name, string, group, list=True, NCData=NCData, verbose=verbose) 334 435 335 436 # or a regular list … … 352 453 353 454 if verbose: 354 print(f'Successfully transferred data from {variable_name} to the N etCDF')355 356 357 def write_string_to_netcdf(variable_name, address_of_child, group, list=False, NetCDF=None, verbose = False):358 # netcdfand strings dont get along.. we have to do it 'custom':455 print(f'Successfully transferred data from {variable_name} to the NCData') 456 457 458 def serialize_string(variable_name, address_of_child, group, list=False, NCData=None, verbose = False): 459 # NCData and strings dont get along.. we have to do it 'custom': 359 460 # if we hand it an address we need to do it this way: 360 if list == True: 361 """ 362 Save a list of strings to a NetCDF file. 363 461 if list: 462 """ 364 463 Convert a list of strings to a numpy.char_array with utf-8 encoded elements 365 and size rows x cols with each row the same # of cols and save to N etCDF464 and size rows x cols with each row the same # of cols and save to NCData 366 465 as char array. 367 466 """ … … 399 498 arr[i] = new_list[i] 400 499 401 # save array to netcdffile500 # save array to NCData file 402 501 string_var[:] = arr 403 502 … … 431 530 432 531 433 def write_numpy_array_to_netcdf(variable_name, address_of_child, group, NetCDF, verbose = False):434 # to make a nested array in netCDF, we have to get the dimensions of the array,435 # create corresponding dimensions in the netCDFfile, then we can make a variable436 # in the netCDFwith dimensions identical to those in the original array532 def serialize_numpy_array(variable_name, address_of_child, group, NCData, verbose = False): 533 # to make a nested array in NCData, we have to get the dimensions of the array, 534 # create corresponding dimensions in the NCData file, then we can make a variable 535 # in the NCData with dimensions identical to those in the original array 437 536 438 537 # start by getting the data type at the lowest level in the array:
Note:
See TracChangeset
for help on using the changeset viewer.