Source code for easyreflectometry.sample.sample
from __future__ import annotations
__author__ = 'github.com/arm61'
from typing import Union
import yaml
from easyscience.Objects.Groups import BaseCollection
from .assemblies.base_assembly import BaseAssembly
from .assemblies.multilayer import Multilayer
from .elements.layers.layer import Layer
NR_DEFAULT_LAYERS = 2
[docs]
class Sample(BaseCollection):
"""Collection of assemblies that represent the sample for which experimental measurements exist."""
[docs]
def __init__(
self,
*list_layer_like: list[Union[Layer, BaseAssembly]],
name: str = 'EasySample',
interface=None,
**kwargs,
):
"""Constructor.
:param args: The assemblies in the sample.
:param name: Name of the sample, defaults to 'EasySample'.
:param interface: Calculator interface, defaults to `None`.
"""
new_items = []
if not list_layer_like:
list_layer_like = [Multilayer(interface=interface) for _ in range(NR_DEFAULT_LAYERS)]
for layer_like in list_layer_like:
if issubclass(type(layer_like), Layer):
new_items.append(Multilayer(layer_like, name=layer_like.name))
elif issubclass(type(layer_like), BaseAssembly):
new_items.append(layer_like)
else:
raise ValueError('The items must be either a Layer or an Assembly.')
super().__init__(name, *new_items, **kwargs)
self.interface = interface
@property
def uid(self) -> int:
"""The UID from the borg map."""
return self._borg.map.convert_id_to_key(self)
# Representation
@property
def _dict_repr(self) -> dict:
"""A simplified dict representation."""
return {self.name: [i._dict_repr for i in self]}
def __repr__(self) -> str:
"""String representation of the sample."""
return yaml.dump(self._dict_repr, sort_keys=False)
[docs]
def as_dict(self, skip: list = None) -> dict:
"""Produces a cleaned dict using a custom as_dict method to skip necessary things.
The resulting dict matches the parameters in __init__
:param skip: List of keys to skip, defaults to `None`.
"""
if skip is None:
skip = []
this_dict = super().as_dict(skip=skip)
for i, layer in enumerate(self.data):
this_dict['data'][i] = layer.as_dict(skip=skip)
return this_dict
[docs]
@classmethod
def from_dict(cls, data: dict) -> Sample:
"""
Create a Sample from a dictionary.
:param data: dictionary of the Sample
:return: Sample
"""
sample = super().from_dict(data)
# Remove the default multilayers
for i in range(NR_DEFAULT_LAYERS):
sample.__delitem__(0)
# Ensure that the data is also converted
# TODO Should probably be handled in easyscience
for i in range(len(sample.data)):
sample[i] = sample[i].__class__.from_dict(data['data'][i])
return sample