diff --git a/src/nomad_material_processing/__init__.py b/src/nomad_material_processing/__init__.py index 4c1992a..a0d1cbe 100644 --- a/src/nomad_material_processing/__init__.py +++ b/src/nomad_material_processing/__init__.py @@ -29,6 +29,8 @@ ElementalComposition, SynthesisMethod, CompositeSystem, + CompositeSystemReference, + SystemComponent, ) from nomad.datamodel.data import ( ArchiveSection, @@ -49,287 +51,374 @@ BoundLogger, ) -m_package = Package(name='Material Processing') +m_package = Package(name="Material Processing") class Geometry(ArchiveSection): - ''' + """ Geometrical shape attributes of a system. Sections derived from `Geometry` represent concrete geometrical shapes. - ''' - m_def = Section( - ) + """ + + m_def = Section() volume = Quantity( type=float, - description='The measure of the amount of space occupied in 3D space.', + description="The measure of the amount of space occupied in 3D space.", a_eln=ELNAnnotation( component=ELNComponentEnum.NumberEditQuantity, ), - unit='meter ** 3', + unit="meter ** 3", ) class Parallelepiped(Geometry): - ''' - Six-faced polyhedron with each pair of opposite faces parallel and equal in size, + """ + Six-faced polyhedron with each pair of opposite faces parallel and equal in size, characterized by rectangular sides and parallelogram faces. - ''' - m_def = Section( - ) + """ + + m_def = Section() height = Quantity( type=float, - description='The z dimension of the parallelepiped.', + description="The z dimension of the parallelepiped.", a_eln=ELNAnnotation( component=ELNComponentEnum.NumberEditQuantity, - defaultDisplayUnit='millimeter', - label='Height (z)', + defaultDisplayUnit="millimeter", + label="Height (z)", ), - unit='meter', + unit="meter", ) width = Quantity( type=float, - description='The x dimension of the parallelepiped.', + description="The x dimension of the parallelepiped.", a_eln=ELNAnnotation( component=ELNComponentEnum.NumberEditQuantity, - defaultDisplayUnit='millimeter', - label='Width (x)', + defaultDisplayUnit="millimeter", + label="Width (x)", ), - unit='meter', + unit="meter", ) length = Quantity( type=float, - description='The y dimension of the parallelepiped.', + description="The y dimension of the parallelepiped.", a_eln=ELNAnnotation( component=ELNComponentEnum.NumberEditQuantity, - defaultDisplayUnit='millimeter', - label='Length (y)', + defaultDisplayUnit="millimeter", + label="Length (y)", ), - unit='meter' + unit="meter", ) surface_area = Quantity( type=float, - description=''' + description=""" The product of length and width, representing the total exposed area of the primary surface. - ''', + """, a_eln=ELNAnnotation( component=ELNComponentEnum.NumberEditQuantity, - defaultDisplayUnit='millimeter ** 2', - label='Surface Area (x*y)', + defaultDisplayUnit="millimeter ** 2", + label="Surface Area (x*y)", ), - unit='meter ** 2', + unit="meter ** 2", ) class Miscut(ArchiveSection): - ''' - The miscut in a crystalline substrate refers to - the intentional deviation from a specific crystallographic orientation, + """ + The miscut in a crystalline substrate refers to + the intentional deviation from a specific crystallographic orientation, commonly expressed as the angular displacement of a crystal plane. - ''' + """ + angle = Quantity( type=float, - description=''' + description=""" The angular displacement from the crystallographic orientation of the substrate. - ''', + """, a_eln=ELNAnnotation( component=ELNComponentEnum.NumberEditQuantity, - defaultDisplayUnit='deg', - label='Miscut Angle', + defaultDisplayUnit="deg", + label="Miscut Angle", ), - unit='deg', + unit="deg", ) angle_deviation = Quantity( type=float, - description='The ± uncertainty in the angular displacement.', + description="The ± uncertainty in the angular displacement.", a_eln=ELNAnnotation( component=ELNComponentEnum.NumberEditQuantity, - defaultDisplayUnit='deg', - label='± Miscut Angle Deviation', + defaultDisplayUnit="deg", + label="± Miscut Angle Deviation", ), - unit='deg', + unit="deg", ) orientation = Quantity( type=str, - description='The direction of the miscut in Miller index, [hkl].', + description="The direction of the miscut in Miller index, [hkl].", a_eln=ELNAnnotation( component=ELNComponentEnum.StringEditQuantity, - label='Miscut Orientation [hkl]', - ) + label="Miscut Orientation [hkl]", + ), ) class Dopant(ElementalComposition): - ''' - A dopant element in a crystalline structure + """ + A dopant element in a crystalline structure is a foreign atom intentionally introduced into the crystal lattice. - ''' + """ + doping_level = Quantity( type=float, - description='The chemical doping level.', + description="The chemical doping level.", a_eln=ELNAnnotation( component=ELNComponentEnum.NumberEditQuantity, - defaultDisplayUnit='1 / cm ** 3', + defaultDisplayUnit="1 / cm ** 3", ), - unit='1 / m ** 3', + unit="1 / m ** 3", ) class CrystalProperties(ArchiveSection): - ''' + """ Characteristics arising from the ordered arrangement of atoms in a crystalline structure. - These properties are defined by factors such as crystal symmetry, lattice parameters, + These properties are defined by factors such as crystal symmetry, lattice parameters, and the specific arrangement of atoms within the crystal lattice. - ''' + """ class SubstrateCrystalProperties(CrystalProperties): - ''' + """ Crystallographic parameters such as orientation, miscut, and surface structure. - ''' + """ + orientation = Quantity( type=str, - description=''' - Alignment of crystal lattice with respect to a vector normal to the surface + description=""" + Alignment of crystal lattice with respect to a vector normal to the surface specified using Miller indices. - ''', + """, a_eln=ELNAnnotation( component=ELNComponentEnum.StringEditQuantity, - label='Substrate Orientation (hkl)', + label="Substrate Orientation (hkl)", ), ) miscut = SubSection( section_def=Miscut, - description=''' + description=""" Section describing any miscut of the substrate with respect to the substrate orientation. - ''', + """, ) class Substrate(CompositeSystem): - ''' + """ A thin free standing sheet of material. Not to be confused with the substrate role during a deposition, which can be a `Substrate` with `ThinFilm`(s) on it. - ''' + """ + m_def = Section() supplier = Quantity( type=str, - description='The supplier of the current substrate specimen.', + description="The supplier of the current substrate specimen.", a_eln=ELNAnnotation( component=ELNComponentEnum.StringEditQuantity, - label='Name of Supplier', - ) + label="Name of Supplier", + ), ) supplier_id = Quantity( type=str, - description='An ID string that is unique from the supplier.', + description="An ID string that is unique from the supplier.", a_eln=ELNAnnotation( component=ELNComponentEnum.StringEditQuantity, - label='Supplier ID', + label="Supplier ID", ), ) lab_id = Quantity( type=str, a_eln=ELNAnnotation( component=ELNComponentEnum.StringEditQuantity, - label='Substrate ID', + label="Substrate ID", ), ) class CrystallineSubstrate(Substrate): - ''' + """ The substrate defined in this class is composed of periodic arrangement of atoms and shows typical features of a crystal structure. - ''' + """ + m_def = Section() geometry = SubSection( section_def=Geometry, - description='Section containing the geometry of the substrate.', + description="Section containing the geometry of the substrate.", ) crystal_properties = SubSection( section_def=SubstrateCrystalProperties, - description='Section containing the crystal properties of the substrate.', + description="Section containing the crystal properties of the substrate.", ) dopants = SubSection( section_def=Dopant, repeats=True, - description=''' + description=""" Repeating section containing information on any dopants in the substrate. - ''', + """, ) class ThinFilm(CompositeSystem): - ''' + """ A thin film of material which exists as part of a stack. - ''' + """ + m_def = Section() geometry = SubSection( section_def=Geometry, - description='Section containing the geometry of the thin film.', + description="Section containing the geometry of the thin film.", ) -class ThinFilmStack(CompositeSystem): - ''' - A stack of `ThinFilm`(s). Typically deposited on a `Substrate`. - ''' - m_def = Section() - substrate = Quantity( +class ThinFilmReference(CompositeSystemReference): + """ + Class autogenerated from yaml schema. + """ + + lab_id = Quantity( + type=str, + a_eln=ELNAnnotation( + component=ELNComponentEnum.StringEditQuantity, + label="Thin Film ID", + ), + ) + reference = Quantity( + type=ThinFilm, + a_eln=ELNAnnotation( + component=ELNComponentEnum.ReferenceEditQuantity, + label="Thin Film", + ), + ) + + +class SubstrateReference(CompositeSystemReference): + """ + A section for describing a system component and its role in a composite system. + """ + + lab_id = Quantity( + type=str, + a_eln=ELNAnnotation( + component=ELNComponentEnum.StringEditQuantity, + label="Substrate ID", + ), + ) + reference = Quantity( type=Substrate, - description=''' - The substrate which the thin film layers of the thin film stack are deposited - on. - ''', a_eln=ELNAnnotation( component=ELNComponentEnum.ReferenceEditQuantity, + label="Substrate", ), ) - layers = Quantity( - type=ThinFilm, - description=''' + + +class ThinFilmStack(CompositeSystem): + """ + A stack of `ThinFilm`(s). Typically deposited on a `Substrate`. + """ + + m_def = Section( + a_eln=ELNAnnotation( + hide=[ + "components", + ], + ), + ) + layers = SubSection( + description=""" An ordered list (starting at the substrate) of the thin films making up the thin film stacks. - ''', + """, + section_def=ThinFilmReference, + repeats=True, + ) + substrate = SubSection( + description=""" + The substrate which the thin film layers of the thin film stack are deposited + on. + """, + section_def=SubstrateReference, + ) + + def normalize(self, archive: "EntryArchive", logger: "BoundLogger") -> None: + """ + The normalizer for the `ThinFilmStack` class. + + Args: + archive (EntryArchive): The archive containing the section that is being + normalized. + logger (BoundLogger): A structlog logger. + """ + self.components = [] + if self.layers: + self.components = [ + SystemComponent(system=layer.reference) for layer in self.layers if layer.reference + ] + if self.substrate.reference: + self.components.append(SystemComponent(system=self.substrate.reference)) + super().normalize(archive, logger) + + +class ThinFilmStackReference(CompositeSystemReference): + """ + Class autogenerated from yaml schema. + """ + + m_def = Section() + lab_id = Quantity( + type=str, + a_eln=ELNAnnotation( + component=ELNComponentEnum.StringEditQuantity, + ), + ) + reference = Quantity( + type=ThinFilmStack, a_eln=ELNAnnotation( component=ELNComponentEnum.ReferenceEditQuantity, ), - shape=["*"], ) class SampleDeposition(SynthesisMethod): - ''' + """ The process of the settling of particles (atoms or molecules) from a solution, suspension or vapour onto a pre-existing surface, resulting in the growth of a new phase. [database_cross_reference: https://orcid.org/0000-0002-0640-0422] Synonyms: - deposition - ''' + """ + m_def = Section( - links=[ - "http://purl.obolibrary.org/obo/CHMO_0001310" - ],) + links=["http://purl.obolibrary.org/obo/CHMO_0001310"], + ) def is_serial(self) -> bool: - ''' + """ Method for determining if the steps are serial. Can be overwritten by sub class. Default behavior is to return True if all steps start after the previous one. Returns: bool: Whether or not the steps are serial. - ''' + """ start_times = [] durations = [] for step in self.steps: if step.start_time is None or step.duration is None: return False start_times.append(step.start_time.timestamp()) - durations.append(step.duration.to('s').magnitude) + durations.append(step.duration.to("s").magnitude) start_times = np.array(start_times) durations = np.array(durations) end_times = start_times + durations @@ -338,15 +427,15 @@ def is_serial(self) -> bool: return False return True - def normalize(self, archive: 'EntryArchive', logger: 'BoundLogger') -> None: - ''' + def normalize(self, archive: "EntryArchive", logger: "BoundLogger") -> None: + """ The normalizer for the `SampleDeposition` class. Args: archive (EntryArchive): The archive containing the section that is being normalized. logger (BoundLogger): A structlog logger. - ''' + """ super().normalize(archive, logger) if self.is_serial(): tasks = [] @@ -357,7 +446,7 @@ def normalize(self, archive: 'EntryArchive', logger: 'BoundLogger') -> None: if previous is not None: task.inputs.append(Link(name=previous.name, section=previous)) tasks.append(task) - previous=step + previous = step archive.workflow2.tasks = tasks diff --git a/src/nomad_material_processing/chemical_vapor_deposition.py b/src/nomad_material_processing/chemical_vapor_deposition.py new file mode 100644 index 0000000..c94eee4 --- /dev/null +++ b/src/nomad_material_processing/chemical_vapor_deposition.py @@ -0,0 +1,214 @@ +# +# Copyright The NOMAD Authors. +# +# This file is part of NOMAD. See https://nomad-lab.eu for further info. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +from typing import ( + TYPE_CHECKING, +) +from nomad.metainfo import ( + Package, + Section, + SubSection, + Quantity, + MEnum, +) +from nomad.datamodel.data import ( + ArchiveSection, +) +from nomad.datamodel.metainfo.annotations import ( + ELNAnnotation, + ELNComponentEnum, +) +from nomad.datamodel.metainfo.basesections import ( + ActivityStep, + CompositeSystem, + PureSubstanceSection, + ReadableIdentifiers, +) +from nomad_material_processing import ( + SampleDeposition, +) + +from nomad_material_processing.vapor_deposition import ( + VaporRate, + EvaporationSource, + VaporDepositionSource, + VaporDepositionStep, + VaporDeposition, +) + +from nomad.datamodel.metainfo.plot import PlotSection, PlotlyFigure + +if TYPE_CHECKING: + from nomad.datamodel.datamodel import ( + EntryArchive, + ) + from structlog.stdlib import ( + BoundLogger, + ) + +m_package = Package(name="Chemical Vapor Deposition") + + +class CVDEvaporationSource(EvaporationSource): + pass + + +class CVDBubbler(CVDEvaporationSource): + """ + Delivers precursor materials to the reaction chamber. + It serves as a mechanism for introducing volatile liquid or solid precursors into the gas phase, + where they can react and deposit onto a substrate surface to form thin films or coatings. + + Key components: + - Bubbler Vessel: This vessel holds the precursor material. + - Heating Element: To facilitate vaporization. + - Gas Inlet and Outlet: Gas delivery system via gas inlet and outlet ports. + - Temperature Control: Maintain the vapor pressure of the precursor at the desired level. + + Operation: + - Loading Precursor: The precursor material is loaded into the bubbler vessel + - Heating: The heating element is activated to form a vapor phase above the liquid or solid. + - Gas Flow: Carrier gas is bubbled through the precursor material. + - Transport: The precursor vapor is delivered to the reaction chamber. + The precursor undergoes decomposition or reaction on the substrate surface, + leading to thin film growth. + """ + + temperature = Quantity( + type=float, + description="Temperature of the bubbler, used to calculate the precursor partial pressure.", + a_eln=ELNAnnotation( + component=ELNComponentEnum.NumberEditQuantity, + defaultDisplayUnit="mbar", + ), + unit="mbar", + ) + pressure = Quantity( + type=float, + description="The back-pressur ein the tube carrying the bubbler material.", + a_eln=ELNAnnotation( + component=ELNComponentEnum.NumberEditQuantity, + defaultDisplayUnit="mbar", + ), + unit="mbar", + ) + partial_pressure = Quantity( + type=float, + description="Calculated with the August-Antoine equation: 1.33322*10^[(A-B)/T].", + a_eln=ELNAnnotation( + component=ELNComponentEnum.NumberEditQuantity, + defaultDisplayUnit="mbar", + ), + unit="mbar", + ) + dilution = Quantity( + type=float, + description="ONLY FOR DOPING PRECURSOR", + a_eln=ELNAnnotation( + component=ELNComponentEnum.NumberEditQuantity, + defaultDisplayUnit="cm ** 3 / minute", + ), + unit="cm ** 3 / minute", + ) + source = Quantity( + type=float, + description="ONLY FOR DOPING PRECURSOR", + a_eln=ELNAnnotation( + component=ELNComponentEnum.NumberEditQuantity, + defaultDisplayUnit="cm ** 3 / minute", + ), + unit="cm ** 3 / minute", + ) + inject = Quantity( + type=float, + description="ONLY FOR DOPING PRECURSOR", + a_eln=ELNAnnotation( + component=ELNComponentEnum.NumberEditQuantity, + defaultDisplayUnit="cm ** 3 / minute", + ), + unit="cm ** 3 / minute", + ) + + +class CVDVaporRate(VaporRate): + m_def = Section( + a_plot=dict( + x="process_time", + y="rate", + ), + ) + mass_flow_controller = Quantity( + type=float, + description="Flux of material with mass flow controller.", + a_eln={ + "component": "NumberEditQuantity", + "defaultDisplayUnit": "cm ** 3 / minute", + }, + unit="cm ** 3 / minute", + ) + rate = Quantity( + type=float, + description="FILL THE DESCRIPTION", + a_eln=ELNAnnotation( + component=ELNComponentEnum.NumberEditQuantity, + defaultDisplayUnit="mol / minute", + ), + shape=["*"], + unit="mol / minute", + label="Molar flux", + ) + process_time = Quantity( + type=float, + unit="second", + shape=["*"], + ) + measurement_type = Quantity( + type=MEnum( + "Assumed", + "Mass Flow Controller", + ) + ) + + +class CVDSource(VaporDepositionSource): + m_def = Section( + a_plot=dict( + x="deposition_rate/process_time", + y="deposition_rate/rate", + ), + ) + name = Quantity( + type=str, + description=""" + A short and descriptive name for this source. + """, + ) + vapor_source = SubSection( + section_def=CVDEvaporationSource, + description=""" + Example: A heater, a filament, a laser, a bubbler, etc. + """, + ) + vapor_rate = SubSection( + section_def=CVDVaporRate, + description=""" + The rate of the material being evaporated (mol/time). + """, + ) + + +m_package.__init_metainfo__() diff --git a/src/nomad_material_processing/physical_vapor_deposition.py b/src/nomad_material_processing/physical_vapor_deposition.py index bcdd884..eb46064 100644 --- a/src/nomad_material_processing/physical_vapor_deposition.py +++ b/src/nomad_material_processing/physical_vapor_deposition.py @@ -33,15 +33,17 @@ ELNComponentEnum, ) from nomad.datamodel.metainfo.basesections import ( - ActivityStep, CompositeSystem, - PureSubstanceSection, + CompositeSystemReference, ReadableIdentifiers, ) -from nomad_material_processing import ( - SampleDeposition, - ThinFilmStack, - ThinFilm, + +from nomad_material_processing.vapor_deposition import ( + EvaporationSource, + VaporDepositionSource, + SampleParameters, + VaporDepositionStep, + VaporDeposition, ) if TYPE_CHECKING: @@ -52,302 +54,148 @@ BoundLogger, ) -m_package = Package(name='Physical Vapor Deposition') +m_package = Package(name="Physical Vapor Deposition") -class PVDMaterialEvaporationRate(ArchiveSection): +class SourcePower(ArchiveSection): m_def = Section( a_plot=dict( - x='process_time', - y='rate', + x="process_time", + y="power", ), ) - rate = Quantity( + power = Quantity( type=float, - unit='mol/meter ** 2/second', - shape=['*'], - a_eln=ELNAnnotation( - defaultDisplayUnit='micromol/m ** 2/second', - ), + unit="watt", + shape=["*"], ) process_time = Quantity( type=float, - unit='second', - shape=['*'], - a_eln=ELNAnnotation( - defaultDisplayUnit='second', - ), - ) - measurement_type = Quantity( - type=MEnum( - 'Assumed', - 'Quartz Crystal Microbalance', - 'RHEED', - ) + unit="second", + shape=["*"], ) -class PVDMaterialSource(ArchiveSection): +class PVDEvaporationSource(EvaporationSource): m_def = Section( a_plot=dict( - x='rate/process_time', - y='rate/rate', + x="power/process_time", + y="power/power", ), ) - material = Quantity( - description=''' - The material that is being evaporated. - ''', - type=CompositeSystem, - ) - rate = SubSection( - section_def=PVDMaterialEvaporationRate, + power = SubSection( + section_def=SourcePower, ) -class PVDSourcePower(ArchiveSection): +class ImpingingFlux(ArchiveSection): m_def = Section( a_plot=dict( - x='process_time', - y='power', + x="process_time", + y="rate", ), ) - power = Quantity( + rate = Quantity( type=float, - unit='watt', - shape=['*'], - a_eln=ELNAnnotation( - defaultDisplayUnit='watt', - ), + unit="mol/meter ** 2/second", + shape=["*"], ) process_time = Quantity( type=float, - unit='second', - shape=['*'], - a_eln=ELNAnnotation( - defaultDisplayUnit='second', - ), - ) - - -class PVDEvaporationSource(ArchiveSection): - m_def = Section( - a_plot=dict( - x='power/process_time', - y='power/power', - ), + unit="second", + shape=["*"], ) - power = SubSection( - section_def=PVDSourcePower, + measurement_type = Quantity( + type=MEnum( + "Assumed", + "Quartz Crystal Microbalance", + ) ) -class PVDSource(ArchiveSection): +class PVDSource(VaporDepositionSource): m_def = Section( a_plot=[ dict( x=[ - 'evaporation_source/power/process_time', - 'material_source/rate/process_time', + "evaporation_source/power/process_time", + "material_source/rate/process_time", ], y=[ - 'evaporation_source/power/power', - 'material_source/rate/rate', - ] + "evaporation_source/power/power", + "material_source/rate/rate", + ], ), ], ) - name = Quantity( - type=str, - description=''' - A short and descriptive name for this source. - ''' - ) - material_source = SubSection( - section_def=PVDMaterialSource, - ) - evaporation_source = SubSection( + vapor_source = SubSection( section_def=PVDEvaporationSource, + description=""" + Example: A heater, a filament, a laser, etc. + """, + ) + impinging_flux = SubSection( + section_def=ImpingingFlux, + description=""" + The deposition rate of the material onto the substrate (mol/area/time). + """, + repeats=True, ) -class PVDSubstrateTemperature(ArchiveSection): - m_def = Section( - a_plot=dict( - x='process_time', - y='temperature', - ), - ) - temperature = Quantity( - type=float, - unit='kelvin', - shape=['*'], - a_eln=ELNAnnotation( - defaultDisplayUnit='celsius', - ), - ) - process_time = Quantity( - type=float, - unit='second', - shape=['*'], - a_eln=ELNAnnotation( - defaultDisplayUnit='second', - ), - ) - measurement_type = Quantity( - type=MEnum( - 'Heater thermocouple', - 'Pyrometer', - ) - ) - - -class PVDSubstrate(ArchiveSection): - m_def = Section( - a_plot=dict( - x='temperature/process_time', - y='temperature/temperature', - ), - ) - substrate = Quantity( - description=''' - The thin film stack that is being evaporated on. - ''', - type=ThinFilmStack, - ) - thin_film = Quantity( - description=''' - The thin film that is being created during this step. - ''', - type=ThinFilm, - ) - temperature = SubSection( - section_def=PVDSubstrateTemperature, - ) +class PVDSampleParameters(SampleParameters): heater = Quantity( + description=""" + What is the substrate heated by. + """, type=MEnum( - 'No heating', - 'Halogen lamp', - 'Filament', - 'Resistive element', - 'CO2 laser', - ) - ) - distance_to_source = Quantity( - type=float, - unit='meter', - shape=['*'], - # a_eln=ELNAnnotation( - # defaultDisplayUnit='millimeter', - # ), - ) - - -class PVDPressure(ArchiveSection): - m_def = Section( - a_plot=dict( - x='process_time', - y='pressure', - ), - ) - pressure = Quantity( - type=float, - unit='pascal', - shape=['*'], - a_eln=ELNAnnotation( - defaultDisplayUnit='millibar', + "No heating", + "Halogen lamp", + "Filament", + "Resistive element", + "CO2 laser", ), ) - process_time = Quantity( - type=float, - unit='second', - shape=['*'], - a_eln=ELNAnnotation( - defaultDisplayUnit='second', - ), - ) - - -class PVDGasFlow(ArchiveSection): - gas = SubSection( - section_def=PureSubstanceSection, - ) - flow = Quantity( - type=float, - unit='meter ** 3 / second', - shape=['*'], - ) - process_time = Quantity( + distance_to_source = Quantity( type=float, - unit='second', - shape=['*'], - # a_eln=ELNAnnotation( - # defaultDisplayUnit='second', - # ), - ) - - -class PVDChamberEnvironment(ArchiveSection): - m_def = Section( - a_plot=dict( - x='pressure/process_time', - y='pressure/pressure', - ), - ) - gas_flow = SubSection( - section_def=PVDGasFlow, - repeats=True, - ) - pressure = SubSection( - section_def=PVDPressure, + unit="meter", + description=""" + The distance between the substrate and all the sources. + In the case of multiple sources, the distances are listed in the same order as the + sources are listed in the parent `VaporDepositionStep` section. + """, + shape=["*"], ) -class PVDStep(ActivityStep): - ''' +class PVDStep(VaporDepositionStep): + """ A step of any physical vapor deposition process. - ''' - m_def = Section() - creates_new_thin_film = Quantity( - type=bool, - description=''' - Whether or not this step creates a new thin film. - ''', - default=False, - a_eln=ELNAnnotation( - component='BoolEditQuantity', - ), - ) - duration = Quantity( - type=float, - unit='second' - ) + """ + sources = SubSection( section_def=PVDSource, repeats=True, ) - substrate = SubSection( - section_def=PVDSubstrate, + sample_parameters = SubSection( + section_def=PVDSampleParameters, repeats=True, ) - environment = SubSection( - section_def=PVDChamberEnvironment, - ) - def normalize(self, archive: 'EntryArchive', logger: 'BoundLogger') -> None: - ''' + def normalize(self, archive: "EntryArchive", logger: "BoundLogger") -> None: + """ The normalizer for the `PVDStep` class. Args: archive (EntryArchive): The archive containing the section that is being normalized. logger (BoundLogger): A structlog logger. - ''' + """ super(PVDStep, self).normalize(archive, logger) -class PhysicalVaporDeposition(SampleDeposition): - ''' +class PhysicalVaporDeposition(VaporDeposition): + """ A synthesis technique where vaporized molecules or atoms condense on a surface, forming a thin layer. The process is purely physical; no chemical reaction occurs at the surface. [database_cross_reference: https://orcid.org/0000-0002-0640-0422] @@ -355,55 +203,59 @@ class PhysicalVaporDeposition(SampleDeposition): Synonyms: - PVD - physical vapor deposition - ''' + """ + m_def = Section( links=["http://purl.obolibrary.org/obo/CHMO_0001356"], a_plot=[ dict( - x='steps/:/environment/pressure/process_time', - y='steps/:/environment/pressure/pressure', + x="steps/:/environment/pressure/process_time", + y="steps/:/environment/pressure/pressure", ), dict( - x='steps/:/source/:/evaporation_source/power/process_time', - y='steps/:/source/:/evaporation_source/power/power', + x="steps/:/source/:/evaporation_source/power/process_time", + y="steps/:/source/:/evaporation_source/power/power", ), ], ) steps = SubSection( - description=''' + description=""" The steps of the deposition process. - ''', + """, section_def=PVDStep, repeats=True, ) - def normalize(self, archive: 'EntryArchive', logger: 'BoundLogger') -> None: - ''' + def normalize(self, archive: "EntryArchive", logger: "BoundLogger") -> None: + """ The normalizer for the `PhysicalVaporDeposition` class. Args: archive (EntryArchive): The archive containing the section that is being normalized. logger (BoundLogger): A structlog logger. - ''' + """ super(PhysicalVaporDeposition, self).normalize(archive, logger) class PLDTarget(CompositeSystem): target_id = SubSection( - section_def = ReadableIdentifiers, + section_def=ReadableIdentifiers, ) -class PLDTargetSource(PVDMaterialSource): - material = Quantity( - description=''' - The material that is being evaporated. - ''', +class PLDTargetReference(CompositeSystemReference): + lab_id = Quantity( + type=str, + a_eln=ELNAnnotation( + component=ELNComponentEnum.StringEditQuantity, + label="Target ID", + ), + ) + reference = Quantity( type=PLDTarget, a_eln=ELNAnnotation( - label='Target', - component=ELNComponentEnum.ReferenceEditQuantity + component=ELNComponentEnum.ReferenceEditQuantity, ), ) @@ -411,39 +263,52 @@ class PLDTargetSource(PVDMaterialSource): class PLDLaser(PVDEvaporationSource): wavelength = Quantity( type=float, - unit='meter', - # a_eln=ELNAnnotation( - # defaultDisplayUnit='nanometer', - # ), + unit="meter", + a_eln=ELNAnnotation( + component=ELNComponentEnum.NumberEditQuantity, + defaultDisplayUnit="nanometer", + ), ) repetition_rate = Quantity( type=float, - unit='hertz', - # a_eln=ELNAnnotation( - # defaultDisplayUnit='hertz', - # ), + unit="hertz", + a_eln=ELNAnnotation( + component=ELNComponentEnum.NumberEditQuantity, + defaultDisplayUnit="hertz", + ), ) spot_size = Quantity( type=float, - unit='meter ** 2', - # a_eln=ELNAnnotation( - # defaultDisplayUnit='millimeter ** 2', - # ), + unit="meter ** 2", + a_eln=ELNAnnotation( + component=ELNComponentEnum.NumberEditQuantity, + defaultDisplayUnit="millimeter ** 2", + ), ) pulses = Quantity( - description=''' + description=""" The total number of laser pulses during the deposition step. - ''', + """, type=int, + a_eln=ELNAnnotation( + component=ELNComponentEnum.NumberEditQuantity, + ), ) class PLDSource(PVDSource): - material_source = SubSection( - section_def=PLDTargetSource, - ) - evaporation_source = SubSection( + material = SubSection( + section_def=PLDTargetReference, + description=""" + The source of the material that is being evaporated. + Example: A sputtering target, a powder in a crucible, etc. + """, + ) + vapor_source = SubSection( section_def=PLDLaser, + description=""" + Section containing the details of the laser source. + """, ) @@ -455,7 +320,7 @@ class PLDStep(PVDStep): class PulsedLaserDeposition(PhysicalVaporDeposition): - ''' + """ A synthesis technique where a high-power pulsed laser beam is focused (inside a vacuum chamber) onto a target of the desired composition. Material is then vaporized from the target ('ablation') and deposited as a thin film on a @@ -469,36 +334,37 @@ class PulsedLaserDeposition(PhysicalVaporDeposition): - laser ablation growth - PLA deposition - pulsed-laser deposition - ''' + """ + m_def = Section( links=["http://purl.obolibrary.org/obo/CHMO_0001363"], ) method = Quantity( type=str, - default='Pulsed Laser Deposition' + default="Pulsed Laser Deposition", ) steps = SubSection( - description=''' + description=""" The steps of the deposition process. - ''', + """, section_def=PLDStep, repeats=True, ) - def normalize(self, archive: 'EntryArchive', logger: 'BoundLogger') -> None: - ''' + def normalize(self, archive: "EntryArchive", logger: "BoundLogger") -> None: + """ The normalizer for the `PulsedLaserDeposition` class. Args: archive (EntryArchive): The archive containing the section that is being normalized. logger (BoundLogger): A structlog logger. - ''' + """ super(PulsedLaserDeposition, self).normalize(archive, logger) class SputterDeposition(PhysicalVaporDeposition): - ''' + """ A synthesis technique where a solid target is bombarded with electrons or energetic ions (e.g. Ar+) causing atoms to be ejected ('sputtering'). The ejected atoms then deposit, as a thin-film, on a substrate. @@ -507,49 +373,44 @@ class SputterDeposition(PhysicalVaporDeposition): Synonyms: - sputtering - sputter coating - ''' + """ + m_def = Section( links=["http://purl.obolibrary.org/obo/CHMO_0001364"], ) method = Quantity( type=str, - default='Sputter Deposition' + default="Sputter Deposition", ) - def normalize(self, archive: 'EntryArchive', logger: 'BoundLogger') -> None: - ''' + def normalize(self, archive: "EntryArchive", logger: "BoundLogger") -> None: + """ The normalizer for the `SputterDeposition` class. Args: archive (EntryArchive): The archive containing the section that is being normalized. logger (BoundLogger): A structlog logger. - ''' + """ super(SputterDeposition, self).normalize(archive, logger) class ThermalEvaporationHeaterTemperature(ArchiveSection): m_def = Section( a_plot=dict( - x='process_time', - y='temperature', + x="process_time", + y="temperature", ), ) temperature = Quantity( type=float, - unit='kelvin', - shape=['*'], - a_eln=ELNAnnotation( - defaultDisplayUnit='celsius', - ), + unit="kelvin", + shape=["*"], ) process_time = Quantity( type=float, - unit='second', - shape=['*'], - a_eln=ELNAnnotation( - defaultDisplayUnit='second', - ), + unit="second", + shape=["*"], ) @@ -557,24 +418,24 @@ class ThermalEvaporationHeater(PVDEvaporationSource): m_def = Section( a_plot=dict( x=[ - 'temperature/process_time', - 'power/process_time', + "temperature/process_time", + "power/process_time", ], y=[ - 'temperature/temperature', - 'power/power', + "temperature/temperature", + "power/power", ], lines=[ dict( - mode= 'lines', + mode="lines", line=dict( - color='rgb(25, 46, 135)', + color="rgb(25, 46, 135)", ), ), dict( - mode= 'lines', + mode="lines", line=dict( - color='rgb(0, 138, 104)', + color="rgb(0, 138, 104)", ), ), ], @@ -589,33 +450,30 @@ class ThermalEvaporationSource(PVDSource): m_def = Section( a_plot=dict( x=[ - 'material_source/rate/process_time', - 'evaporation_source/temperature/process_time', + "deposition_rate/process_time", + "vapor_source/temperature/process_time", ], y=[ - 'material_source/rate/rate', - 'evaporation_source/temperature/temperature', + "deposition_rate/rate", + "vapor_source/temperature/temperature", ], lines=[ dict( - mode= 'lines', + mode="lines", line=dict( - color='rgb(25, 46, 135)', + color="rgb(25, 46, 135)", ), ), dict( - mode= 'lines', + mode="lines", line=dict( - color='rgb(0, 138, 104)', + color="rgb(0, 138, 104)", ), ), ], ), ) - material_source = SubSection( - section_def=PVDMaterialSource, - ) - evaporation_source = SubSection( + vapor_source = SubSection( section_def=ThermalEvaporationHeater, ) @@ -624,16 +482,16 @@ class ThermalEvaporationStep(PVDStep): m_def = Section( a_plot=[ dict( - x='sources/:/material_source/rate/process_time', - y='sources/:/material_source/rate/rate', + x="sources/:/deposition_rate/process_time", + y="sources/:/deposition_rate/rate", ), dict( - x='sources/:/evaporation_source/temperature/process_time', - y='sources/:/evaporation_source/temperature/temperature', + x="sources/:/vapor_source/temperature/process_time", + y="sources/:/vapor_source/temperature/temperature", ), dict( - x='sources/:/evaporation_source/power/process_time', - y='sources/:/evaporation_source/power/power', + x="sources/:/vapor_source/power/process_time", + y="sources/:/vapor_source/power/power", ), ], ) @@ -644,7 +502,7 @@ class ThermalEvaporationStep(PVDStep): class ThermalEvaporation(PhysicalVaporDeposition): - ''' + """ A synthesis technique where the material to be deposited is heated until evaporation in a vacuum (<10^{-4} Pa) and eventually deposits as a thin film by condensing on a (cold) substrate. @@ -657,24 +515,25 @@ class ThermalEvaporation(PhysicalVaporDeposition): - thermal deposition - filament evaporation - vacuum condensation - ''' + """ + m_def = Section( links=["http://purl.obolibrary.org/obo/CHMO_0001360"], a_plot=[ dict( - x='steps/:/sources/:/material_source/rate/process_time', - y='steps/:/sources/:/material_source/rate/rate', + x="steps/:/sources/:/deposition_rate/process_time", + y="steps/:/sources/:/deposition_rate/rate", + ), + dict( + x="steps/:/sources/:/vapor_source/temperature/process_time", + y="steps/:/sources/:/vapor_source/temperature/temperature", ), - # dict( - # x='steps/:/sources/:/evaporation_source/temperature/process_time', - # y='steps/:/sources/:/evaporation_source/temperature/temperature', - # ), dict( - x='steps/:/environment/pressure/process_time', - y='steps/:/environment/pressure/pressure', + x="steps/:/environment/pressure/process_time", + y="steps/:/environment/pressure/pressure", layout=dict( yaxis=dict( - type='log', + type="log", ), ), ), @@ -682,18 +541,25 @@ class ThermalEvaporation(PhysicalVaporDeposition): ) method = Quantity( type=str, - default='Thermal Evaporation' + default="Thermal Evaporation", + ) + steps = SubSection( + description=""" + The steps of the deposition process. + """, + section_def=ThermalEvaporationStep, + repeats=True, ) - def normalize(self, archive: 'EntryArchive', logger: 'BoundLogger') -> None: - ''' + def normalize(self, archive: "EntryArchive", logger: "BoundLogger") -> None: + """ The normalizer for the `ThermalEvaporation` class. Args: archive (EntryArchive): The archive containing the section that is being normalized. logger (BoundLogger): A structlog logger. - ''' + """ super(ThermalEvaporation, self).normalize(archive, logger) diff --git a/src/nomad_material_processing/vapor_deposition.py b/src/nomad_material_processing/vapor_deposition.py new file mode 100644 index 0000000..255a7ec --- /dev/null +++ b/src/nomad_material_processing/vapor_deposition.py @@ -0,0 +1,435 @@ +# +# Copyright The NOMAD Authors. +# +# This file is part of NOMAD. See https://nomad-lab.eu for further info. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +from typing import ( + TYPE_CHECKING, +) +from nomad.metainfo import ( + Package, + Section, + SubSection, + Quantity, + MEnum, +) +from nomad.datamodel.data import ( + ArchiveSection, +) +from nomad.datamodel.metainfo.annotations import ( + ELNAnnotation, +) +from nomad.datamodel.metainfo.basesections import ( + ActivityStep, + PureSubstanceSection, + CompositeSystemReference, +) +from nomad.datamodel.metainfo.plot import ( + PlotSection, +) +from nomad.datamodel.metainfo.workflow import ( + Link, + Task, +) +from nomad_material_processing import ( + SampleDeposition, + ThinFilmStackReference, + ThinFilmReference, +) + +if TYPE_CHECKING: + from nomad.datamodel.datamodel import ( + EntryArchive, + ) + from structlog.stdlib import ( + BoundLogger, + ) + +m_package = Package(name="Vapor Deposition") + + +class VaporRate(ArchiveSection): + m_def = Section( + a_plot=dict( + x="process_time", + y="rate", + ), + ) + rate = Quantity( + type=float, + unit="mol/second", + shape=["*"], + ) + process_time = Quantity( + type=float, + unit="second", + shape=["*"], + ) + measurement_type = Quantity( + type=MEnum( + "Assumed", + "Mass Flow Controller", + ) + ) + + +class EvaporationSource(ArchiveSection): + pass + + +class VaporDepositionSource(ArchiveSection): + m_def = Section( + a_plot=dict( + x="deposition_rate/process_time", + y="deposition_rate/rate", + ), + ) + name = Quantity( + type=str, + description=""" + A short and descriptive name for this source. + """, + ) + material = SubSection( + section_def=CompositeSystemReference, + description=""" + The source of the material that is being evaporated. + Example: A sputtering target, a powder in a crucible, etc. + """, + ) + vapor_source = SubSection( + section_def=EvaporationSource, + description=""" + Example: A heater, a filament, a laser, a bubbler, etc. + """, + ) + vapor_rate = SubSection( + section_def=VaporRate, + description=""" + The rate of the material being evaporated (mol/time). + """, + ) + + +class GrowthRate(ArchiveSection): + m_def = Section( + a_plot=dict( + x="process_time", + y="rate", + ), + ) + rate = Quantity( + type=float, + unit="meter/second", + shape=["*"], + ) + process_time = Quantity( + type=float, + unit="second", + shape=["*"], + ) + measurement_type = Quantity( + type=MEnum( + "Assumed", + "RHEED", + "Reflectance", + ) + ) + + +class SubstrateTemperature(ArchiveSection): + m_def = Section( + a_plot=dict( + x="process_time", + y="temperature", + ), + ) + temperature = Quantity( + type=float, + unit="kelvin", + shape=["*"], + ) + process_time = Quantity( + type=float, + unit="second", + shape=["*"], + ) + measurement_type = Quantity( + type=MEnum( + "Heater thermocouple", + "Pyrometer", + "Assumed", + ) + ) + + +class SampleParameters(PlotSection, ArchiveSection): + m_def = Section( + a_plotly_graph_object={ + "label": "Measured Temperatures", + "index": 1, + "dragmode": "pan", + "data": { + "type": "scattergl", + "line": {"width": 2}, + "marker": {"size": 2}, + "mode": "lines+markers", + "name": "Temperature", + "x": "#temperature/process_time", + "y": "#temperature/temperature", + }, + "layout": { + "title": {"text": "Measured Temperature"}, + "xaxis": { + "showticklabels": True, + "fixedrange": True, + "ticks": "", + "title": {"text": "Process time [s]"}, + "showline": True, + "linewidth": 1, + "linecolor": "black", + "mirror": True, + }, + "yaxis": { + "showticklabels": True, + "fixedrange": True, + "ticks": "", + "title": {"text": "Temperature [°C]"}, + "showline": True, + "linewidth": 1, + "linecolor": "black", + "mirror": True, + }, + "showlegend": False, + }, + "config": { + "displayModeBar": False, + "scrollZoom": False, + "responsive": False, + "displaylogo": False, + "dragmode": False, + }, + }, + ) + growth_rate = SubSection( + section_def=GrowthRate, + description=""" + The growth rate of the thin film (length/time). + Measured by in-situ RHEED or Reflection or assumed. + """, + ) + temperature = SubSection( + section_def=SubstrateTemperature, + ) + layer = SubSection( + description=""" + The thin film that is being created during this step. + """, + section_def=ThinFilmReference, + ) + substrate = SubSection( + description=""" + The thin film stack that is being evaporated on. + """, + section_def=ThinFilmStackReference, + ) + + +class Pressure(ArchiveSection): + m_def = Section( + a_plot=dict( + x="process_time", + y="pressure", + ), + ) + pressure = Quantity( + type=float, + unit="pascal", + shape=["*"], + ) + process_time = Quantity( + type=float, + unit="second", + shape=["*"], + ) + + +class GasFlow(ArchiveSection): + m_def = Section( + a_plot=dict( + x="process_time", + y="flow", + ), + ) + gas = SubSection( + section_def=PureSubstanceSection, + ) + flow = Quantity( + type=float, + unit="meter ** 3 / second", + shape=["*"], + ) + process_time = Quantity( + type=float, + unit="second", + shape=["*"], + ) + + +class SubstrateHeater(ArchiveSection): + pass + + +class ChamberEnvironment(ArchiveSection): + m_def = Section( + a_plot=dict( + x="pressure/process_time", + y="pressure/pressure", + ), + ) + gas_flow = SubSection( + section_def=GasFlow, + repeats=True, + ) + pressure = SubSection( + section_def=Pressure, + ) + heater = SubSection( + section_def=SubstrateHeater, + ) + + +class VaporDepositionStep(ActivityStep): + """ + A step of any vapor deposition process. + """ + + m_def = Section() + creates_new_thin_film = Quantity( + type=bool, + description=""" + Whether or not this step creates a new thin film. + """, + default=False, + a_eln=ELNAnnotation( + component="BoolEditQuantity", + ), + ) + duration = Quantity( + type=float, + unit="second", + ) + sources = SubSection( + section_def=VaporDepositionSource, + repeats=True, + ) + sample_parameters = SubSection( + section_def=SampleParameters, + repeats=True, + ) + environment = SubSection( + section_def=ChamberEnvironment, + ) + + def to_task(self) -> Task: + """ + Returns the task description of this activity step. + + Returns: + Task: The activity step as a workflow task. + """ + inputs = [ + Link( + name=source.material.name, + section=source.material.reference, + ) + for source in self.sources + if source.material is not None and source.material.reference is not None + ] + outputs = [ + Link( + name=parameters.layer.name, + section=parameters.layer.reference, + ) + for parameters in self.sample_parameters + if parameters.layer is not None and parameters.layer.reference is not None + ] + return Task(name=self.name, inputs=inputs, outputs=outputs) + + def normalize(self, archive: "EntryArchive", logger: "BoundLogger") -> None: + """ + The normalizer for the `VaporDepositionStep` class. + + Args: + archive (EntryArchive): The archive containing the section that is being + normalized. + logger (BoundLogger): A structlog logger. + """ + super(VaporDepositionStep, self).normalize(archive, logger) + + +class VaporDeposition(SampleDeposition): + """ + VaporDeposition is a general class that encompasses both Physical Vapor Deposition + (PVD) and Chemical Vapor Deposition (CVD). + It involves the deposition of material from a vapor phase to a solid thin film or + coating onto a substrate. + - material sources: + Both PVD and CVD involve a source material that is transformed into a vapor phase. + In PVD, the source material is physically evaporated or sputtered from a solid + target. + In CVD, gaseous precursors undergo chemical reactions to produce a solid material + on the substrate. + - substrate: + The substrate is the material onto which the thin film is deposited. + - environment: + The process typically takes place in a controlled environment. + The deposition is usually affected by the pressure in the chamber. + For some processes additional background gasses are also added. + """ + + m_def = Section( + links=[ + "http://purl.obolibrary.org/obo/CHMO_0001314", + "http://purl.obolibrary.org/obo/CHMO_0001356", + ], + a_plot=[ + dict( + x="steps/:/environment/pressure/process_time", + y="steps/:/environment/pressure/pressure", + ), + ], + ) + steps = SubSection( + description=""" + The steps of the deposition process. + """, + section_def=VaporDepositionStep, + repeats=True, + ) + + def normalize(self, archive: "EntryArchive", logger: "BoundLogger") -> None: + """ + The normalizer for the `VaporDeposition` class. + + Args: + archive (EntryArchive): The archive containing the section that is being + normalized. + logger (BoundLogger): A structlog logger. + """ + super(VaporDeposition, self).normalize(archive, logger) + + +m_package.__init_metainfo__()