@@ -27,6 +27,10 @@ class ModelError(Exception):
2727 pass
2828
2929
30+ class ModelElementNotFound (ModelError ):
31+ pass
32+
33+
3034class Model (Datastructure ):
3135 """Class representing a general model of hierarchically organised elements, with interactions.
3236
@@ -252,6 +256,44 @@ def add_element(
252256 element .model = self
253257 return element
254258
259+ def add_elements (
260+ self ,
261+ elements : list [Union [Element , ElementType ]],
262+ parent : Optional [Element ] = None ,
263+ material : Optional [Material ] = None ,
264+ ) -> list [Union [Element , ElementType ]]:
265+ """Add a list of elements to the model.
266+
267+ Parameters
268+ ----------
269+ elements : list[:class:`Element`]
270+ The elements to add.
271+ parent : :class:`Element`, optional
272+ The parent element of the elements.
273+ If ``None``, the elements will be added directly under the root element.
274+ material : :class:`Material`, optional
275+ A material to assign to the elements.
276+ Note that the material should have already been added to the model before it can be assigned.
277+
278+ Returns
279+ -------
280+ list[:class:`Element`]
281+ The list of elements added to the model.
282+
283+ Raises
284+ ------
285+ ValueError
286+ If the parent node is not a GroupNode.
287+ ValueError
288+ If a material is provided that is not part of the model.
289+
290+ """
291+ # try
292+ # roll back if not all were added
293+ for element in elements :
294+ self .add_element (element , parent , material )
295+ return elements
296+
255297 def remove_element (self , element : Element ) -> None :
256298 """Remove an element from the model.
257299
@@ -322,6 +364,50 @@ def find_element_with_name(self, name: str) -> Optional[Element]:
322364 if element .name == name :
323365 return element
324366
367+ def find_element_with_name_or_fail (self , name : str ) -> Element :
368+ element = self .find_element_with_name (name )
369+ if not element :
370+ raise ModelElementNotFound
371+ return element
372+
373+ def find_all_elements_of_type (self , elementtype : Type [Element ]) -> list [Element ]:
374+ """Find all model elements of a given type.
375+
376+ Parameters
377+ ----------
378+ elementtype : Type[:class:`Element`]
379+ The type of element.
380+
381+ Returns
382+ -------
383+ list[:class:`Element`]
384+
385+ """
386+ elements = []
387+ for element in self .elements ():
388+ if isinstance (element , elementtype ):
389+ elements .append (element )
390+ return elements
391+
392+ def remove_elements_of_type (self , elementtype : Type [Element ]) -> list [Element ]:
393+ """Remove all model elements of a given type.
394+
395+ Parameters
396+ ----------
397+ elementtype : Type[:class:`Element`]
398+ The type of element.
399+
400+ Returns
401+ -------
402+ list[:class:`Element`]
403+ The removed elements.
404+
405+ """
406+ elements = self .find_all_elements_of_type (elementtype )
407+ for element in elements :
408+ self .remove_element (element )
409+ return elements
410+
325411 # =============================================================================
326412 # Groups
327413 # =============================================================================
@@ -393,6 +479,25 @@ def has_material(self, material: Material) -> bool:
393479 guid = str (material .guid )
394480 return guid in self ._materials
395481
482+ def add_or_get_material (self , material : Material ) -> Material :
483+ """Add a material to the model or retrieve an existing instance of the same type.
484+
485+ Parameters
486+ ----------
487+ material : :class:`Material`
488+ A material.
489+
490+ Returns
491+ -------
492+ :class:`Material`
493+
494+ """
495+ for existing in self .materials ():
496+ if isinstance (existing , type (material )):
497+ return existing
498+ self .add_material (material )
499+ return material
500+
396501 def assign_material (
397502 self ,
398503 material : Material ,
0 commit comments