@@ -274,16 +274,7 @@ def get_old_path(path: str, previous_name: str) -> str:
274274 self .version_old ,
275275 )
276276 elif self ._check_data_type (old_item , new_item ):
277- # use class helper to register simple renames and
278- # reciprocal mappings
279277 self ._add_rename (old_path , new_path )
280- if old_item .get ("data_type" ) in DDVersionMap .STRUCTURE_TYPES :
281- # Add entries for common sub-elements
282- for path in old_paths :
283- if path .startswith (old_path ):
284- npath = path .replace (old_path , new_path , 1 )
285- if npath in new_path_set :
286- self ._add_rename (path , npath )
287278 elif nbc_description == "type_changed" :
288279 pass # We will handle this (if possible) in self._check_data_type
289280 elif nbc_description == "repeat_children_first_point" :
@@ -334,28 +325,40 @@ def get_old_path(path: str, previous_name: str) -> str:
334325 # Additional conversion rules for DDv3 to DDv4
335326 if self .version_old .major == 3 and new_version and new_version .major == 4 :
336327 self ._apply_3to4_conversion (old , new )
328+ # 3to4 rules may have introduced additional missing items in self.old_to_new
329+ self ._map_missing (
330+ False , old_path_set .difference (new_path_set , self .old_to_new )
331+ )
337332
338- def _add_rename (self , old_path : str , new_path : str ) -> None :
333+ def _add_rename (
334+ self , old_path : str , new_path : str , reciprocal : bool = True
335+ ) -> None :
339336 """Register a simple rename from old_path -> new_path using the
340337 path->Element maps stored on the instance (self.old_paths/self.new_paths).
341338 This will also add the reciprocal mapping when possible.
342339 """
343340 old_item = self .old_paths [old_path ]
344341 new_item = self .new_paths [new_path ]
345-
346- # forward mapping
342+ # Forward mapping
347343 self .old_to_new [old_path ] = (
348344 new_path ,
349345 _get_tbp (new_item , self .new_paths ),
350346 _get_ctxpath (new_path , self .new_paths ),
351347 )
352-
353- # reciprocal mapping
354- self .new_to_old [new_path ] = (
355- old_path ,
356- _get_tbp (old_item , self .old_paths ),
357- _get_ctxpath (old_path , self .old_paths ),
358- )
348+ # Reciprocal mapping
349+ if reciprocal :
350+ self .new_to_old [new_path ] = (
351+ old_path ,
352+ _get_tbp (old_item , self .old_paths ),
353+ _get_ctxpath (old_path , self .old_paths ),
354+ )
355+ # Apply to descendent nodes as well if the item is a struct or AoS
356+ for item in old_item .findall ("field" ):
357+ path = item .get ("path" )
358+ assert path is not None and path .startswith (old_path )
359+ npath = path .replace (old_path , new_path , 1 )
360+ if npath in self .new_paths :
361+ self ._add_rename (path , npath , reciprocal )
359362
360363 def _apply_3to4_conversion (self , old : Element , new : Element ) -> None :
361364 # Postprocessing for COCOS definition change:
@@ -421,6 +424,13 @@ def _apply_3to4_conversion(self, old: Element, new: Element) -> None:
421424 to_update [p ] = v
422425 self .old_to_new .path .update (to_update )
423426
427+ # Migrate additional obsolescent nodes
428+ # TODO: define migrations in a separate variable (as with the sign flips)?
429+ if self .ids_name == "magnetics" :
430+ self ._add_rename ("bpol_probe" , "b_field_pol_probe" , reciprocal = False )
431+ self ._add_rename ("method" , "ip" , reciprocal = False )
432+ self .old_to_new .type_change ["method" ] = _magnetics_method_to_ip
433+
424434 # GH#59: To improve further the conversion of DD3 to DD4, especially the
425435 # Machine Description part of the IDSs, we would like to add a 3to4 specific
426436 # rule to convert any siblings name + identifier (that are not part of an
@@ -431,19 +441,20 @@ def _apply_3to4_conversion(self, old: Element, new: Element) -> None:
431441 # Only perform the mapping if the corresponding target fields exist in the
432442 # new DD and if we don't already have a mapping for the involved paths.
433443 # use self.old_paths and self.new_paths set in _build_map
434- for p in self .old_paths :
444+ for name_path in self .old_paths :
435445 # look for name children
436- if not p .endswith ("/name" ):
446+ if not name_path .endswith ("/name" ):
437447 continue
438- parent = p .rsplit ("/" , 1 )[0 ]
439- name_path = f"{ parent } /name"
448+ parent = name_path .rsplit ("/" , 1 )[0 ]
440449 id_path = f"{ parent } /identifier"
441450 index_path = f"{ parent } /index"
442- desc_path = f"{ parent } /description"
443- new_name_path = name_path
451+ # Follow renames of parent structure
452+ new_parent = self .old_to_new .path .get (parent ) or parent
453+ desc_path = f"{ new_parent } /description"
454+ new_name_path = f"{ new_parent } /name"
444455
445- # If neither 'name' nor 'identifier' existed in the old DD, skip this parent
446- if name_path not in self . old_paths or id_path not in self .old_paths :
456+ # If 'identifier' doesn't exist in the old DD, skip this parent
457+ if id_path not in self .old_paths :
447458 continue
448459 # exclude identifier-structure (has index sibling)
449460 if index_path in self .old_paths :
@@ -454,14 +465,11 @@ def _apply_3to4_conversion(self, old: Element, new: Element) -> None:
454465 continue
455466
456467 # Map DD3 name -> DD4 description
457- if name_path not in self .old_to_new .path :
458- self ._add_rename (name_path , desc_path )
459- # GH#114: Also preserve name in DD4 name when identifier is empty
460- self .old_to_new .type_change [name_path ] = _name_identifier_3to4
461-
468+ self ._add_rename (name_path , desc_path )
469+ # GH#114: Also preserve name in DD4 name when identifier is empty
470+ self .old_to_new .type_change [name_path ] = _name_identifier_3to4
462471 # Map DD3 identifier -> DD4 name
463- if id_path in self .old_to_new .path :
464- self ._add_rename (id_path , new_name_path )
472+ self ._add_rename (id_path , new_name_path )
465473
466474 def _map_missing (self , is_new : bool , missing_paths : Set [str ]):
467475 rename_map = self .new_to_old if is_new else self .old_to_new
@@ -1329,3 +1337,14 @@ def _equilibrium_boundary_3to4(eq3: IDSToplevel, eq4: IDSToplevel, deepcopy: boo
13291337 node [2 ].psi = - ts3 .boundary_secondary_separatrix .psi # COCOS change
13301338 node [2 ].levelset .r = copy (ts3 .boundary_secondary_separatrix .outline .r )
13311339 node [2 ].levelset .z = copy (ts3 .boundary_secondary_separatrix .outline .z )
1340+
1341+
1342+ def _magnetics_method_to_ip (method : IDSBase , ip : IDSBase ) -> None :
1343+ """Convert obsolescent method(:) to ip(:) in the magnetics IDS."""
1344+ if not len (method ):
1345+ return
1346+ ip .resize (len (method ))
1347+ for old_item , new_item in zip (method , ip , strict = True ):
1348+ new_item .method_name .value = old_item .name .value
1349+ new_item .data .value = old_item .ip .data .value
1350+ new_item .time .value = old_item .ip .time .value
0 commit comments