Changeset 27875 for issm/trunk
- Timestamp:
- 08/10/23 18:34:53 (20 months ago)
- Location:
- issm/trunk/src/m/contrib/musselman
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
issm/trunk/src/m/contrib/musselman/read_netCDF.m
r27874 r27875 17 17 18 18 function model_copy = read_netCDF(filename) 19 fprintf('NetCDF42C v1.1.1 3\n');19 fprintf('NetCDF42C v1.1.14\n'); 20 20 21 21 % make a model framework to fill that is in the scope of this file … … 109 109 for variable = variables 110 110 [varname, xtype, dimids, numatts] = netcdf.inqVar(group_location_in_file, variable); 111 copy_variable_data_to_new_model(group_location_in_file,varname, xtype); 111 112 % keep an eye out for nested structs: 113 if strcmp(varname, 'this_is_a_nested') 114 is_nested = true; 115 copy_nested_struct(group_location_in_file) 116 else 117 is_nested = false; 118 copy_variable_data_to_new_model(group_location_in_file,varname, xtype); 119 end 112 120 end 113 121 catch ME … … 117 125 % try to find groups in current level, if it doesn't work it's because there is nothing there 118 126 try 119 % search for nested groups in the current level to feed back to this function 120 groups = netcdf.inqGrps(group_location_in_file); 121 if not(isempty(groups)) 122 for group = groups 123 %disp('found nested group!!') 124 group_id = netcdf.inqNcid(group_location_in_file, netcdf.inqGrpName(group)); 125 %disp(netcdf.inqGrpNameFull(group_id)) 126 walk_nested_groups(group); 127 end 128 end 129 catch 130 end 131 end 127 % if it's not a nested struct, keep searching for subgroups 128 if isnested 129 % do nothing 130 else 131 % search for nested groups in the current level to feed back to this function 132 groups = netcdf.inqGrps(group_location_in_file); 133 if not(isempty(groups)) 134 for group = groups 135 %disp('found nested group!!') 136 group_id = netcdf.inqNcid(group_location_in_file, netcdf.inqGrpName(group)); 137 %disp(netcdf.inqGrpNameFull(group_id)) 138 walk_nested_groups(group); 139 end 140 end 141 end 142 catch % no nested groups here 143 end 144 end 145 146 147 148 function copy_nested_struct(group_location_in_file) 149 global model_copy; 150 global NCData; 151 %{ 152 A common multidimensional struct array is the 1xn md.results.TransientSolution struct. 153 The process to recreate is as follows: 154 1. Get the name of the struct from group variable name_of_struct 155 2. Get the fieldnames from the subgroups 156 3. Recreate the struct with fieldnames 157 4. Populate the fields with their respective values 158 %} 159 160 % step 1 161 varid = netcdf.inqVarID(group_location_in_file, 'name_of_struct'); 162 name_of_struct = netcdf.getVar(group_location_in_file, varid)'; 163 164 % step 2 165 subgroups = netcdf.inqGrps(group_location_in_file); % numerical cell array with ID's of subgroups 166 % get single subgroup's data 167 single_subgroup_ID = subgroups(1); 168 subgroup_varids = netcdf.inqVarIDs(single_subgroup_ID); 169 fieldnames = {}; 170 for variable = subgroup_varids 171 [varname, xtype, dimids, numatts] = netcdf.inqVar(single_subgroup_ID, variable); 172 fieldnames{end+1} = varname; 173 end 174 175 % step 3 176 address_in_model = strrep(netcdf.inqGrpNameFull(group_location_in_file), '/', ''); 177 % we cannot assign a variable to represent this object as MATLAB treats all variables as copies 178 % and not pointers to the same memory address 179 % this means that if address_in_model is more than 1 item, we need to modify the code. For now, 180 % we just hope this will do 181 182 model_copy.(address_in_model).(name_of_struct) = struct(); 183 184 % for every fieldname in the subgroup, create an empty field 185 for fieldname = string(fieldnames) 186 model_copy.(address_in_model).(name_of_struct).(fieldname) = {}; 187 end 188 189 % use repmat to make the struct array multidimensional along the fields axis 190 number_of_dimensions = numel(subgroups); 191 model_copy.(address_in_model).(name_of_struct) = repmat(model_copy.(address_in_model).(name_of_struct), 1, number_of_dimensions); 192 193 % step 4 194 % for every layer of the multidimensional struct array, populate the fields 195 for current_layer = 1:number_of_dimensions 196 % choose subgroup 197 current_layer_subgroup_ID = subgroups(current_layer); 198 % get all vars 199 current_layer_subgroup_varids = netcdf.inqVarIDs(current_layer_subgroup_ID); 200 % get individual vars and set fields at layer current_layer 201 for varid = current_layer_subgroup_varids 202 [varname, xtype, dimids, numatts] = netcdf.inqVar(current_layer_subgroup_ID, varid); 203 data = netcdf.getVar(current_layer_subgroup_ID, varid); 204 205 % netcdf uses Row Major Order but MATLAB uses Column Major Order so we need to transpose all arrays w/ more than 1 dim 206 if all(size(data)~=1) || xtype == 2 207 data = data.'; 208 end 209 210 % set the field 211 model_copy.(address_in_model).(name_of_struct)(current_layer).(varname) = data; 212 %address_to_struct_in_model = setfield(address_to_struct_in_model(current_layer), varname, data) 213 end 214 model_copy.(address_in_model).(name_of_struct)(current_layer); 215 fprintf("Successfully saved layer %s to multidimension struct array\n", num2str(current_layer)) 216 end 217 fprintf('Successfully recreated multidimensional structure array %s in md.%s\n', name_of_struct, address_in_model) 218 end 219 220 221 132 222 133 223 %{ … … 142 232 %disp(varname) 143 233 % this is an inversion band-aid 144 if strcmp(varname, 'inversion_class_name') 234 if strcmp(varname, 'inversion_class_name') || strcmp(varname, 'name_of_struct') || strcmp(varname, 'solution') 145 235 % we don't need this 146 236 else … … 149 239 %disp(netcdf.inqGrpNameFull(group_location_in_file)) 150 240 %disp(class(netcdf.inqGrpNameFull(group_location_in_file))) 151 ad ress_to_attr = strrep(netcdf.inqGrpNameFull(group_location_in_file), '/', '.');152 153 data = netcdf.getVar(group_location_in_file, netcdf.inqVarID(group_location_in_file, varname));154 155 156 % matlab needs to know that ' ' = char()241 address_to_attr = strrep(netcdf.inqGrpNameFull(group_location_in_file), '/', '.'); 242 varid = netcdf.inqVarID(group_location_in_file, varname); 243 data = netcdf.getVar(group_location_in_file, varid); 244 245 246 % if we have an empty string 157 247 if xtype == 2 && isempty(all(data)) 158 248 data = cell(char()); 249 % if we have an empty cell-char array 159 250 elseif numel(data) == 1 && xtype == 3 && data == -32767 160 251 data = cell(char()); 161 252 end 162 % band-aid for cell-char-arrays:253 % band-aid for some cell-char-arrays: 163 254 if xtype == 2 && strcmp(data, 'default') 164 255 data = {'default'}; … … 168 259 if all(size(data)~=1) || xtype == 2 169 260 data = data.'; 261 end 262 263 % if we have a list of strings 264 if xtype == 2 265 try 266 if strcmp(netcdf.getAtt(group, varid, "type_is"), 'cell_array_of_strings') 267 data = cellstr(data) 268 end 269 catch 270 % no attr found so we pass 271 end 170 272 end 171 273 … … 174 276 %xtype 175 277 if xtype == 10 176 arg_to_eval = ['model_copy', ad ress_to_attr, '.', varname, ' = ' , 'double(data);'];278 arg_to_eval = ['model_copy', address_to_attr, '.', varname, ' = ' , 'double(data);']; 177 279 eval(arg_to_eval); 178 280 %disp('saved int64 as int16') 179 281 else 180 arg_to_eval = ['model_copy', ad ress_to_attr, '.', varname, ' = ' , 'data;'];282 arg_to_eval = ['model_copy', address_to_attr, '.', varname, ' = ' , 'data;']; 181 283 eval(arg_to_eval); 182 284 end -
issm/trunk/src/m/contrib/musselman/write_netCDF.m
r27874 r27875 11 11 12 12 function write_netCDF(model_var, filename) 13 disp('MATLAB C2NetCDF4 v1.1.1 3');13 disp('MATLAB C2NetCDF4 v1.1.14'); 14 14 % model_var = class object to be saved 15 15 % filename = path and name to save file under … … 179 179 % there are 2 cases: the location is a struct, the location is a class 180 180 if isstruct(model_subclass) 181 % if the current field is a nested struct assume it has valuable data that needs to be saved 182 if isstruct(location_of_child) && any(size(location_of_child) > 1) 183 create_group(location_of_child, list_of_layers); 184 181 185 % this would mean that the layer above the layer we're interested in is a struct, so 182 186 % we can navigate our empty model as such 183 if isfield(empty_model_subclass, current_child)187 elseif isfield(empty_model_subclass, current_child) 184 188 % the layer we're interested in does exist, we just need to compare states 185 189 location_of_child_in_empty_model = empty_model_subclass.(current_child); 190 186 191 % if the current attribute is a numerical array assume it has valuable data that needs to be saved 187 192 if isnumeric(location_of_child) && logical(numel(location_of_child) > 1) … … 264 269 % first we make the group at the highest level (ie, inversion) 265 270 group_name = list_of_layers{1}; 271 variable_name = list_of_layers{end}; 266 272 267 273 % if the group is already made, get it's ID instead of creating it again … … 284 290 end 285 291 end 286 % if the object is not a variable, we have nothing to save292 % we may be dealing with an object 287 293 try 288 294 % if this line works, we're still dealing with a struct and need lower levels 289 295 if isempty(fieldnames(location_of_child)) 290 296 % do nothing 297 elseif isstruct(location_of_child) && any(size(location_of_child) > 1) 298 % we have a nested struct 299 copy_nested_struct(variable_name, location_of_child, group) 291 300 end 292 301 catch 293 % if that line doesn't work, it means we're dealing with data 294 % Lastly, handle the variable(s) 295 variable_name = list_of_layers{end}; 302 % if that line doesn't work, it means we're dealing with raw data 303 % not a nested struct, so we can pass 296 304 create_var(variable_name, location_of_child, group); 297 305 end 298 306 end 307 308 309 310 function copy_nested_struct(parent_struct_name, address_of_struct, group) 311 %{ 312 This function takes a struct of structs and saves them to netcdf. 313 314 To do this, we get the number of dimensions (substructs) of the parent struct. 315 Next, we iterate through each substruct and record the data. 316 For each substruct, we create a subgroup of the main struct. 317 For each variable, we create dimensions that are assigned to each subgroup uniquely. 318 %} 319 320 disp("Beginning transfer of nested MATLAB struct to the NetCDF") 321 322 % make sure other systems can flag the nested struct type 323 dimID = netcdf.defDim(group, 'struct', 6); 324 string_var = netcdf.defVar(group, 'this_is_a_nested', "NC_CHAR", dimID); 325 uint_method=uint8('struct').'; 326 method_ID = char(uint_method); 327 netcdf.putVar(group, string_var, method_ID); 328 329 % make sure other systems know the name of the parent struct 330 uint_method=uint8(parent_struct_name).'; 331 method_ID = char(uint_method); 332 dimID = netcdf.defDim(group, 'struct_name', [numel(method_ID)]); 333 string_var = netcdf.defVar(group, 'name_of_struct', "NC_CHAR", dimID); 334 netcdf.putVar(group, string_var, method_ID); 335 336 % 'a' will always be 1 and is not useful to us 337 [a, no_of_dims] = size(address_of_struct); 338 339 for substruct = 1:no_of_dims 340 % we start by making subgroups with nice names like "TransientSolution_substruct_44" 341 name_of_subgroup = [parent_struct_name, '_substruct_', num2str(substruct)]; 342 subgroup = netcdf.defGrp(group, name_of_subgroup); 343 344 % do some housekeeping to keep track of the current layer 345 current_substruct = address_of_struct(substruct); 346 substruct_fields = fieldnames(current_substruct)'; % transpose because matlab only interates over n x 1 arrays 347 348 % now we need to iterate over each variable of the nested struct and save it to this new subgroup 349 for variable_name = string(substruct_fields) 350 address_of_child = current_substruct.(variable_name); 351 create_var(variable_name, address_of_child, subgroup); 352 end 353 end 354 fprintf('Succesfully transferred nested MATLAB struct %s to the NetCDF\n', parent_struct_name) 355 end 356 299 357 300 358 … … 338 396 339 397 % This first conditional statement will catch numeric arrays (matrices) of any dimension and save them 340 if any(size(address_of_child)>1) && ~isc har(address_of_child)398 if any(size(address_of_child)>1) && ~iscellstr(address_of_child) && ~ischar(address_of_child) 341 399 write_numeric_array_to_netcdf(variable_name, address_of_child, group); 342 400 … … 349 407 variable = netcdf.defVar(group, variable_name, "NC_DOUBLE", intdim); 350 408 351 % or a list of strings -- this needs work as it can only handle a list of 1 string 352 elseif iscell(address_of_child) && ischar(address_of_child{1}) 353 for i = 1:numel(address_of_child) 354 write_string_to_netcdf(variable_name, address_of_child{i}, group, true); 355 end 409 % or a list of strings 410 elseif iscellstr(address_of_child) || iscell(address_of_child) && ischar(address_of_child{1}) 411 write_cell_with_strings(variable_name, address_of_child, group) 356 412 357 413 % or an empty list … … 396 452 end 397 453 398 disp(['Successfully transferred data from ', variable_name, ' to the NetCDF']); 399 end 400 401 402 403 404 function write_string_to_netcdf(variable_name, address_of_child, group, list) 454 fprintf('Successfully transferred data from %s to the NetCDF\n', variable_name); 455 end 456 457 458 function write_cell_with_strings(variable_name, address_of_child, group) 459 %{ 460 Write cell array (ie {'one' 'two' 'three'}) to netcdf 461 %} 462 global NetCDF 463 464 if isempty(address_of_child) 465 % if the char array is empty, save an empty char 466 name_of_dimension = ['char', num2str(0)]; 467 try 468 dimID = netcdf.defDim(group, name_of_dimension, 0); 469 catch 470 dimID = netcdf.inqDimID(group, name_of_dimension); 471 end 472 % Now we can make a variable in this dimension: 473 string_var = netcdf.defVar(group, variable_name, "NC_CHAR", [dimID]); 474 % we leave empty now 475 else 476 % covert data to char array 477 method_ID = char(address_of_child); 478 479 % make dimensions 480 [rows, cols] = size(method_ID); 481 482 IDDim1 = netcdf.defDim(group,'cols',cols); 483 IDDim2 = netcdf.defDim(group,'rows',rows); 484 485 % create the variable slot 486 IDVarId = netcdf.defVar(group,variable_name,'NC_CHAR', [IDDim1 IDDim2]); 487 488 % save the variable 489 netcdf.putVar(group, IDVarId, method_ID'); %transpose 490 491 % tell other platforms that this is a cell of strings 492 netcdf.putAtt(group, IDVarId, 'type_is','cell_array_of_strings'); 493 end 494 end 495 496 497 function write_string_to_netcdf(variable_name, address_of_child, group) 405 498 % netcdf and strings don't get along.. we have to do it 'custom': 406 499 global NetCDF; 407 % If 'list' is not provided, assume it is false 408 if nargin < 4 409 list = false; 410 end 500 411 501 the_string_to_save = address_of_child; 412 502
Note:
See TracChangeset
for help on using the changeset viewer.