Compare commits
37 Commits
e40173f264
...
async
| Author | SHA256 | Date | |
|---|---|---|---|
| 0a879cbfe9 | |||
| f60b58f2f2 | |||
| 6f618b2340 | |||
| 38940995b5 | |||
| f686ea65b1 | |||
| 23bfdefd30 | |||
| 38d281543e | |||
| a12506b8be | |||
| 43cfd788f3 | |||
| da42de5466 | |||
| d86b35a5fe | |||
| c4903a536b | |||
| 3e85940eb6 | |||
| 820337c06e | |||
| 5a605038df | |||
| fd4c3b718a | |||
| 7b3bff854d | |||
| 4df8048e55 | |||
| 97d534c5d1 | |||
| 88aacf23c1 | |||
| 43a898e4e6 | |||
| 5725dbfbf8 | |||
| ddd3775112 | |||
| 2117f61f36 | |||
| 5aa7527cca | |||
| c49aa23aea | |||
| 352a223d95 | |||
| 1d0bc6668c | |||
| 46df7a948f | |||
| 03d7811904 | |||
| c5f85b2618 | |||
| 9dbf523190 | |||
| 4e224d3e29 | |||
| f74d8efea8 | |||
| fd903f025b | |||
| f51b0d8615 | |||
| 7245c757c3 |
5
.gitignore
vendored
5
.gitignore
vendored
@@ -1,6 +1,9 @@
|
|||||||
# ignora log di h5tojson e jsontoh5
|
# ignores logs of h5tojson, jsontoh5
|
||||||
*.log
|
*.log
|
||||||
|
|
||||||
|
# ignores output json of main.py
|
||||||
|
output/*.json
|
||||||
|
|
||||||
# ---> Python
|
# ---> Python
|
||||||
# Byte-compiled / optimized / DLL files
|
# Byte-compiled / optimized / DLL files
|
||||||
__pycache__/
|
__pycache__/
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
* Sample: what is being produced by a deposition. A sample is made up of different stacked layers of material (target) deposited upon another material (substrate).
|
* Sample: what is being produced by a deposition. A sample is made up of different stacked layers of material (target) deposited upon another material (substrate).
|
||||||
* Target: material "consumed" during the deposition.
|
* Target: material "consumed" during the deposition.
|
||||||
* Substrate: material on which the target is deposited.
|
* Substrate: material on which the target is deposited.
|
||||||
|
* Compound: which material is a target or a substrate made of; substrates of the same batch are made of the same compound.
|
||||||
* Layer: one of the layers of material of which a sample is composed; every layer can have different properties, both in the physical sense (i.e. shape, thickness...) and regarding their manufacturing process (i.e. frequency of pulses, deposition temperature and pressure...).
|
* Layer: one of the layers of material of which a sample is composed; every layer can have different properties, both in the physical sense (i.e. shape, thickness...) and regarding their manufacturing process (i.e. frequency of pulses, deposition temperature and pressure...).
|
||||||
|
|
||||||
## eLabFTW glossary
|
## eLabFTW glossary
|
||||||
@@ -19,7 +20,7 @@
|
|||||||
* JSON: fancy dictionaries with important data.
|
* JSON: fancy dictionaries with important data.
|
||||||
|
|
||||||
### Endpoints
|
### Endpoints
|
||||||
Base url: https://{ELAB_BASE_URL}:{PORT}/api/v2
|
API URL: `https://{ELAB_BASE_URL}:{PORT}/api/v2`
|
||||||
|
|
||||||
#### GET, PATCH, DELETE
|
#### GET, PATCH, DELETE
|
||||||
* `/items/{elabid}`: data on a resource identified by its elabid.
|
* `/items/{elabid}`: data on a resource identified by its elabid.
|
||||||
|
|||||||
0
output/placeholder
Normal file
0
output/placeholder
Normal file
@@ -1 +1,2 @@
|
|||||||
requests
|
requests
|
||||||
|
asyncio
|
||||||
|
|||||||
41
src/APIHandler.py
Normal file
41
src/APIHandler.py
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
import requests
|
||||||
|
|
||||||
|
class APIHandler:
|
||||||
|
'''
|
||||||
|
Class to standardize the format of the headers of our http requests.
|
||||||
|
'''
|
||||||
|
# TO-DO: remove static url.
|
||||||
|
def __init__(self, apikey="", ELABFTW_API_URL="https://elabftw.fisica.unina.it/api/v2"):
|
||||||
|
'''Init method, apikey suggested but not required (empty by default).'''
|
||||||
|
self.auth = {"Authorization" : apikey}
|
||||||
|
self.content = {"Content-Type" : "application/json"}
|
||||||
|
self.header = {**self.auth, **self.content}
|
||||||
|
self.elaburl = ELABFTW_API_URL
|
||||||
|
def get_entry_from_elabid(self, elabid, entryType="items"):
|
||||||
|
'''
|
||||||
|
Method which returns a resource's raw data (as dictionary) from its elabid and entry type.
|
||||||
|
|
||||||
|
Entry type can be either "experiments" or "items".
|
||||||
|
'''
|
||||||
|
# TO-DO: validation and error handling on entryType value.
|
||||||
|
header = self.header
|
||||||
|
response = requests.get(
|
||||||
|
headers = header,
|
||||||
|
url = f"{self.elaburl}/{entryType}/{elabid}",
|
||||||
|
verify=True
|
||||||
|
)
|
||||||
|
if response.status_code // 100 in [1,2,3]:
|
||||||
|
entry_data = response.json()
|
||||||
|
return entry_data
|
||||||
|
elif response.status_code // 100 == 4:
|
||||||
|
match response.status_code:
|
||||||
|
case 401|403:
|
||||||
|
raise ConnectionError(f"Invalid API key or authentication method.")
|
||||||
|
case 404:
|
||||||
|
raise ConnectionError(f"404: Not Found. This means there's no resource with this elabid (wrong elabid?) on your eLabFTW (wrong endpoint?).")
|
||||||
|
case 400:
|
||||||
|
raise ConnectionError(f"400: Bad Request. This means the API endpoint you tried to reach is invalid. Did you tamper with the source code? If not, contact the developer.")
|
||||||
|
case _:
|
||||||
|
raise ConnectionError(f"HTTP request failed with status code: {response.status_code} (NOTE: 4xx means user's fault).")
|
||||||
|
else:
|
||||||
|
raise ConnectionError(f"There's a problem on the server. Status code: {response.status_code}.")
|
||||||
@@ -1,43 +0,0 @@
|
|||||||
import os, json, requests
|
|
||||||
from getpass import getpass
|
|
||||||
from classes import Header
|
|
||||||
|
|
||||||
'''
|
|
||||||
Starting from the sample's page we'll use this code to pull and return all data from the entries related to the sample and its fabrication.
|
|
||||||
'''
|
|
||||||
|
|
||||||
class Entrypoint:
|
|
||||||
'''
|
|
||||||
Use: Entrypoint(elabid)
|
|
||||||
|
|
||||||
The entrypoint is the starting point of the process of resolving the data chain. The entrypoint must be a sample.
|
|
||||||
|
|
||||||
Currently, the elabid of the sample must be provided. In the future a different method will eventually be implemented.
|
|
||||||
'''
|
|
||||||
def __init__(self, elabid):
|
|
||||||
'''
|
|
||||||
Constructor method.
|
|
||||||
self.sample_data is a dictionary of all data on the sample's eLab entry.
|
|
||||||
self.linked_experiments is a sub-dictionary which only includes links to related experiments.
|
|
||||||
self.batch_elabid is an integer (or NoneType if there's an error) containing the elabid of the associated substrate batch entry.
|
|
||||||
'''
|
|
||||||
header = Header(apikey).dump
|
|
||||||
self.sample_data = requests.get(
|
|
||||||
headers = header,
|
|
||||||
url = f"https://elabftw.fisica.unina.it/api/v2/items/{elabid}",
|
|
||||||
verify=True
|
|
||||||
).json()
|
|
||||||
self.linked_experiments = self.sample_data.get("related_experiments_links") or None
|
|
||||||
try:
|
|
||||||
self.batch_elabid = self.sample_data["metadata_decoded"]["extra_fields"]["Substrate batch"]["value"]
|
|
||||||
except KeyError as k: # if no metadata exists - which means there's a problem with the entry
|
|
||||||
self.batch_elabid = None
|
|
||||||
|
|
||||||
if __name__=="__main__":
|
|
||||||
print("===== DEBUG MODE! =====")
|
|
||||||
apikey = getpass("Paste API key here: ")
|
|
||||||
elabid = input("Input elabid here [default = 1108]: ") or 1108
|
|
||||||
chain = Entrypoint(elabid)
|
|
||||||
print(json.dumps(chain.sample_data))
|
|
||||||
print(json.dumps(chain.linked_experiments))
|
|
||||||
print(chain.batch_elabid)
|
|
||||||
181
src/classes.py
181
src/classes.py
@@ -1,14 +1,179 @@
|
|||||||
class Header:
|
import os, json, requests
|
||||||
|
from APIHandler import APIHandler
|
||||||
|
|
||||||
|
class Layer:
|
||||||
'''
|
'''
|
||||||
Class to standardize the format of the headers of our http requests.
|
Layer(layer_data) - where layer_data is a Python dictionary.
|
||||||
|
|
||||||
|
Meant to be used for eLabFTW Experiments of the "PLD Deposition" category.
|
||||||
|
|
||||||
|
eLabFTW experiments contain most of the data required by the NeXus file - although every layer is on a different eLab entry;
|
||||||
|
unfortunately, some data like the target's chemical formula must be retrieved through additional HTTP requests.
|
||||||
|
Attributes 'target_elabid', 'rheed_system_elabid' and 'laser_system_elabid' contain elabid's for these resources, which are all items.
|
||||||
'''
|
'''
|
||||||
def __init__(self, apikey=""):
|
def __init__(self, layer_data):
|
||||||
'''Init method, apikey suggested but not required (empty by default).'''
|
try:
|
||||||
self.auth = {"Authorization" : apikey}
|
self.extra = layer_data["metadata_decoded"]["extra_fields"]
|
||||||
self.content = {"Content-Type" : "application/json"}
|
self.layer_number = self.extra["Layer Progressive Number"]["value"] # integer
|
||||||
self.dump = {**self.auth, **self.content}
|
self.target_elabid = self.extra["Target"]["value"] # elabid
|
||||||
|
self.laser_system_elabid = self.extra["Laser System"]["value"] # elabid
|
||||||
|
self.chamber_elabid = self.extra["Chamber"]["value"] # elabid
|
||||||
|
self.rheed_system_elabid = self.extra["RHEED System"]["value"] # elabid
|
||||||
|
self.start_time = layer_data.get("created_at")
|
||||||
|
self.operator = layer_data.get("fullname")
|
||||||
|
self.description = layer_data.get("body")
|
||||||
|
self.deposition_time = self.extra["Duration"]["value"]
|
||||||
|
self.repetition_rate = self.extra["Repetition rate"]["value"]
|
||||||
|
try:
|
||||||
|
self.number_of_pulses = (float(self.deposition_time) * float(self.repetition_rate)).__floor__()
|
||||||
|
except ValueError:
|
||||||
|
# Since number_of_pulses is required, if it can't be calculated raise error:
|
||||||
|
raise ValueError("""
|
||||||
|
Fatal: either Duration or Repetition Rate are empty or invalid.
|
||||||
|
This has to be an error, since these fields are required by the NeXus standard.
|
||||||
|
Please edit your eLabFTW entry and retry.
|
||||||
|
""")
|
||||||
|
self.temperature = self.extra["Heater temperature"]["value"] # Note: this field used to have a trailing space in its name
|
||||||
|
self.process_pressure = self.extra["Process pressure"]["value"] # Note: this field used to have a trailing space in its name
|
||||||
|
self.heating_method = self.extra["Heating Method"]["value"]
|
||||||
|
self.layer_thickness = self.extra["Thickness"]["value"]
|
||||||
|
self.buffer_gas = self.extra["Buffer gas"]["value"]
|
||||||
|
self.heater_target_distance = self.extra["Heater-target distance"]["value"]
|
||||||
|
self.laser_fluence = self.extra["Laser Intensity"]["value"] # here fluence = intensity
|
||||||
|
self.laser_spot_area = self.extra["Spot Area"]["value"]
|
||||||
|
try:
|
||||||
|
self.laser_energy = (float(self.laser_fluence) * float(self.laser_spot_area)).__round__(3)
|
||||||
|
except ValueError:
|
||||||
|
# Since laser_energy is NOT required, if it can't be calculated warn user but allow the software to continue execution:
|
||||||
|
print("""
|
||||||
|
Warning: either Laser Intensity or Spot Area are empty or invalid.
|
||||||
|
If you think this is an error, please edit your eLabFTW entry and retry.
|
||||||
|
Setting Laser Energy to NoneType.
|
||||||
|
""")
|
||||||
|
# Placeholder
|
||||||
|
self.laser_energy = None
|
||||||
|
# Laser rasternig section
|
||||||
|
self.laser_rastering_geometry = self.extra["Laser Rastering Geometry"]["value"]
|
||||||
|
self.laser_rastering_positions = self.extra["Laser Rastering Position"]["value"]
|
||||||
|
self.laser_rastering_velocities = self.extra["Laser Rastering Speed"]["value"]
|
||||||
|
# Pre annealing section
|
||||||
|
self.pre_annealing_ambient_gas = self.extra["Buffer gas Pre"]["value"]
|
||||||
|
self.pre_annealing_pressure = self.extra["Process pressure Pre"]["value"]
|
||||||
|
self.pre_annealing_temperature = self.extra["Heater temperature Pre"]["value"]
|
||||||
|
self.pre_annealing_duration = self.extra["Duration Pre"]["value"]
|
||||||
|
# Post annealing section
|
||||||
|
self.post_annealing_ambient_gas = self.extra["Buffer gas PA"]["value"]
|
||||||
|
self.post_annealing_pressure = self.extra["Process pressure PA"]["value"]
|
||||||
|
self.post_annealing_temperature = self.extra["Heater temperature PA"]["value"]
|
||||||
|
self.post_annealing_duration = self.extra["Duration PA"]["value"]
|
||||||
|
# Rejected but suggested by the NeXus standard:
|
||||||
|
#self.laser_rastering_coefficients = None
|
||||||
|
except KeyError as k:
|
||||||
|
# Some keys are not required and can be called through the .get() method - which is permissive and allows null values;
|
||||||
|
# Other keys are required so if they can't be called (invalid or null) raise error and stop execution of the program:
|
||||||
|
raise KeyError(f"The provided dictionary lacks a \"{k}\" key. Check the deposition layer entry on eLabFTW and make sure you used the correct Experiment template.")
|
||||||
|
def get_instruments(self, apikey):
|
||||||
|
raw_lasersys_data = APIHandler(apikey).get_entry_from_elabid(self.laser_system_elabid, entryType="items")
|
||||||
|
raw_chamber_data = APIHandler(apikey).get_entry_from_elabid(self.chamber_elabid, entryType="items")
|
||||||
|
raw_rheedsys_data = APIHandler(apikey).get_entry_from_elabid(self.rheed_system_elabid, entryType="items")
|
||||||
|
instruments_used = {
|
||||||
|
"laser_system": raw_lasersys_data.get("title") or None,
|
||||||
|
"deposition_chamber": raw_chamber_data.get("title") or None,
|
||||||
|
"rheed_system": raw_rheedsys_data.get("title") or None,
|
||||||
|
}
|
||||||
|
return instruments_used
|
||||||
|
|
||||||
|
class Entrypoint:
|
||||||
|
'''
|
||||||
|
Entrypoint(sample_data) - where sample_data is a Python dictionary.
|
||||||
|
|
||||||
|
Meant to be used for eLabFTW Resources of the "Sample" category.
|
||||||
|
|
||||||
|
The entrypoint is the starting point of the process of resolving the data chain.
|
||||||
|
The entrypoint must be a dictionary containing the data of a sample, created directly from the JSON of the item endpoint on eLabFTW - which can be done through the function get_entry_from_elabid.
|
||||||
|
'''
|
||||||
|
def __init__(self, sample_data):
|
||||||
|
try:
|
||||||
|
self.extra = sample_data["metadata_decoded"]["extra_fields"]
|
||||||
|
self.linked_items = sample_data["items_links"] # dict
|
||||||
|
self.batch_elabid = self.extra["Substrate batch"]["value"] # elabid
|
||||||
|
self.linked_experiments = sample_data["related_experiments_links"] # dict
|
||||||
|
self.linked_experiments_elabid = [ i["entityid"] for i in self.linked_experiments ] # list of elabid
|
||||||
|
except KeyError as k:
|
||||||
|
# Some keys are not required and can be called through the .get() method - which is permissive and allows null values;
|
||||||
|
# Other keys are required so if they can't be called (invalid or null) raise error and stop execution of the program:
|
||||||
|
raise KeyError(f"The provided dictionary lacks a \"{k}\" key. Check the sample entry on eLabFTW and make sure you used the correct Resource template.")
|
||||||
|
# Non-required attributes:
|
||||||
|
self.name = sample_data.get("title") or None # error prevention is more important than preventing empty fields here
|
||||||
|
|
||||||
|
class Material:
|
||||||
|
'''
|
||||||
|
Material(material_data) - where material_data is a Python dictionary.
|
||||||
|
|
||||||
|
Meant to be used for eLabFTW Resources of either the "PLD Target" or the "Substrate" categories.
|
||||||
|
|
||||||
|
Both a PLD Target and a Substrate are materials made of a certain compound, of which we want to know:
|
||||||
|
* Name and formula;
|
||||||
|
* Shape and dimensions;
|
||||||
|
* Misc.
|
||||||
|
'''
|
||||||
|
def __init__(self, material_data):
|
||||||
|
try:
|
||||||
|
self.name = material_data["title"] # required
|
||||||
|
self.extra = material_data["metadata_decoded"]["extra_fields"]
|
||||||
|
self.compound_elabid = self.extra["Compound"]["value"]
|
||||||
|
self.dimensions = self.extra["Size"]["value"]
|
||||||
|
except KeyError as k:
|
||||||
|
# Some keys are not required and can be called through the .get() method - which is permissive and allows null values;
|
||||||
|
# Other keys are required so if they can't be called (invalid or null) raise error and stop execution of the program:
|
||||||
|
raise KeyError(f"The provided dictionary lacks a \"{k}\" key. Check the target/substrate entry on eLabFTW and make sure you used the correct Resource template.")
|
||||||
|
def get_compound_data(self, apikey):
|
||||||
|
raw_compound_data = APIHandler(apikey).get_entry_from_elabid(self.compound_elabid, entryType="items")
|
||||||
|
name = raw_compound_data["title"]
|
||||||
|
extra = raw_compound_data["metadata_decoded"]["extra_fields"]
|
||||||
|
formula = extra.get("Chemical formula")
|
||||||
|
cas = extra.get("CAS number ") or { "value": None }
|
||||||
|
compound_data = {
|
||||||
|
"name" : name,
|
||||||
|
"chemical_formula" : formula.get("value"),
|
||||||
|
"cas_number" : cas.get("value")
|
||||||
|
}
|
||||||
|
return compound_data
|
||||||
|
def get_compound_formula(self, apikey):
|
||||||
|
formula = self.get_compound_data(apikey).get("chemical_formula")
|
||||||
|
return formula
|
||||||
|
|
||||||
|
class Substrate(Material):
|
||||||
|
def __init__(self, material_data):
|
||||||
|
super().__init__(material_data)
|
||||||
|
try:
|
||||||
|
self.orientation = self.extra["Orientation"]["value"]
|
||||||
|
self.miscut_angle = self.extra["Miscut Angle"]["value"]
|
||||||
|
self.miscut_direction = self.extra["Miscut Direction"]["value"]
|
||||||
|
# Not present (yet) on eLabFTW for Substrates:
|
||||||
|
self.thickness = None #self.extra["Thickness"]["value"]
|
||||||
|
self.surface_treatment = self.extra["Surface treatment"]["value"]
|
||||||
|
self.manufacturer = self.extra["Supplier"]["value"]
|
||||||
|
self.batch_id = self.extra["Batch ID"]["value"]
|
||||||
|
except KeyError as k:
|
||||||
|
raise KeyError(f"The provided dictionary lacks a \"{k}\" key - which is specific for substrates. Check the {self.name} substrate entry on eLabFTW and make sure you used the correct Resource template.")
|
||||||
|
|
||||||
|
class Target(Material):
|
||||||
|
def __init__(self, material_data):
|
||||||
|
super().__init__(material_data)
|
||||||
|
try:
|
||||||
|
self.thickness = self.extra["Thickness"]["value"]
|
||||||
|
self.shape = self.extra["shape"]["value"]
|
||||||
|
self.solid_form = self.extra["Solid form"]["value"]
|
||||||
|
self.manufacturer = self.extra["Supplier"]["value"]
|
||||||
|
except KeyError as k:
|
||||||
|
raise KeyError(f"The provided dictionary lacks a \"{k}\" key - which is specific for PLD targets. Check the {self.name} target entry on eLabFTW and make sure you used the correct Resource template.")
|
||||||
|
# Non-required attributes:
|
||||||
|
self.description = material_data.get("body") or ""
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if __name__=="__main__":
|
if __name__=="__main__":
|
||||||
head = Header("MyApiKey-123456789abcdef")
|
head = Header("MyApiKey-123456789abcdef")
|
||||||
print(f"Example header: {head.dump()}")
|
print(f"Example header:\n\t{head.header}\n")
|
||||||
print("Warning: you're not supposed to be running this as the main program.")
|
print("Warning: you're not supposed to be running this as the main program.")
|
||||||
62
src/functions.py
Normal file
62
src/functions.py
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
"""
|
||||||
|
Currently unused!
|
||||||
|
"""
|
||||||
|
import json, requests
|
||||||
|
from APIHandler import APIHandler
|
||||||
|
|
||||||
|
def get_entry_from_elabid(elabid, entryType="items"):
|
||||||
|
'''
|
||||||
|
Function which returns entrypoint data (as dictionary) from its elabid.
|
||||||
|
'''
|
||||||
|
header = APIHandler(apikey).dump
|
||||||
|
response = requests.get(
|
||||||
|
headers = header,
|
||||||
|
url = f"{ELABFTW_API_URL}/{entryType}/{elabid}",
|
||||||
|
verify=True
|
||||||
|
)
|
||||||
|
if response.status_code // 100 in [2,3]:
|
||||||
|
entry_data = response.json()
|
||||||
|
return entry_data
|
||||||
|
else:
|
||||||
|
raise ConnectionError(f"HTTP request failed with status code: {response.status_code}.")
|
||||||
|
|
||||||
|
def get_sample_layers_data(elabid):
|
||||||
|
'''
|
||||||
|
Return the following data from every eLabFTW experiment linked
|
||||||
|
to a certain sample, identified by elabid.
|
||||||
|
|
||||||
|
- Title of the experiment
|
||||||
|
- Category (should check it's "PLD Deposition")
|
||||||
|
- Layer number - if present (PLD depositions)
|
||||||
|
- Deposition time - returns error if not present
|
||||||
|
- Repetition rate - returns error if not present
|
||||||
|
'''
|
||||||
|
# header = {
|
||||||
|
# "Authorization": apikey,
|
||||||
|
# "Content-Type": "application/json"
|
||||||
|
# }
|
||||||
|
sample_data = requests.get(
|
||||||
|
headers = header,
|
||||||
|
url = f"https://elabftw.fisica.unina.it/api/v2/items/{elabid}",
|
||||||
|
verify=True
|
||||||
|
).json()
|
||||||
|
related_experiments = sample_data["related_experiments_links"]
|
||||||
|
result = []
|
||||||
|
for exp in related_experiments:
|
||||||
|
experiment_data = requests.get(
|
||||||
|
headers = header,
|
||||||
|
url = f"https://elabftw.fisica.unina.it/api/v2/experiments/{exp.get("entityid")}",
|
||||||
|
verify=True
|
||||||
|
).json()
|
||||||
|
extra = experiment_data["metadata_decoded"]["extra_fields"]
|
||||||
|
result.append(
|
||||||
|
{"title": exp.get("title"),
|
||||||
|
"layer_number": extra.get("Layer Progressive Number").get("value"),
|
||||||
|
"category": exp.get("category_title"),
|
||||||
|
"deposition_time": extra.get("Duration").get("value"),
|
||||||
|
"repetition_rate": extra.get("Repetition rate").get("value")}
|
||||||
|
)
|
||||||
|
return result
|
||||||
|
|
||||||
|
if __name__=="__main__":
|
||||||
|
print("Warning: you're not supposed to be running this as the main program.")
|
||||||
247
src/main.py
247
src/main.py
@@ -1,46 +1,215 @@
|
|||||||
import os, json, requests
|
import os, json, requests
|
||||||
from getpass import getpass
|
from getpass import getpass
|
||||||
from classes import Header
|
from APIHandler import APIHandler
|
||||||
|
from classes import *
|
||||||
|
|
||||||
def get_sample_layers_data(elabid):
|
|
||||||
'''
|
|
||||||
Return the following data from every eLabFTW experiment linked
|
|
||||||
to a certain sample, identified by elabid.
|
|
||||||
|
|
||||||
- Title of the experiment
|
def call_entrypoint_from_elabid(elabid):
|
||||||
- Category (should check it's "PLD Deposition")
|
|
||||||
- Layer number - if present (PLD depositions)
|
|
||||||
- Deposition time - returns error if not present
|
|
||||||
- Repetition rate - returns error if not present
|
|
||||||
'''
|
'''
|
||||||
# header = {
|
Calls an entrypoint sample from eLabFTW using its elabid, then returns an object of the Entrypoint class.
|
||||||
# "Authorization": apikey,
|
|
||||||
# "Content-Type": "application/json"
|
If the entry is not a sample (category_title not matching exactly "Sample") returns ValueError.
|
||||||
# }
|
'''
|
||||||
sample_data = requests.get(
|
try:
|
||||||
headers = header,
|
sample_data = APIHandler(apikey).get_entry_from_elabid(elabid, entryType="items")
|
||||||
url = f"https://elabftw.fisica.unina.it/api/v2/items/{elabid}",
|
if not sample_data.get("category_title") == "Sample":
|
||||||
verify=True
|
raise ValueError("The resource you selected is not a sample, therefore it can't be used as an entrypoint.")
|
||||||
).json()
|
sample_object = Entrypoint(sample_data)
|
||||||
related_experiments = sample_data["related_experiments_links"]
|
except ConnectionError as e:
|
||||||
result = []
|
raise ConnectionError(e)
|
||||||
for exp in related_experiments:
|
return sample_object # Entrypoint-class object
|
||||||
experiment_data = requests.get(
|
|
||||||
headers = header,
|
def call_material_from_elabid(elabid):
|
||||||
url = f"https://elabftw.fisica.unina.it/api/v2/experiments/{exp.get("entityid")}",
|
'''
|
||||||
verify=True
|
Calls a material from eLabFTW using its elabid, then returns an object of the Material class.
|
||||||
).json()
|
|
||||||
extra = experiment_data["metadata_decoded"]["extra_fields"]
|
If the entry is neither a PLD Target or a Substrate batch returns ValueError. Such entries always have a category_title key with its value matching exactly "PLD Target" or "Substrate".
|
||||||
result.append(
|
Because of an old typo, the value "Subtrate" (second 's' is missing) is also accepted.
|
||||||
{"title": exp.get("title"),
|
'''
|
||||||
"layer_number": extra.get("Layer Progressive Number").get("value"),
|
try:
|
||||||
"category": exp.get("category_title"),
|
material_data = APIHandler(apikey).get_entry_from_elabid(elabid, entryType="items")
|
||||||
"deposition_time": extra.get("Duration").get("value"),
|
material_category = material_data.get("category_title")
|
||||||
"repetition_rate": extra.get("Repetition rate").get("value")}
|
# TO-DO: correct this typo on elabftw: Subtrate → Substrate.
|
||||||
|
if not material_category in ["PLD Target", "Substrate", "Subtrate"]:
|
||||||
|
print(f"Category of the resource: {material_category}.")
|
||||||
|
raise ValueError(f"The referenced resource (elabid = {elabid}) is not a material.")
|
||||||
|
elif material_category == "PLD Target":
|
||||||
|
material_object = Target(material_data)
|
||||||
|
else:
|
||||||
|
material_object = Substrate(material_data)
|
||||||
|
except ConnectionError as e:
|
||||||
|
raise ConnectionError(e)
|
||||||
|
return material_object # Material-class object
|
||||||
|
|
||||||
|
def call_layers_from_list(elabid_list):
|
||||||
|
'''
|
||||||
|
Calls a list of (PLD deposition) experiments from eLabFTW using their elabid - which means the input must be a list of integers instead of a single one - then returns a list of Layer-class objects.
|
||||||
|
|
||||||
|
If one of the entries is not related to a deposition layer (category_title not matching exactly "PLD Deposition") that entry is skipped, with no error raised.
|
||||||
|
'''
|
||||||
|
list_of_layers = []
|
||||||
|
for elabid in elabid_list:
|
||||||
|
try:
|
||||||
|
layer_data = APIHandler(apikey).get_entry_from_elabid(elabid, entryType="experiments")
|
||||||
|
if not layer_data.get("category_title") == "PLD Deposition":
|
||||||
|
continue
|
||||||
|
layer_object = Layer(layer_data)
|
||||||
|
list_of_layers.append(layer_object)
|
||||||
|
except ConnectionError as e:
|
||||||
|
nums = [ layer.layer_number for layer in list_of_layers ]
|
||||||
|
nums.sort()
|
||||||
|
print(f"LIST OF THE LAYERS PROCESSED (unordered):\n" + str(nums))
|
||||||
|
raise ConnectionError(f"An error occurred while fetching the experiment with elabid = {elabid}:\n" +
|
||||||
|
str(e) + f"\nPlease solve the problem before retrying." + "\n\n" +
|
||||||
|
f"Last resource attempted to call: {ELABFTW_API_URL}/experiments/{elabid}"
|
||||||
)
|
)
|
||||||
return result
|
return list_of_layers # list of Layer-class objects
|
||||||
|
|
||||||
apikey = getpass("Paste API key here: ") # consider replacing with .env file
|
def chain_entrypoint_to_batch(sample_object):
|
||||||
header = Header(apikey).dump
|
'''
|
||||||
result = get_sample_layers_data(1108) # edit id at will in case of deletion of remote source
|
Takes an Entrypoint-class object, looks at its .batch_elabid attribute and returns a Material-class object containing data on the substrate batch associated to the starting sample.
|
||||||
print(json.dumps(result))
|
|
||||||
|
Dependency: call_material_from_elabid.
|
||||||
|
'''
|
||||||
|
material_elabid = sample_object.batch_elabid
|
||||||
|
material_object = call_material_from_elabid(material_elabid)
|
||||||
|
return material_object
|
||||||
|
|
||||||
|
def chain_entrypoint_to_layers(sample_object):
|
||||||
|
'''
|
||||||
|
Takes an Entrypoint-class object, looks at its .linked_experiments_elabid attribute (list) and returns a list of Layer-class objects containing data on the deposition layers associated to the starting sample - using the function call_layers_from_list.
|
||||||
|
|
||||||
|
The list is sorted by progressive layer number (layer_number attribute).
|
||||||
|
|
||||||
|
Dependency: call_layers_from_list.
|
||||||
|
'''
|
||||||
|
linked_experiments_elabid = sample_object.linked_experiments_elabid # list of elabid
|
||||||
|
layer_object_list = call_layers_from_list(linked_experiments_elabid)
|
||||||
|
layer_object_list.sort(key=lambda x: x.layer_number)
|
||||||
|
return layer_object_list
|
||||||
|
|
||||||
|
def chain_layer_to_target(layer_object):
|
||||||
|
'''
|
||||||
|
Takes a Layer-class object, looks at its .target_elabid attribute and returns a Material-class object containing data on the PLD target used in the deposition of said layer.
|
||||||
|
|
||||||
|
Dependency: call_material_from_elabid.
|
||||||
|
'''
|
||||||
|
target_elabid = layer_object.target_elabid
|
||||||
|
material_object = call_material_from_elabid(target_elabid)
|
||||||
|
return material_object
|
||||||
|
|
||||||
|
def deduplicate_instruments_from_layers(layers):
|
||||||
|
'''
|
||||||
|
Takes a list of Layer-class objects and for each layer gets the instruments used (laser, depo chamber and RHEED), returns deduplicated list. Ideally, the lists should only contain one element.
|
||||||
|
'''
|
||||||
|
lasers = []
|
||||||
|
chambers = []
|
||||||
|
rheeds = []
|
||||||
|
for lyr in layers:
|
||||||
|
instruments = lyr.get_instruments(apikey)
|
||||||
|
lasers.append(instruments["laser_system"])
|
||||||
|
chambers.append(instruments["deposition_chamber"])
|
||||||
|
rheeds.append(instruments["rheed_system"])
|
||||||
|
instruments_used_dict = {
|
||||||
|
"laser_system": list( set( lasers ) ),
|
||||||
|
"deposition_chamber": list( set( chambers ) ),
|
||||||
|
"rheed_system" : list( set( rheeds ) ),
|
||||||
|
}
|
||||||
|
# lasers = { f"layer_{lyr.layer_number}": lyr.laser_system for lyr in layers }
|
||||||
|
# chambers = { f"layer_{lyr.layer_number}": lyr.deposition_chamber for lyr in layers }
|
||||||
|
# rheeds = { f"layer_{lyr.layer_number}": lyr.rheed_system for lyr in layers }
|
||||||
|
# instruments_used_dict = {
|
||||||
|
# "laser_system": lasers,
|
||||||
|
# "deposition_chamber": chambers,
|
||||||
|
# "rheed_system": rheeds,
|
||||||
|
# }
|
||||||
|
return instruments_used_dict
|
||||||
|
|
||||||
|
def make_nexus_schema_dictionary(substrate_object, layers):
|
||||||
|
'''
|
||||||
|
Main function, takes all the other functions to reconstruct the full dataset. Takes a Substrate-class object (output of the chain_entrypoint_to_batch() function) and a list of Layer-class objects (output of the chain_entrypoint_to_layers() function), returns dictionary with the same schema as the NeXus standard for PLD fabrications.
|
||||||
|
'''
|
||||||
|
pld_fabrication = {
|
||||||
|
"sample": {
|
||||||
|
"substrate": {
|
||||||
|
"name": substrate_object.name,
|
||||||
|
"chemical_formula" : substrate_object.get_compound_formula(apikey),
|
||||||
|
"orientation" : substrate_object.orientation,
|
||||||
|
"miscut_angle" : substrate_object.miscut_angle,
|
||||||
|
"miscut_direction" : substrate_object.miscut_direction,
|
||||||
|
"thickness" : substrate_object.thickness,
|
||||||
|
"dimensions" : substrate_object.dimensions,
|
||||||
|
"surface_treatment" : substrate_object.surface_treatment,
|
||||||
|
"manufacturer" : substrate_object.manufacturer,
|
||||||
|
"batch_id" : substrate_object.batch_id,
|
||||||
|
},
|
||||||
|
"multilayer": {},
|
||||||
|
},
|
||||||
|
"instruments_used": deduplicate_instruments_from_layers(layers),
|
||||||
|
}
|
||||||
|
multilayer = pld_fabrication["sample"]["multilayer"]
|
||||||
|
for layer in layers:
|
||||||
|
name = "layer_" + layer.layer_number
|
||||||
|
target_object = chain_layer_to_target(layer)
|
||||||
|
target_dict = {
|
||||||
|
"name": target_object.name,
|
||||||
|
"chemical_formula" : target_object.get_compound_formula(apikey),
|
||||||
|
"description" : target_object.description,
|
||||||
|
"shape" : target_object.shape,
|
||||||
|
"dimensions" : target_object.dimensions,
|
||||||
|
"thickness" : target_object.thickness,
|
||||||
|
"solid_form" : target_object.solid_form,
|
||||||
|
"manufacturer" : target_object.manufacturer,
|
||||||
|
# TO-DO: currently not available:
|
||||||
|
# "batch_id" : target_object.batch_id,
|
||||||
|
}
|
||||||
|
multilayer[name] = {
|
||||||
|
"target": target_dict,
|
||||||
|
"start_time": layer.start_time,
|
||||||
|
"operator": layer.operator,
|
||||||
|
"description": layer.description,
|
||||||
|
"number_of_pulses": layer.number_of_pulses,
|
||||||
|
"deposition_time": layer.deposition_time,
|
||||||
|
"temperature": layer.temperature,
|
||||||
|
"heating_method": layer.heating_method,
|
||||||
|
"layer_thickness": layer.layer_thickness,
|
||||||
|
"buffer_gas": layer.buffer_gas,
|
||||||
|
"process_pressure": layer.process_pressure,
|
||||||
|
"heater_target_distance": layer.heater_target_distance,
|
||||||
|
"repetition_rate": layer.repetition_rate,
|
||||||
|
"laser_fluence": layer.laser_fluence,
|
||||||
|
"laser_spot_area": layer.laser_spot_area,
|
||||||
|
"laser_energy": layer.laser_energy,
|
||||||
|
"laser_rastering": {
|
||||||
|
"geometry": layer.laser_rastering_geometry,
|
||||||
|
"positions": layer.laser_rastering_positions,
|
||||||
|
"velocities": layer.laser_rastering_velocities,
|
||||||
|
},
|
||||||
|
"pre_annealing": {
|
||||||
|
"ambient_gas": layer.pre_annealing_ambient_gas,
|
||||||
|
"pressure": layer.pre_annealing_pressure,
|
||||||
|
"temperature": layer.pre_annealing_temperature,
|
||||||
|
"duration": layer.pre_annealing_duration,
|
||||||
|
},
|
||||||
|
"post_annealing": {
|
||||||
|
"ambient_gas": layer.post_annealing_ambient_gas,
|
||||||
|
"pressure": layer.post_annealing_pressure,
|
||||||
|
"temperature": layer.post_annealing_temperature,
|
||||||
|
"duration": layer.post_annealing_duration,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
return pld_fabrication
|
||||||
|
|
||||||
|
if __name__=="__main__":
|
||||||
|
# TO-DO: place the API base URL somewhere else.
|
||||||
|
ELABFTW_API_URL = "https://elabftw.fisica.unina.it/api/v2"
|
||||||
|
apikey = getpass("Paste API key here: ")
|
||||||
|
elabid = input("Enter elabid of your starting sample [default= 1111]: ") or 1111
|
||||||
|
data = APIHandler(apikey).get_entry_from_elabid(elabid)
|
||||||
|
sample = Entrypoint(data)
|
||||||
|
substrate_object = chain_entrypoint_to_batch(sample) # Substrate-class object
|
||||||
|
layers = chain_entrypoint_to_layers(sample) # list of Layer-class objects
|
||||||
|
result = make_nexus_schema_dictionary(substrate_object, layers)
|
||||||
|
# print(make_nexus_schema_dictionary(substrate_object, layers)) # debug
|
||||||
|
with open (f"output/sample-{elabid}.json", "w") as f:
|
||||||
|
json.dump(result, f, indent=3)
|
||||||
|
|||||||
207
tests/chained_requests.py
Normal file
207
tests/chained_requests.py
Normal file
@@ -0,0 +1,207 @@
|
|||||||
|
import os, json, requests
|
||||||
|
from getpass import getpass
|
||||||
|
|
||||||
|
class Header:
|
||||||
|
'''
|
||||||
|
Class to standardize the format of the headers of our http requests.
|
||||||
|
'''
|
||||||
|
def __init__(self, apikey=""):
|
||||||
|
'''Init method, apikey suggested but not required (empty by default).'''
|
||||||
|
self.auth = {"Authorization" : apikey}
|
||||||
|
self.content = {"Content-Type" : "application/json"}
|
||||||
|
self.header = {**self.auth, **self.content}
|
||||||
|
|
||||||
|
def get_entry_from_elabid(elabid, entryType="items"):
|
||||||
|
'''
|
||||||
|
Function which returns entrypoint data (as dictionary) from its elabid.
|
||||||
|
'''
|
||||||
|
header = Header(apikey).header
|
||||||
|
response = requests.get(
|
||||||
|
headers = header,
|
||||||
|
url = f"{ELABFTW_API_URL}/{entryType}/{elabid}",
|
||||||
|
verify=True
|
||||||
|
)
|
||||||
|
if response.status_code // 100 in [2,3]:
|
||||||
|
entry_data = response.json()
|
||||||
|
return entry_data
|
||||||
|
else:
|
||||||
|
raise ConnectionError(f"HTTP request failed with status code: {response.status_code}.")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class Layer:
|
||||||
|
'''
|
||||||
|
Layer(layer_data) - where layer_data is a Python dictionary.
|
||||||
|
|
||||||
|
Meant to be used for eLabFTW Experiments of the "PLD Deposition" category.
|
||||||
|
|
||||||
|
eLabFTW experiments contain most of the data required by the NeXus file - although every layer is on a different eLab entry;
|
||||||
|
unfortunately, some data like the target's chemical formula must be retrieved through additional HTTP requests.
|
||||||
|
Attributes 'target_elabid', 'rheed_system_elabid' and 'laser_system_elabid' contain elabid's for these resources, which are all items.
|
||||||
|
'''
|
||||||
|
def __init__(self, layer_data):
|
||||||
|
try:
|
||||||
|
self.extra = layer_data["metadata_decoded"]["extra_fields"]
|
||||||
|
self.layer_number = self.extra["Layer Progressive Number"]["value"] # integer
|
||||||
|
self.target_elabid = self.extra["Target"]["value"] # elabid
|
||||||
|
self.rheed_system_elabid = self.extra["RHEED System"]["value"] # elabid
|
||||||
|
self.laser_system_elabid = self.extra["Laser System"]["value"] # elabid
|
||||||
|
self.start_time = layer_data.get("created_at")
|
||||||
|
self.operator = layer_data.get("fullname")
|
||||||
|
self.description = layer_data.get("body")
|
||||||
|
self.deposition_time = self.extra["Duration"]["value"]
|
||||||
|
self.repetition_rate = self.extra["Repetition rate"]["value"]
|
||||||
|
try:
|
||||||
|
self.number_of_pulses = float(self.deposition_time) * float(self.repetition_rate)
|
||||||
|
except ValueError:
|
||||||
|
# Since number_of_pulses is required, if it can't be calculated raise error:
|
||||||
|
raise ValueError("""
|
||||||
|
Fatal: either Duration or Repetition Rate are empty or invalid.
|
||||||
|
This has to be an error, since these fields are required by the NeXus standard.
|
||||||
|
Please edit your eLabFTW entry and retry.
|
||||||
|
""")
|
||||||
|
self.temperature = self.extra["Heater temperature"]["value"] # Note: this field used to have a trailing space in its name
|
||||||
|
self.process_pressure = self.extra["Process pressure"]["value"] # Note: this field used to have a trailing space in its name
|
||||||
|
self.heating_method = self.extra["Heating Method"]["value"]
|
||||||
|
self.layer_thickness = self.extra["Thickness"]["value"]
|
||||||
|
self.buffer_gas = self.extra["Buffer gas"]["value"]
|
||||||
|
self.heater_target_distance = self.extra["Heater-target distance"]["value"]
|
||||||
|
self.laser_fluence = self.extra["Laser Intensity"]["value"] # here fluence = intensity
|
||||||
|
self.laser_spot_area = self.extra["Spot Area"]["value"]
|
||||||
|
try:
|
||||||
|
self.laser_energy = float(self.laser_fluence) * float(self.laser_spot_area)
|
||||||
|
except ValueError:
|
||||||
|
# Since laser_energy is NOT required, if it can't be calculated warn user but allow the software to continue execution:
|
||||||
|
print("""
|
||||||
|
Warning: either Laser Intensity or Spot Area are empty or invalid.
|
||||||
|
If you think this is an error, please edit your eLabFTW entry and retry.
|
||||||
|
Setting Laser Energy to NoneType.
|
||||||
|
""")
|
||||||
|
# Placeholder
|
||||||
|
self.laser_energy = None
|
||||||
|
# Laser rasternig section
|
||||||
|
self.laser_rastering_geometry = self.extra["Laser Rastering Geometry"]["value"]
|
||||||
|
self.laser_rastering_positions = self.extra["Laser Rastering Position"]["value"]
|
||||||
|
self.laser_rastering_velocities = self.extra["Laser Rastering Speed"]["value"]
|
||||||
|
# Pre annealing section
|
||||||
|
self.pre_annealing_ambient_gas = self.extra["Buffer gas Pre"]["value"]
|
||||||
|
self.pre_annealing_pressure = self.extra["Process pressure Pre"]["value"]
|
||||||
|
self.pre_annealing_temperature = self.extra["Heater temperature Pre"]["value"]
|
||||||
|
self.pre_annealing_duration = self.extra["Duration Pre"]["value"]
|
||||||
|
# Post annealing section
|
||||||
|
self.post_annealing_ambient_gas = self.extra["Buffer gas PA"]["value"]
|
||||||
|
self.post_annealing_pressure = self.extra["Process pressure PA"]["value"]
|
||||||
|
self.post_annealing_temperature = self.extra["Heater temperature PA"]["value"]
|
||||||
|
self.post_annealing_duration = self.extra["Duration PA"]["value"]
|
||||||
|
# Rejected but suggested by the NeXus standard:
|
||||||
|
#self.laser_rastering_coefficients = None
|
||||||
|
except KeyError as k:
|
||||||
|
# Some keys are not required and can be called through the .get() method - which is permissive and allows null values;
|
||||||
|
# Other keys are required so if they can't be called (invalid or null) raise error and stop execution of the program:
|
||||||
|
raise KeyError(f"The provided dictionary lacks a \"{k}\" key. Check the deposition layer entry on eLabFTW and make sure you used the correct Experiment template.")
|
||||||
|
|
||||||
|
class Entrypoint:
|
||||||
|
'''
|
||||||
|
Entrypoint(sample_data) - where sample_data is a Python dictionary.
|
||||||
|
|
||||||
|
Meant to be used for eLabFTW Resources of the "Sample" category.
|
||||||
|
|
||||||
|
The entrypoint is the starting point of the process of resolving the data chain.
|
||||||
|
The entrypoint must be a dictionary containing the data of a sample, created directly from the JSON of the item endpoint on eLabFTW - which can be done through the function get_entry_from_elabid.
|
||||||
|
'''
|
||||||
|
def __init__(self, sample_data):
|
||||||
|
try:
|
||||||
|
self.extra = sample_data["metadata_decoded"]["extra_fields"]
|
||||||
|
self.linked_items = sample_data["items_links"]
|
||||||
|
self.batch_elabid = self.extra["Substrate batch"]["value"]
|
||||||
|
self.linked_experiments = sample_data["related_experiments_links"]
|
||||||
|
self.linked_experiments_elabid = [ i["entityid"] for i in self.linked_experiments ]
|
||||||
|
except KeyError as k:
|
||||||
|
# Some keys are not required and can be called through the .get() method - which is permissive and allows null values;
|
||||||
|
# Other keys are required so if they can't be called (invalid or null) raise error and stop execution of the program:
|
||||||
|
raise KeyError(f"The provided dictionary lacks a \"{k}\" key. Check the sample entry on eLabFTW and make sure you used the correct Resource template.")
|
||||||
|
# Non-required attributes:
|
||||||
|
self.name = sample_data.get("title") or None # error prevention is more important than preventing empty fields here
|
||||||
|
|
||||||
|
class Material:
|
||||||
|
'''
|
||||||
|
Material(material_data) - where material_data is a Python dictionary.
|
||||||
|
|
||||||
|
Meant to be used for eLabFTW Resources of either the "PLD Target" or the "Substrate" categories.
|
||||||
|
|
||||||
|
Both a PLD Target and a Substrate are materials made of a certain compound, of which we want to know:
|
||||||
|
* Name and formula;
|
||||||
|
* Shape and dimensions;
|
||||||
|
* Misc.
|
||||||
|
'''
|
||||||
|
def __init__(self, material_data):
|
||||||
|
try:
|
||||||
|
self.extra = material_data["metadata_decoded"]["extra_fields"]
|
||||||
|
self.compound_elabid = self.extra["Compound"]["value"]
|
||||||
|
except KeyError as k:
|
||||||
|
# Some keys are not required and can be called through the .get() method - which is permissive and allows null values;
|
||||||
|
# Other keys are required so if they can't be called (invalid or null) raise error and stop execution of the program:
|
||||||
|
raise KeyError(f"The provided dictionary lacks a \"{k}\" key. Check the target/substrate entry on eLabFTW and make sure you used the correct Resource template.")
|
||||||
|
def get_compound_data(self):
|
||||||
|
raw_compound_data = get_entry_from_elabid(self.compound_elabid, entryType="items")
|
||||||
|
name = raw_compound_data["title"]
|
||||||
|
extra = raw_compound_data["metadata_decoded"]["extra_fields"]
|
||||||
|
formula = extra.get("Chemical formula")
|
||||||
|
cas = extra.get("CAS number ") or { "value": None }
|
||||||
|
compound_data = {
|
||||||
|
"name" : name,
|
||||||
|
"chemical_formula" : formula.get("value"),
|
||||||
|
"cas_number" : cas.get("value")
|
||||||
|
}
|
||||||
|
return compound_data
|
||||||
|
def get_compound_formula(self):
|
||||||
|
formula = self.get_compound_data().get("chemical_formula")
|
||||||
|
return formula
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if __name__=="__main__":
|
||||||
|
print(f"=======================\n===== DEBUG MODE! =====\n=======================\n")
|
||||||
|
ELABFTW_API_URL = "https://elabftw.fisica.unina.it/api/v2"
|
||||||
|
apikey = getpass("Paste API key here: ")
|
||||||
|
# TEST. In production the entryType will probably just be "items" since the entrypoint is an item (sample).
|
||||||
|
entryType = None
|
||||||
|
while entryType not in ["items", "experiments"]:
|
||||||
|
eT = input("Enter a valid entry type [items, experiments]: ")
|
||||||
|
# This allows for a shortcut: instead of prompting the type before and the elabid after I can just prompt both at the same time - e.g. e51 is exp. 51, i1108 is item 1108...
|
||||||
|
if eT[0] in ["e", "i"] and eT[-1].isnumeric():
|
||||||
|
try:
|
||||||
|
elabid = int(eT[1:])
|
||||||
|
eT = eT[0]
|
||||||
|
except Exception:
|
||||||
|
print("Usage: i|item|items|i[ELABID] for items, e|experiment|experiments|e[ELABID] for experiments.")
|
||||||
|
continue
|
||||||
|
match eT:
|
||||||
|
case "items" | "i" | "item":
|
||||||
|
entryType = "items"
|
||||||
|
case "experiments" | "e" | "exp" | "experiment":
|
||||||
|
entryType = "experiments"
|
||||||
|
case _:
|
||||||
|
continue
|
||||||
|
# This will probably be reworked in production
|
||||||
|
try:
|
||||||
|
elabid = elabid
|
||||||
|
except NameError:
|
||||||
|
elabid = input("Input elabid here [default = 1111]: ") or 1111
|
||||||
|
data = get_entry_from_elabid(elabid, entryType)
|
||||||
|
if entryType == "experiments":
|
||||||
|
layer = Layer(data)
|
||||||
|
result = layer.__dict__
|
||||||
|
result.pop("extra")
|
||||||
|
print(result)
|
||||||
|
elif entryType == "items":
|
||||||
|
if data.get("category_title") == "Sample":
|
||||||
|
item = Entrypoint(data)
|
||||||
|
elif data.get("category_title") in ["PLD Target", "Substrate"]:
|
||||||
|
item = Material(data)
|
||||||
|
print(item.get_compound_formula(apikey))
|
||||||
|
else:
|
||||||
|
raise Exception("The selected item or experiment is not in one of the following categories: [Sample, PLD Target, Substrate, PLD Deposition].")
|
||||||
|
result = item.__dict__
|
||||||
|
result.pop("extra")
|
||||||
|
print(result)
|
||||||
480
tests/layer_A.json
Normal file
480
tests/layer_A.json
Normal file
@@ -0,0 +1,480 @@
|
|||||||
|
{
|
||||||
|
"access_key": null,
|
||||||
|
"body": "",
|
||||||
|
"body_html": "",
|
||||||
|
"canread": "{\"base\": 40, \"teams\": [], \"users\": [], \"teamgroups\": []}",
|
||||||
|
"canread_is_immutable": 0,
|
||||||
|
"canwrite": "{\"base\": 20, \"teams\": [], \"users\": [], \"teamgroups\": []}",
|
||||||
|
"canwrite_is_immutable": 0,
|
||||||
|
"category": 2,
|
||||||
|
"category_color": "8b8d43",
|
||||||
|
"category_title": "PLD Deposition",
|
||||||
|
"comments": [],
|
||||||
|
"compounds": [],
|
||||||
|
"containers": [],
|
||||||
|
"content_type": 1,
|
||||||
|
"created_at": "2026-02-09 09:53:50",
|
||||||
|
"custom_id": null,
|
||||||
|
"date": "2026-02-09",
|
||||||
|
"elabid": "20260209-8ba774f27896bbec37a7cc5eab18747dbac3a4fb",
|
||||||
|
"events_start": null,
|
||||||
|
"events_start_itemid": null,
|
||||||
|
"exclusive_edit_mode": null,
|
||||||
|
"experiments_links": [
|
||||||
|
{
|
||||||
|
"entityid": 59,
|
||||||
|
"title": "Na-26-015 lao on stocazzo",
|
||||||
|
"custom_id": null,
|
||||||
|
"elabid": "20260209-554888c7b8a17efd963fece04426f6ec5722fa8a",
|
||||||
|
"link_state": 1,
|
||||||
|
"page": "experiments.php",
|
||||||
|
"type": "experiments",
|
||||||
|
"category_title": "PLD Deposition",
|
||||||
|
"category_color": "8b8d43",
|
||||||
|
"status_title": null,
|
||||||
|
"status_color": null
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"firstname": "Emiliano",
|
||||||
|
"fullname": "Emiliano Di Gennaro",
|
||||||
|
"id": 58,
|
||||||
|
"is_pinned": 0,
|
||||||
|
"items_links": [
|
||||||
|
{
|
||||||
|
"entityid": 1075,
|
||||||
|
"title": "ETO single crystal",
|
||||||
|
"custom_id": null,
|
||||||
|
"elabid": "20260126-6f77512fa5a3c5803fcfc64797ffa003429094dc",
|
||||||
|
"link_state": 1,
|
||||||
|
"is_bookable": 0,
|
||||||
|
"page": "database.php",
|
||||||
|
"type": "items",
|
||||||
|
"category_title": "PLD Target",
|
||||||
|
"category_color": "1a5fb4",
|
||||||
|
"status_title": null,
|
||||||
|
"status_color": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"entityid": 1074,
|
||||||
|
"title": "LAO single crystal",
|
||||||
|
"custom_id": null,
|
||||||
|
"elabid": "20260126-2cef9e71c0ff4aa15062cb6562f64f6ac3a366fb",
|
||||||
|
"link_state": 1,
|
||||||
|
"is_bookable": 0,
|
||||||
|
"page": "database.php",
|
||||||
|
"type": "items",
|
||||||
|
"category_title": "PLD Target",
|
||||||
|
"category_color": "1a5fb4",
|
||||||
|
"status_title": null,
|
||||||
|
"status_color": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"entityid": 1099,
|
||||||
|
"title": "Coherent Excimer Laser (KrF 248 nm)",
|
||||||
|
"custom_id": null,
|
||||||
|
"elabid": "20260126-9175c1674aef9947736fbc12447f912c8ea9bc81",
|
||||||
|
"link_state": 1,
|
||||||
|
"is_bookable": 0,
|
||||||
|
"page": "database.php",
|
||||||
|
"type": "items",
|
||||||
|
"category_title": "Process Instrument",
|
||||||
|
"category_color": "a51d2d",
|
||||||
|
"status_title": "Available",
|
||||||
|
"status_color": "6a7753"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"entityid": 1096,
|
||||||
|
"title": "PLD Chamber I (small area)",
|
||||||
|
"custom_id": null,
|
||||||
|
"elabid": "20260126-19cf5d06fd119f841383f21db1c29eebfad550c5",
|
||||||
|
"link_state": 1,
|
||||||
|
"is_bookable": 1,
|
||||||
|
"page": "database.php",
|
||||||
|
"type": "items",
|
||||||
|
"category_title": "Process Instrument",
|
||||||
|
"category_color": "a51d2d",
|
||||||
|
"status_title": "Available",
|
||||||
|
"status_color": "6a7753"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"entityid": 1098,
|
||||||
|
"title": "STAIB RHEED 30",
|
||||||
|
"custom_id": null,
|
||||||
|
"elabid": "20260126-5df7738907b198451c19296ab07e5093d12a3ead",
|
||||||
|
"link_state": 1,
|
||||||
|
"is_bookable": 0,
|
||||||
|
"page": "database.php",
|
||||||
|
"type": "items",
|
||||||
|
"category_title": "Process Instrument",
|
||||||
|
"category_color": "a51d2d",
|
||||||
|
"status_title": "Available",
|
||||||
|
"status_color": "6a7753"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"entityid": 1111,
|
||||||
|
"title": "Na-26-015",
|
||||||
|
"custom_id": null,
|
||||||
|
"elabid": "20260209-6e19f19795b7ea79594a35d9a11da1896b13453e",
|
||||||
|
"link_state": 1,
|
||||||
|
"is_bookable": 0,
|
||||||
|
"page": "database.php",
|
||||||
|
"type": "items",
|
||||||
|
"category_title": "Sample",
|
||||||
|
"category_color": "ffbe6f",
|
||||||
|
"status_title": null,
|
||||||
|
"status_color": null
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"lastchangeby": 2,
|
||||||
|
"lastname": "Di Gennaro",
|
||||||
|
"locked": 0,
|
||||||
|
"locked_at": null,
|
||||||
|
"lockedby": null,
|
||||||
|
"metadata": "{\"elabftw\": {\"extra_fields_groups\": [{\"id\": 1, \"name\": \"Process\"}, {\"id\": 2, \"name\": \"Laser\"}, {\"id\": 3, \"name\": \"Pre Annealing\"}, {\"id\": 4, \"name\": \"Post Annealing\"}, {\"id\": 5, \"name\": \"Instruments\"}]}, \"extra_fields\": {\"Sample\": {\"type\": \"items\", \"value\": 1111, \"group_id\": 1, \"position\": 0, \"required\": true}, \"Target\": {\"type\": \"items\", \"value\": 1075, \"group_id\": 1, \"position\": 2, \"required\": true}, \"Chamber\": {\"type\": \"items\", \"value\": 1096, \"group_id\": 5, \"position\": 0, \"required\": true}, \"Duration\": {\"type\": \"number\", \"unit\": \"s\", \"units\": [\"s\", \"min\"], \"value\": \"45\", \"group_id\": 1, \"position\": 3, \"required\": true}, \"Spot Area\": {\"type\": \"number\", \"unit\": \"mm^2\", \"units\": [\"mm^2\"], \"value\": \"0.8\", \"group_id\": 2, \"position\": 2}, \"Thickness\": {\"type\": \"number\", \"unit\": \"u.c.\", \"units\": [\"u.c.\", \"nm\"], \"value\": \"3\", \"group_id\": 1, \"position\": 4}, \"Buffer gas\": {\"type\": \"select\", \"value\": \"O2\", \"options\": [\"O2\", \"N2\", \"Ar\", \"\"], \"group_id\": 1, \"position\": 5}, \"Duration PA\": {\"type\": \"number\", \"unit\": \"s\", \"units\": [\"s\", \"min\"], \"value\": \"\", \"group_id\": 4, \"position\": 0}, \"Duration Pre\": {\"type\": \"number\", \"unit\": \"s\", \"units\": [\"s\", \"min\"], \"value\": \"\", \"group_id\": 3, \"position\": 0}, \"Laser System\": {\"type\": \"items\", \"value\": 1099, \"group_id\": 5, \"position\": 1}, \"RHEED System\": {\"type\": \"items\", \"value\": 1098, \"group_id\": 5, \"position\": 2}, \"Buffer gas PA\": {\"type\": \"select\", \"value\": \"O2\", \"options\": [\"O2\", \"N2\", \"Ar\", \"\"], \"group_id\": 4, \"position\": 1}, \"Buffer gas Pre\": {\"type\": \"select\", \"value\": \"O2\", \"options\": [\"O2\", \"N2\", \"Ar\", \"\"], \"group_id\": 3, \"position\": 1}, \"Heating Method\": {\"type\": \"select\", \"value\": \"Radiative Heater\", \"options\": [\"Radiative Heater\", \"Laser Heater\"], \"group_id\": 1, \"position\": 9}, \"Laser Intensity\": {\"type\": \"number\", \"unit\": \"J/(s cm^2)\", \"units\": [\"J/(s cm^2)\"], \"value\": \"1.5\", \"group_id\": 2, \"position\": 0}, \"Repetition rate\": {\"type\": \"number\", \"unit\": \"Hz\", \"units\": [\"Hz\"], \"value\": \"1\", \"group_id\": 2, \"position\": 1}, \"Process pressure\": {\"type\": \"number\", \"unit\": \"mbar\", \"units\": [\"mbar\"], \"value\": \"1e-3\", \"group_id\": 1, \"position\": 6}, \"Heater temperature\": {\"type\": \"number\", \"unit\": \"\u00b0C\", \"units\": [\"\u00b0C\"], \"value\": \"650\", \"group_id\": 1, \"position\": 7}, \"Process pressure PA\": {\"type\": \"number\", \"unit\": \"mbar\", \"units\": [\"mbar\"], \"value\": \"\", \"group_id\": 4, \"position\": 2}, \"Process pressure Pre\": {\"type\": \"number\", \"unit\": \"mbar\", \"units\": [\"mbar\"], \"value\": \"\", \"group_id\": 3, \"position\": 2}, \"Heater temperature PA\": {\"type\": \"number\", \"unit\": \"\u00b0C\", \"units\": [\"\u00b0C\"], \"value\": \"\", \"group_id\": 4, \"position\": 3}, \"Laser Rastering Speed\": {\"type\": \"number\", \"unit\": \"\", \"units\": [], \"value\": \"\", \"group_id\": 2, \"position\": 4}, \"Heater temperature Pre\": {\"type\": \"number\", \"unit\": \"\u00b0C\", \"units\": [\"\u00b0C\"], \"value\": \"\", \"group_id\": 3, \"position\": 3}, \"Heater-target distance\": {\"type\": \"number\", \"unit\": \"mm\", \"units\": [\"mm\"], \"value\": \"45\", \"group_id\": 1, \"position\": 8}, \"Laser Rastering Geometry\": {\"type\": \"select\", \"value\": \"none\", \"options\": [\"none\", \"on a square\", \"on a rectangle\", \"on a line\", \"other\"], \"group_id\": 2, \"position\": 3}, \"Laser Rastering Position\": {\"type\": \"number\", \"unit\": \"\", \"units\": [], \"value\": \"\", \"group_id\": 2, \"position\": 5}, \"Layer Progressive Number\": {\"type\": \"number\", \"unit\": \"\", \"units\": [], \"value\": \"2\", \"group_id\": 1, \"position\": 1, \"required\": true}}}",
|
||||||
|
"metadata_decoded": {
|
||||||
|
"elabftw": {
|
||||||
|
"extra_fields_groups": [
|
||||||
|
{
|
||||||
|
"id": 1,
|
||||||
|
"name": "Process"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 2,
|
||||||
|
"name": "Laser"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 3,
|
||||||
|
"name": "Pre Annealing"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 4,
|
||||||
|
"name": "Post Annealing"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 5,
|
||||||
|
"name": "Instruments"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"extra_fields": {
|
||||||
|
"Sample": {
|
||||||
|
"type": "items",
|
||||||
|
"value": 1111,
|
||||||
|
"group_id": 1,
|
||||||
|
"position": 0,
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
"Target": {
|
||||||
|
"type": "items",
|
||||||
|
"value": 1075,
|
||||||
|
"group_id": 1,
|
||||||
|
"position": 2,
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
"Chamber": {
|
||||||
|
"type": "items",
|
||||||
|
"value": 1096,
|
||||||
|
"group_id": 5,
|
||||||
|
"position": 0,
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
"Duration": {
|
||||||
|
"type": "number",
|
||||||
|
"unit": "s",
|
||||||
|
"units": [
|
||||||
|
"s",
|
||||||
|
"min"
|
||||||
|
],
|
||||||
|
"value": "69",
|
||||||
|
"group_id": 1,
|
||||||
|
"position": 3,
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
"Spot Area": {
|
||||||
|
"type": "number",
|
||||||
|
"unit": "mm^2",
|
||||||
|
"units": [
|
||||||
|
"mm^2"
|
||||||
|
],
|
||||||
|
"value": "0.8",
|
||||||
|
"group_id": 2,
|
||||||
|
"position": 2
|
||||||
|
},
|
||||||
|
"Thickness": {
|
||||||
|
"type": "number",
|
||||||
|
"unit": "u.c.",
|
||||||
|
"units": [
|
||||||
|
"u.c.",
|
||||||
|
"nm"
|
||||||
|
],
|
||||||
|
"value": "3",
|
||||||
|
"group_id": 1,
|
||||||
|
"position": 4
|
||||||
|
},
|
||||||
|
"Buffer gas": {
|
||||||
|
"type": "select",
|
||||||
|
"value": "O2",
|
||||||
|
"options": [
|
||||||
|
"O2",
|
||||||
|
"N2",
|
||||||
|
"Ar",
|
||||||
|
""
|
||||||
|
],
|
||||||
|
"group_id": 1,
|
||||||
|
"position": 5
|
||||||
|
},
|
||||||
|
"Duration PA": {
|
||||||
|
"type": "number",
|
||||||
|
"unit": "s",
|
||||||
|
"units": [
|
||||||
|
"s",
|
||||||
|
"min"
|
||||||
|
],
|
||||||
|
"value": "",
|
||||||
|
"group_id": 4,
|
||||||
|
"position": 0
|
||||||
|
},
|
||||||
|
"Duration Pre": {
|
||||||
|
"type": "number",
|
||||||
|
"unit": "s",
|
||||||
|
"units": [
|
||||||
|
"s",
|
||||||
|
"min"
|
||||||
|
],
|
||||||
|
"value": "",
|
||||||
|
"group_id": 3,
|
||||||
|
"position": 0
|
||||||
|
},
|
||||||
|
"Laser System": {
|
||||||
|
"type": "items",
|
||||||
|
"value": 1099,
|
||||||
|
"group_id": 5,
|
||||||
|
"position": 1
|
||||||
|
},
|
||||||
|
"RHEED System": {
|
||||||
|
"type": "items",
|
||||||
|
"value": 1098,
|
||||||
|
"group_id": 5,
|
||||||
|
"position": 2
|
||||||
|
},
|
||||||
|
"Buffer gas PA": {
|
||||||
|
"type": "select",
|
||||||
|
"value": "O2",
|
||||||
|
"options": [
|
||||||
|
"O2",
|
||||||
|
"N2",
|
||||||
|
"Ar",
|
||||||
|
""
|
||||||
|
],
|
||||||
|
"group_id": 4,
|
||||||
|
"position": 1
|
||||||
|
},
|
||||||
|
"Buffer gas Pre": {
|
||||||
|
"type": "select",
|
||||||
|
"value": "O2",
|
||||||
|
"options": [
|
||||||
|
"O2",
|
||||||
|
"N2",
|
||||||
|
"Ar",
|
||||||
|
""
|
||||||
|
],
|
||||||
|
"group_id": 3,
|
||||||
|
"position": 1
|
||||||
|
},
|
||||||
|
"Heating Method": {
|
||||||
|
"type": "select",
|
||||||
|
"value": "Radiative Heater",
|
||||||
|
"options": [
|
||||||
|
"Radiative Heater",
|
||||||
|
"Laser Heater"
|
||||||
|
],
|
||||||
|
"group_id": 1,
|
||||||
|
"position": 9
|
||||||
|
},
|
||||||
|
"Laser Intensity": {
|
||||||
|
"type": "number",
|
||||||
|
"unit": "J/(s cm^2)",
|
||||||
|
"units": [
|
||||||
|
"J/(s cm^2)"
|
||||||
|
],
|
||||||
|
"value": "1.5",
|
||||||
|
"group_id": 2,
|
||||||
|
"position": 0
|
||||||
|
},
|
||||||
|
"Repetition rate": {
|
||||||
|
"type": "number",
|
||||||
|
"unit": "Hz",
|
||||||
|
"units": [
|
||||||
|
"Hz"
|
||||||
|
],
|
||||||
|
"value": "1",
|
||||||
|
"group_id": 2,
|
||||||
|
"position": 1
|
||||||
|
},
|
||||||
|
"Process pressure": {
|
||||||
|
"type": "number",
|
||||||
|
"unit": "mbar",
|
||||||
|
"units": [
|
||||||
|
"mbar"
|
||||||
|
],
|
||||||
|
"value": "1e-3",
|
||||||
|
"group_id": 1,
|
||||||
|
"position": 6
|
||||||
|
},
|
||||||
|
"Heater temperature": {
|
||||||
|
"type": "number",
|
||||||
|
"unit": "\u00b0C",
|
||||||
|
"units": [
|
||||||
|
"\u00b0C"
|
||||||
|
],
|
||||||
|
"value": "650",
|
||||||
|
"group_id": 1,
|
||||||
|
"position": 7
|
||||||
|
},
|
||||||
|
"Process pressure PA": {
|
||||||
|
"type": "number",
|
||||||
|
"unit": "mbar",
|
||||||
|
"units": [
|
||||||
|
"mbar"
|
||||||
|
],
|
||||||
|
"value": "",
|
||||||
|
"group_id": 4,
|
||||||
|
"position": 2
|
||||||
|
},
|
||||||
|
"Process pressure Pre": {
|
||||||
|
"type": "number",
|
||||||
|
"unit": "mbar",
|
||||||
|
"units": [
|
||||||
|
"mbar"
|
||||||
|
],
|
||||||
|
"value": "",
|
||||||
|
"group_id": 3,
|
||||||
|
"position": 2
|
||||||
|
},
|
||||||
|
"Heater temperature PA": {
|
||||||
|
"type": "number",
|
||||||
|
"unit": "\u00b0C",
|
||||||
|
"units": [
|
||||||
|
"\u00b0C"
|
||||||
|
],
|
||||||
|
"value": "",
|
||||||
|
"group_id": 4,
|
||||||
|
"position": 3
|
||||||
|
},
|
||||||
|
"Laser Rastering Speed": {
|
||||||
|
"type": "number",
|
||||||
|
"unit": "",
|
||||||
|
"units": [],
|
||||||
|
"value": "",
|
||||||
|
"group_id": 2,
|
||||||
|
"position": 4
|
||||||
|
},
|
||||||
|
"Heater temperature Pre": {
|
||||||
|
"type": "number",
|
||||||
|
"unit": "\u00b0C",
|
||||||
|
"units": [
|
||||||
|
"\u00b0C"
|
||||||
|
],
|
||||||
|
"value": "",
|
||||||
|
"group_id": 3,
|
||||||
|
"position": 3
|
||||||
|
},
|
||||||
|
"Heater-target distance": {
|
||||||
|
"type": "number",
|
||||||
|
"unit": "mm",
|
||||||
|
"units": [
|
||||||
|
"mm"
|
||||||
|
],
|
||||||
|
"value": "45",
|
||||||
|
"group_id": 1,
|
||||||
|
"position": 8
|
||||||
|
},
|
||||||
|
"Laser Rastering Geometry": {
|
||||||
|
"type": "select",
|
||||||
|
"value": "none",
|
||||||
|
"options": [
|
||||||
|
"none",
|
||||||
|
"on a square",
|
||||||
|
"on a rectangle",
|
||||||
|
"on a line",
|
||||||
|
"other"
|
||||||
|
],
|
||||||
|
"group_id": 2,
|
||||||
|
"position": 3
|
||||||
|
},
|
||||||
|
"Laser Rastering Position": {
|
||||||
|
"type": "number",
|
||||||
|
"unit": "",
|
||||||
|
"units": [],
|
||||||
|
"value": "",
|
||||||
|
"group_id": 2,
|
||||||
|
"position": 5
|
||||||
|
},
|
||||||
|
"Layer Progressive Number": {
|
||||||
|
"type": "number",
|
||||||
|
"unit": "",
|
||||||
|
"units": [],
|
||||||
|
"value": "3",
|
||||||
|
"group_id": 1,
|
||||||
|
"position": 1,
|
||||||
|
"required": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"modified_at": "2026-02-09 15:16:33",
|
||||||
|
"next_step": null,
|
||||||
|
"orcid": "0000-0003-4231-9776",
|
||||||
|
"page": "experiments",
|
||||||
|
"rating": 0,
|
||||||
|
"recent_comment": null,
|
||||||
|
"related_experiments_links": [],
|
||||||
|
"related_items_links": [],
|
||||||
|
"sharelink": "https://elabftw.fisica.unina.it:8080/experiments.php?mode=view&id=58",
|
||||||
|
"state": 1,
|
||||||
|
"status": null,
|
||||||
|
"status_color": null,
|
||||||
|
"status_title": null,
|
||||||
|
"steps": [
|
||||||
|
{
|
||||||
|
"id": 74,
|
||||||
|
"item_id": 58,
|
||||||
|
"body": "add process data",
|
||||||
|
"ordering": 1,
|
||||||
|
"finished": 1,
|
||||||
|
"finished_time": "2026-02-09 09:54:53",
|
||||||
|
"deadline": null,
|
||||||
|
"deadline_notif": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 75,
|
||||||
|
"item_id": 58,
|
||||||
|
"body": "add RHEED data",
|
||||||
|
"ordering": 2,
|
||||||
|
"finished": 1,
|
||||||
|
"finished_time": "2026-02-09 09:54:54",
|
||||||
|
"deadline": null,
|
||||||
|
"deadline_notif": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 76,
|
||||||
|
"item_id": 58,
|
||||||
|
"body": "add RHEED images",
|
||||||
|
"ordering": 3,
|
||||||
|
"finished": 1,
|
||||||
|
"finished_time": "2026-02-09 09:54:56",
|
||||||
|
"deadline": null,
|
||||||
|
"deadline_notif": 0
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"tags": null,
|
||||||
|
"tags_id": null,
|
||||||
|
"team": 1,
|
||||||
|
"team_name": "Default team",
|
||||||
|
"timestamped": 0,
|
||||||
|
"timestamped_at": null,
|
||||||
|
"timestampedby": null,
|
||||||
|
"title": "Na-26-015 eto on lao on sto",
|
||||||
|
"type": "experiments",
|
||||||
|
"uploads": [],
|
||||||
|
"userid": 2
|
||||||
|
}
|
||||||
500
tests/layer_B.json
Normal file
500
tests/layer_B.json
Normal file
@@ -0,0 +1,500 @@
|
|||||||
|
{
|
||||||
|
"access_key": null,
|
||||||
|
"body": "",
|
||||||
|
"body_html": "",
|
||||||
|
"canread": "{\"base\": 40, \"teams\": [], \"users\": [], \"teamgroups\": []}",
|
||||||
|
"canread_is_immutable": 0,
|
||||||
|
"canwrite": "{\"base\": 20, \"teams\": [], \"users\": [], \"teamgroups\": []}",
|
||||||
|
"canwrite_is_immutable": 0,
|
||||||
|
"category": 2,
|
||||||
|
"category_color": "8b8d43",
|
||||||
|
"category_title": "PLD Deposition",
|
||||||
|
"comments": [],
|
||||||
|
"compounds": [],
|
||||||
|
"containers": [],
|
||||||
|
"content_type": 1,
|
||||||
|
"created_at": "2026-02-09 09:32:10",
|
||||||
|
"custom_id": null,
|
||||||
|
"date": "2026-02-09",
|
||||||
|
"elabid": "20260209-554888c7b8a17efd963fece04426f6ec5722fa8a",
|
||||||
|
"events_start": null,
|
||||||
|
"events_start_itemid": null,
|
||||||
|
"exclusive_edit_mode": null,
|
||||||
|
"experiments_links": [],
|
||||||
|
"firstname": "Emiliano",
|
||||||
|
"fullname": "Emiliano Di Gennaro",
|
||||||
|
"id": 56,
|
||||||
|
"is_pinned": 0,
|
||||||
|
"items_links": [
|
||||||
|
{
|
||||||
|
"entityid": 1074,
|
||||||
|
"title": "LAO single crystal",
|
||||||
|
"custom_id": null,
|
||||||
|
"elabid": "20260126-2cef9e71c0ff4aa15062cb6562f64f6ac3a366fb",
|
||||||
|
"link_state": 1,
|
||||||
|
"is_bookable": 0,
|
||||||
|
"page": "database.php",
|
||||||
|
"type": "items",
|
||||||
|
"category_title": "PLD Target",
|
||||||
|
"category_color": "1a5fb4",
|
||||||
|
"status_title": null,
|
||||||
|
"status_color": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"entityid": 1099,
|
||||||
|
"title": "Coherent Excimer Laser (KrF 248 nm)",
|
||||||
|
"custom_id": null,
|
||||||
|
"elabid": "20260126-9175c1674aef9947736fbc12447f912c8ea9bc81",
|
||||||
|
"link_state": 1,
|
||||||
|
"is_bookable": 0,
|
||||||
|
"page": "database.php",
|
||||||
|
"type": "items",
|
||||||
|
"category_title": "Process Instrument",
|
||||||
|
"category_color": "a51d2d",
|
||||||
|
"status_title": "Available",
|
||||||
|
"status_color": "6a7753"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"entityid": 1096,
|
||||||
|
"title": "PLD Chamber I (small area)",
|
||||||
|
"custom_id": null,
|
||||||
|
"elabid": "20260126-19cf5d06fd119f841383f21db1c29eebfad550c5",
|
||||||
|
"link_state": 1,
|
||||||
|
"is_bookable": 1,
|
||||||
|
"page": "database.php",
|
||||||
|
"type": "items",
|
||||||
|
"category_title": "Process Instrument",
|
||||||
|
"category_color": "a51d2d",
|
||||||
|
"status_title": "Available",
|
||||||
|
"status_color": "6a7753"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"entityid": 1098,
|
||||||
|
"title": "STAIB RHEED 30",
|
||||||
|
"custom_id": null,
|
||||||
|
"elabid": "20260126-5df7738907b198451c19296ab07e5093d12a3ead",
|
||||||
|
"link_state": 1,
|
||||||
|
"is_bookable": 0,
|
||||||
|
"page": "database.php",
|
||||||
|
"type": "items",
|
||||||
|
"category_title": "Process Instrument",
|
||||||
|
"category_color": "a51d2d",
|
||||||
|
"status_title": "Available",
|
||||||
|
"status_color": "6a7753"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"entityid": 1111,
|
||||||
|
"title": "Na-26-015",
|
||||||
|
"custom_id": null,
|
||||||
|
"elabid": "20260209-6e19f19795b7ea79594a35d9a11da1896b13453e",
|
||||||
|
"link_state": 1,
|
||||||
|
"is_bookable": 0,
|
||||||
|
"page": "database.php",
|
||||||
|
"type": "items",
|
||||||
|
"category_title": "Sample",
|
||||||
|
"category_color": "ffbe6f",
|
||||||
|
"status_title": null,
|
||||||
|
"status_color": null
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"lastchangeby": 2,
|
||||||
|
"lastname": "Di Gennaro",
|
||||||
|
"locked": 0,
|
||||||
|
"locked_at": null,
|
||||||
|
"lockedby": null,
|
||||||
|
"metadata": "{\"elabftw\": {\"extra_fields_groups\": [{\"id\": 1, \"name\": \"Process\"}, {\"id\": 2, \"name\": \"Laser\"}, {\"id\": 3, \"name\": \"Pre Annealing\"}, {\"id\": 4, \"name\": \"Post Annealing\"}, {\"id\": 5, \"name\": \"Instruments\"}]}, \"extra_fields\": {\"Sample\": {\"type\": \"items\", \"value\": 1111, \"group_id\": 1, \"position\": 0, \"required\": true}, \"Target\": {\"type\": \"items\", \"value\": 1074, \"group_id\": 1, \"position\": 2, \"required\": true}, \"Chamber\": {\"type\": \"items\", \"value\": 1096, \"group_id\": 5, \"position\": 0, \"required\": true}, \"Duration\": {\"type\": \"number\", \"unit\": \"s\", \"units\": [\"s\", \"min\"], \"value\": \"128\", \"group_id\": 1, \"position\": 3, \"required\": true}, \"Spot Area\": {\"type\": \"number\", \"unit\": \"mm^2\", \"units\": [\"mm^2\"], \"value\": \"0.8\", \"group_id\": 2, \"position\": 2}, \"Thickness\": {\"type\": \"number\", \"unit\": \"u.c.\", \"units\": [\"u.c.\", \"nm\"], \"value\": \"8\", \"group_id\": 1, \"position\": 4}, \"Buffer gas\": {\"type\": \"select\", \"value\": \"O2\", \"options\": [\"O2\", \"N2\", \"Ar\", \"\"], \"group_id\": 1, \"position\": 5}, \"Duration PA\": {\"type\": \"number\", \"unit\": \"s\", \"units\": [\"s\", \"min\"], \"value\": \"\", \"group_id\": 4, \"position\": 0}, \"Duration Pre\": {\"type\": \"number\", \"unit\": \"s\", \"units\": [\"s\", \"min\"], \"value\": \"\", \"group_id\": 3, \"position\": 0}, \"Laser System\": {\"type\": \"items\", \"value\": 1099, \"group_id\": 5, \"position\": 1}, \"RHEED System\": {\"type\": \"items\", \"value\": 1098, \"group_id\": 5, \"position\": 2}, \"Buffer gas PA\": {\"type\": \"select\", \"value\": \"O2\", \"options\": [\"O2\", \"N2\", \"Ar\", \"\"], \"group_id\": 4, \"position\": 1}, \"Buffer gas Pre\": {\"type\": \"select\", \"value\": \"O2\", \"options\": [\"O2\", \"N2\", \"Ar\", \"\"], \"group_id\": 3, \"position\": 1}, \"Heating Method\": {\"type\": \"select\", \"value\": \"Radiative Heater\", \"options\": [\"Radiative Heater\", \"Laser Heater\"], \"group_id\": 1, \"position\": 9}, \"Laser Intensity\": {\"type\": \"number\", \"unit\": \"J/(s cm^2)\", \"units\": [\"J/(s cm^2)\"], \"value\": \"1.5\", \"group_id\": 2, \"position\": 0}, \"Repetition rate\": {\"type\": \"number\", \"unit\": \"Hz\", \"units\": [\"Hz\"], \"value\": \"1\", \"group_id\": 2, \"position\": 1}, \"Process pressure\": {\"type\": \"number\", \"unit\": \"mbar\", \"units\": [\"mbar\"], \"value\": \"1e-3\", \"group_id\": 1, \"position\": 6}, \"Heater temperature\": {\"type\": \"number\", \"unit\": \"\u00b0C\", \"units\": [\"\u00b0C\"], \"value\": \"650\", \"group_id\": 1, \"position\": 7}, \"Process pressure PA\": {\"type\": \"number\", \"unit\": \"mbar\", \"units\": [\"mbar\"], \"value\": \"\", \"group_id\": 4, \"position\": 2}, \"Process pressure Pre\": {\"type\": \"number\", \"unit\": \"mbar\", \"units\": [\"mbar\"], \"value\": \"1e-1\", \"group_id\": 3, \"position\": 2}, \"Heater temperature PA\": {\"type\": \"number\", \"unit\": \"\u00b0C\", \"units\": [\"\u00b0C\"], \"value\": \"\", \"group_id\": 4, \"position\": 3}, \"Laser Rastering Speed\": {\"type\": \"number\", \"unit\": \"\", \"units\": [], \"value\": \"\", \"group_id\": 2, \"position\": 4}, \"Heater temperature Pre\": {\"type\": \"number\", \"unit\": \"\u00b0C\", \"units\": [\"\u00b0C\"], \"value\": \"500\", \"group_id\": 3, \"position\": 3}, \"Heater-target distance\": {\"type\": \"number\", \"unit\": \"mm\", \"units\": [\"mm\"], \"value\": \"45\", \"group_id\": 1, \"position\": 8}, \"Laser Rastering Geometry\": {\"type\": \"select\", \"value\": \"none\", \"options\": [\"none\", \"on a square\", \"on a rectangle\", \"on a line\", \"other\"], \"group_id\": 2, \"position\": 3}, \"Laser Rastering Position\": {\"type\": \"number\", \"unit\": \"\", \"units\": [], \"value\": \"\", \"group_id\": 2, \"position\": 5}, \"Layer Progressive Number\": {\"type\": \"number\", \"unit\": \"\", \"units\": [], \"value\": \"1\", \"group_id\": 1, \"position\": 1, \"required\": true}}}",
|
||||||
|
"metadata_decoded": {
|
||||||
|
"elabftw": {
|
||||||
|
"extra_fields_groups": [
|
||||||
|
{
|
||||||
|
"id": 1,
|
||||||
|
"name": "Process"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 2,
|
||||||
|
"name": "Laser"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 3,
|
||||||
|
"name": "Pre Annealing"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 4,
|
||||||
|
"name": "Post Annealing"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 5,
|
||||||
|
"name": "Instruments"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"extra_fields": {
|
||||||
|
"Sample": {
|
||||||
|
"type": "items",
|
||||||
|
"value": 1111,
|
||||||
|
"group_id": 1,
|
||||||
|
"position": 0,
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
"Target": {
|
||||||
|
"type": "items",
|
||||||
|
"value": 1074,
|
||||||
|
"group_id": 1,
|
||||||
|
"position": 2,
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
"Chamber": {
|
||||||
|
"type": "items",
|
||||||
|
"value": 1096,
|
||||||
|
"group_id": 5,
|
||||||
|
"position": 0,
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
"Duration": {
|
||||||
|
"type": "number",
|
||||||
|
"unit": "s",
|
||||||
|
"units": [
|
||||||
|
"s",
|
||||||
|
"min"
|
||||||
|
],
|
||||||
|
"value": "128",
|
||||||
|
"group_id": 1,
|
||||||
|
"position": 3,
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
"Spot Area": {
|
||||||
|
"type": "number",
|
||||||
|
"unit": "mm^2",
|
||||||
|
"units": [
|
||||||
|
"mm^2"
|
||||||
|
],
|
||||||
|
"value": "0.8",
|
||||||
|
"group_id": 2,
|
||||||
|
"position": 2
|
||||||
|
},
|
||||||
|
"Thickness": {
|
||||||
|
"type": "number",
|
||||||
|
"unit": "u.c.",
|
||||||
|
"units": [
|
||||||
|
"u.c.",
|
||||||
|
"nm"
|
||||||
|
],
|
||||||
|
"value": "8",
|
||||||
|
"group_id": 1,
|
||||||
|
"position": 4
|
||||||
|
},
|
||||||
|
"Buffer gas": {
|
||||||
|
"type": "select",
|
||||||
|
"value": "O2",
|
||||||
|
"options": [
|
||||||
|
"O2",
|
||||||
|
"N2",
|
||||||
|
"Ar",
|
||||||
|
""
|
||||||
|
],
|
||||||
|
"group_id": 1,
|
||||||
|
"position": 5
|
||||||
|
},
|
||||||
|
"Duration PA": {
|
||||||
|
"type": "number",
|
||||||
|
"unit": "s",
|
||||||
|
"units": [
|
||||||
|
"s",
|
||||||
|
"min"
|
||||||
|
],
|
||||||
|
"value": "",
|
||||||
|
"group_id": 4,
|
||||||
|
"position": 0
|
||||||
|
},
|
||||||
|
"Duration Pre": {
|
||||||
|
"type": "number",
|
||||||
|
"unit": "s",
|
||||||
|
"units": [
|
||||||
|
"s",
|
||||||
|
"min"
|
||||||
|
],
|
||||||
|
"value": "",
|
||||||
|
"group_id": 3,
|
||||||
|
"position": 0
|
||||||
|
},
|
||||||
|
"Laser System": {
|
||||||
|
"type": "items",
|
||||||
|
"value": 1099,
|
||||||
|
"group_id": 5,
|
||||||
|
"position": 1
|
||||||
|
},
|
||||||
|
"RHEED System": {
|
||||||
|
"type": "items",
|
||||||
|
"value": 1098,
|
||||||
|
"group_id": 5,
|
||||||
|
"position": 2
|
||||||
|
},
|
||||||
|
"Buffer gas PA": {
|
||||||
|
"type": "select",
|
||||||
|
"value": "O2",
|
||||||
|
"options": [
|
||||||
|
"O2",
|
||||||
|
"N2",
|
||||||
|
"Ar",
|
||||||
|
""
|
||||||
|
],
|
||||||
|
"group_id": 4,
|
||||||
|
"position": 1
|
||||||
|
},
|
||||||
|
"Buffer gas Pre": {
|
||||||
|
"type": "select",
|
||||||
|
"value": "O2",
|
||||||
|
"options": [
|
||||||
|
"O2",
|
||||||
|
"N2",
|
||||||
|
"Ar",
|
||||||
|
""
|
||||||
|
],
|
||||||
|
"group_id": 3,
|
||||||
|
"position": 1
|
||||||
|
},
|
||||||
|
"Heating Method": {
|
||||||
|
"type": "select",
|
||||||
|
"value": "Radiative Heater",
|
||||||
|
"options": [
|
||||||
|
"Radiative Heater",
|
||||||
|
"Laser Heater"
|
||||||
|
],
|
||||||
|
"group_id": 1,
|
||||||
|
"position": 9
|
||||||
|
},
|
||||||
|
"Laser Intensity": {
|
||||||
|
"type": "number",
|
||||||
|
"unit": "J/(s cm^2)",
|
||||||
|
"units": [
|
||||||
|
"J/(s cm^2)"
|
||||||
|
],
|
||||||
|
"value": "1.5",
|
||||||
|
"group_id": 2,
|
||||||
|
"position": 0
|
||||||
|
},
|
||||||
|
"Repetition rate": {
|
||||||
|
"type": "number",
|
||||||
|
"unit": "Hz",
|
||||||
|
"units": [
|
||||||
|
"Hz"
|
||||||
|
],
|
||||||
|
"value": "1",
|
||||||
|
"group_id": 2,
|
||||||
|
"position": 1
|
||||||
|
},
|
||||||
|
"Process pressure": {
|
||||||
|
"type": "number",
|
||||||
|
"unit": "mbar",
|
||||||
|
"units": [
|
||||||
|
"mbar"
|
||||||
|
],
|
||||||
|
"value": "1e-3",
|
||||||
|
"group_id": 1,
|
||||||
|
"position": 6
|
||||||
|
},
|
||||||
|
"Heater temperature": {
|
||||||
|
"type": "number",
|
||||||
|
"unit": "\u00b0C",
|
||||||
|
"units": [
|
||||||
|
"\u00b0C"
|
||||||
|
],
|
||||||
|
"value": "650",
|
||||||
|
"group_id": 1,
|
||||||
|
"position": 7
|
||||||
|
},
|
||||||
|
"Process pressure PA": {
|
||||||
|
"type": "number",
|
||||||
|
"unit": "mbar",
|
||||||
|
"units": [
|
||||||
|
"mbar"
|
||||||
|
],
|
||||||
|
"value": "",
|
||||||
|
"group_id": 4,
|
||||||
|
"position": 2
|
||||||
|
},
|
||||||
|
"Process pressure Pre": {
|
||||||
|
"type": "number",
|
||||||
|
"unit": "mbar",
|
||||||
|
"units": [
|
||||||
|
"mbar"
|
||||||
|
],
|
||||||
|
"value": "1e-1",
|
||||||
|
"group_id": 3,
|
||||||
|
"position": 2
|
||||||
|
},
|
||||||
|
"Heater temperature PA": {
|
||||||
|
"type": "number",
|
||||||
|
"unit": "\u00b0C",
|
||||||
|
"units": [
|
||||||
|
"\u00b0C"
|
||||||
|
],
|
||||||
|
"value": "",
|
||||||
|
"group_id": 4,
|
||||||
|
"position": 3
|
||||||
|
},
|
||||||
|
"Laser Rastering Speed": {
|
||||||
|
"type": "number",
|
||||||
|
"unit": "",
|
||||||
|
"units": [],
|
||||||
|
"value": "",
|
||||||
|
"group_id": 2,
|
||||||
|
"position": 4
|
||||||
|
},
|
||||||
|
"Heater temperature Pre": {
|
||||||
|
"type": "number",
|
||||||
|
"unit": "\u00b0C",
|
||||||
|
"units": [
|
||||||
|
"\u00b0C"
|
||||||
|
],
|
||||||
|
"value": "500",
|
||||||
|
"group_id": 3,
|
||||||
|
"position": 3
|
||||||
|
},
|
||||||
|
"Heater-target distance": {
|
||||||
|
"type": "number",
|
||||||
|
"unit": "mm",
|
||||||
|
"units": [
|
||||||
|
"mm"
|
||||||
|
],
|
||||||
|
"value": "45",
|
||||||
|
"group_id": 1,
|
||||||
|
"position": 8
|
||||||
|
},
|
||||||
|
"Laser Rastering Geometry": {
|
||||||
|
"type": "select",
|
||||||
|
"value": "none",
|
||||||
|
"options": [
|
||||||
|
"none",
|
||||||
|
"on a square",
|
||||||
|
"on a rectangle",
|
||||||
|
"on a line",
|
||||||
|
"other"
|
||||||
|
],
|
||||||
|
"group_id": 2,
|
||||||
|
"position": 3
|
||||||
|
},
|
||||||
|
"Laser Rastering Position": {
|
||||||
|
"type": "number",
|
||||||
|
"unit": "",
|
||||||
|
"units": [],
|
||||||
|
"value": "",
|
||||||
|
"group_id": 2,
|
||||||
|
"position": 5
|
||||||
|
},
|
||||||
|
"Layer Progressive Number": {
|
||||||
|
"type": "number",
|
||||||
|
"unit": "",
|
||||||
|
"units": [],
|
||||||
|
"value": "1",
|
||||||
|
"group_id": 1,
|
||||||
|
"position": 1,
|
||||||
|
"required": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"modified_at": "2026-02-09 15:17:40",
|
||||||
|
"next_step": "add process data",
|
||||||
|
"orcid": "0000-0003-4231-9776",
|
||||||
|
"page": "experiments",
|
||||||
|
"rating": 0,
|
||||||
|
"recent_comment": null,
|
||||||
|
"related_experiments_links": [
|
||||||
|
{
|
||||||
|
"entityid": 58,
|
||||||
|
"title": "Na-26-015 eto on lao on sto",
|
||||||
|
"custom_id": null,
|
||||||
|
"link_state": 1,
|
||||||
|
"page": "experiments.php",
|
||||||
|
"type": "experiments",
|
||||||
|
"category_title": "PLD Deposition",
|
||||||
|
"category_color": "8b8d43",
|
||||||
|
"status_title": null,
|
||||||
|
"status_color": null
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"related_items_links": [],
|
||||||
|
"sharelink": "https://elabftw.fisica.unina.it:8080/experiments.php?mode=view&id=56",
|
||||||
|
"state": 1,
|
||||||
|
"status": null,
|
||||||
|
"status_color": null,
|
||||||
|
"status_title": null,
|
||||||
|
"steps": [
|
||||||
|
{
|
||||||
|
"id": 68,
|
||||||
|
"item_id": 56,
|
||||||
|
"body": "add process data",
|
||||||
|
"ordering": 1,
|
||||||
|
"finished": 0,
|
||||||
|
"finished_time": null,
|
||||||
|
"deadline": null,
|
||||||
|
"deadline_notif": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 69,
|
||||||
|
"item_id": 56,
|
||||||
|
"body": "add RHEED data",
|
||||||
|
"ordering": 2,
|
||||||
|
"finished": 1,
|
||||||
|
"finished_time": "2026-02-09 09:42:59",
|
||||||
|
"deadline": null,
|
||||||
|
"deadline_notif": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 70,
|
||||||
|
"item_id": 56,
|
||||||
|
"body": "add RHEED images",
|
||||||
|
"ordering": 3,
|
||||||
|
"finished": 1,
|
||||||
|
"finished_time": "2026-02-09 09:43:01",
|
||||||
|
"deadline": null,
|
||||||
|
"deadline_notif": 0
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"tags": null,
|
||||||
|
"tags_id": null,
|
||||||
|
"team": 1,
|
||||||
|
"team_name": "Default team",
|
||||||
|
"timestamped": 0,
|
||||||
|
"timestamped_at": null,
|
||||||
|
"timestampedby": null,
|
||||||
|
"title": "Na-26-015 lao on sto",
|
||||||
|
"type": "experiments",
|
||||||
|
"uploads": [
|
||||||
|
{
|
||||||
|
"id": 75,
|
||||||
|
"real_name": "LAO_16min50s_736C_STO.bmp",
|
||||||
|
"long_name": "ce/ce536c93131cca5b3066a34fea81ae427f21d4ab851e64ff2142c99a9c3c7659805f224c582a8a11bc08d6307a6f4e6415891e506a46d346e64d7defbd2fcb7b.bmp",
|
||||||
|
"comment": null,
|
||||||
|
"item_id": 56,
|
||||||
|
"userid": 2,
|
||||||
|
"type": "experiments",
|
||||||
|
"created_at": "2026-02-09 09:42:52",
|
||||||
|
"hash": "881747c39f70a5c2691fe1fe432f81e60e1b81aa81508b103a6bbc66c4183c6c",
|
||||||
|
"hash_algorithm": "sha256",
|
||||||
|
"storage": 1,
|
||||||
|
"filesize": 308278,
|
||||||
|
"state": 1,
|
||||||
|
"immutable": 0,
|
||||||
|
"fullname": "Emiliano Di Gennaro"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 74,
|
||||||
|
"real_name": "Real-time Window Analysis ( Peak Int. ).txt",
|
||||||
|
"long_name": "18/18932061059d64b7edf332568f21507e15e61f054696fda4d88b1c431e6e04209ac1848328f7d72cb39222cdf2b250be5038e491d62809ca9e62542e54a94452.txt",
|
||||||
|
"comment": null,
|
||||||
|
"item_id": 56,
|
||||||
|
"userid": 2,
|
||||||
|
"type": "experiments",
|
||||||
|
"created_at": "2026-02-09 09:42:43",
|
||||||
|
"hash": "1dab085e81dca7c6b8380c98225bc429506ece28e51e976ae564b3b5289b58fe",
|
||||||
|
"hash_algorithm": "sha256",
|
||||||
|
"storage": 1,
|
||||||
|
"filesize": 3755169,
|
||||||
|
"state": 1,
|
||||||
|
"immutable": 0,
|
||||||
|
"fullname": "Emiliano Di Gennaro"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"userid": 2
|
||||||
|
}
|
||||||
480
tests/layer_C.json
Normal file
480
tests/layer_C.json
Normal file
@@ -0,0 +1,480 @@
|
|||||||
|
{
|
||||||
|
"access_key": null,
|
||||||
|
"body": "",
|
||||||
|
"body_html": "",
|
||||||
|
"canread": "{\"base\": 40, \"teams\": [], \"users\": [], \"teamgroups\": []}",
|
||||||
|
"canread_is_immutable": 0,
|
||||||
|
"canwrite": "{\"base\": 20, \"teams\": [], \"users\": [], \"teamgroups\": []}",
|
||||||
|
"canwrite_is_immutable": 0,
|
||||||
|
"category": 2,
|
||||||
|
"category_color": "8b8d43",
|
||||||
|
"category_title": "PLD Deposition",
|
||||||
|
"comments": [],
|
||||||
|
"compounds": [],
|
||||||
|
"containers": [],
|
||||||
|
"content_type": 1,
|
||||||
|
"created_at": "2026-02-09 09:53:50",
|
||||||
|
"custom_id": null,
|
||||||
|
"date": "2026-02-09",
|
||||||
|
"elabid": "20260209-8ba774f27896bbec37a7cc5eab18747dbac3a4fb",
|
||||||
|
"events_start": null,
|
||||||
|
"events_start_itemid": null,
|
||||||
|
"exclusive_edit_mode": null,
|
||||||
|
"experiments_links": [
|
||||||
|
{
|
||||||
|
"entityid": 56,
|
||||||
|
"title": "Na-26-015 lao on sto",
|
||||||
|
"custom_id": null,
|
||||||
|
"elabid": "20260209-554888c7b8a17efd963fece04426f6ec5722fa8a",
|
||||||
|
"link_state": 1,
|
||||||
|
"page": "experiments.php",
|
||||||
|
"type": "experiments",
|
||||||
|
"category_title": "PLD Deposition",
|
||||||
|
"category_color": "8b8d43",
|
||||||
|
"status_title": null,
|
||||||
|
"status_color": null
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"firstname": "Emiliano",
|
||||||
|
"fullname": "Emiliano Di Gennaro",
|
||||||
|
"id": 58,
|
||||||
|
"is_pinned": 0,
|
||||||
|
"items_links": [
|
||||||
|
{
|
||||||
|
"entityid": 1075,
|
||||||
|
"title": "ETO single crystal",
|
||||||
|
"custom_id": null,
|
||||||
|
"elabid": "20260126-6f77512fa5a3c5803fcfc64797ffa003429094dc",
|
||||||
|
"link_state": 1,
|
||||||
|
"is_bookable": 0,
|
||||||
|
"page": "database.php",
|
||||||
|
"type": "items",
|
||||||
|
"category_title": "PLD Target",
|
||||||
|
"category_color": "1a5fb4",
|
||||||
|
"status_title": null,
|
||||||
|
"status_color": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"entityid": 1074,
|
||||||
|
"title": "LAO single crystal",
|
||||||
|
"custom_id": null,
|
||||||
|
"elabid": "20260126-2cef9e71c0ff4aa15062cb6562f64f6ac3a366fb",
|
||||||
|
"link_state": 1,
|
||||||
|
"is_bookable": 0,
|
||||||
|
"page": "database.php",
|
||||||
|
"type": "items",
|
||||||
|
"category_title": "PLD Target",
|
||||||
|
"category_color": "1a5fb4",
|
||||||
|
"status_title": null,
|
||||||
|
"status_color": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"entityid": 1099,
|
||||||
|
"title": "Coherent Excimer Laser (KrF 248 nm)",
|
||||||
|
"custom_id": null,
|
||||||
|
"elabid": "20260126-9175c1674aef9947736fbc12447f912c8ea9bc81",
|
||||||
|
"link_state": 1,
|
||||||
|
"is_bookable": 0,
|
||||||
|
"page": "database.php",
|
||||||
|
"type": "items",
|
||||||
|
"category_title": "Process Instrument",
|
||||||
|
"category_color": "a51d2d",
|
||||||
|
"status_title": "Available",
|
||||||
|
"status_color": "6a7753"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"entityid": 1096,
|
||||||
|
"title": "PLD Chamber I (small area)",
|
||||||
|
"custom_id": null,
|
||||||
|
"elabid": "20260126-19cf5d06fd119f841383f21db1c29eebfad550c5",
|
||||||
|
"link_state": 1,
|
||||||
|
"is_bookable": 1,
|
||||||
|
"page": "database.php",
|
||||||
|
"type": "items",
|
||||||
|
"category_title": "Process Instrument",
|
||||||
|
"category_color": "a51d2d",
|
||||||
|
"status_title": "Available",
|
||||||
|
"status_color": "6a7753"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"entityid": 1098,
|
||||||
|
"title": "STAIB RHEED 30",
|
||||||
|
"custom_id": null,
|
||||||
|
"elabid": "20260126-5df7738907b198451c19296ab07e5093d12a3ead",
|
||||||
|
"link_state": 1,
|
||||||
|
"is_bookable": 0,
|
||||||
|
"page": "database.php",
|
||||||
|
"type": "items",
|
||||||
|
"category_title": "Process Instrument",
|
||||||
|
"category_color": "a51d2d",
|
||||||
|
"status_title": "Available",
|
||||||
|
"status_color": "6a7753"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"entityid": 1111,
|
||||||
|
"title": "Na-26-015",
|
||||||
|
"custom_id": null,
|
||||||
|
"elabid": "20260209-6e19f19795b7ea79594a35d9a11da1896b13453e",
|
||||||
|
"link_state": 1,
|
||||||
|
"is_bookable": 0,
|
||||||
|
"page": "database.php",
|
||||||
|
"type": "items",
|
||||||
|
"category_title": "Sample",
|
||||||
|
"category_color": "ffbe6f",
|
||||||
|
"status_title": null,
|
||||||
|
"status_color": null
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"lastchangeby": 2,
|
||||||
|
"lastname": "Di Gennaro",
|
||||||
|
"locked": 0,
|
||||||
|
"locked_at": null,
|
||||||
|
"lockedby": null,
|
||||||
|
"metadata": "{\"elabftw\": {\"extra_fields_groups\": [{\"id\": 1, \"name\": \"Process\"}, {\"id\": 2, \"name\": \"Laser\"}, {\"id\": 3, \"name\": \"Pre Annealing\"}, {\"id\": 4, \"name\": \"Post Annealing\"}, {\"id\": 5, \"name\": \"Instruments\"}]}, \"extra_fields\": {\"Sample\": {\"type\": \"items\", \"value\": 1111, \"group_id\": 1, \"position\": 0, \"required\": true}, \"Target\": {\"type\": \"items\", \"value\": 1075, \"group_id\": 1, \"position\": 2, \"required\": true}, \"Chamber\": {\"type\": \"items\", \"value\": 1096, \"group_id\": 5, \"position\": 0, \"required\": true}, \"Duration\": {\"type\": \"number\", \"unit\": \"s\", \"units\": [\"s\", \"min\"], \"value\": \"45\", \"group_id\": 1, \"position\": 3, \"required\": true}, \"Spot Area\": {\"type\": \"number\", \"unit\": \"mm^2\", \"units\": [\"mm^2\"], \"value\": \"0.8\", \"group_id\": 2, \"position\": 2}, \"Thickness\": {\"type\": \"number\", \"unit\": \"u.c.\", \"units\": [\"u.c.\", \"nm\"], \"value\": \"3\", \"group_id\": 1, \"position\": 4}, \"Buffer gas\": {\"type\": \"select\", \"value\": \"O2\", \"options\": [\"O2\", \"N2\", \"Ar\", \"\"], \"group_id\": 1, \"position\": 5}, \"Duration PA\": {\"type\": \"number\", \"unit\": \"s\", \"units\": [\"s\", \"min\"], \"value\": \"\", \"group_id\": 4, \"position\": 0}, \"Duration Pre\": {\"type\": \"number\", \"unit\": \"s\", \"units\": [\"s\", \"min\"], \"value\": \"\", \"group_id\": 3, \"position\": 0}, \"Laser System\": {\"type\": \"items\", \"value\": 1099, \"group_id\": 5, \"position\": 1}, \"RHEED System\": {\"type\": \"items\", \"value\": 1098, \"group_id\": 5, \"position\": 2}, \"Buffer gas PA\": {\"type\": \"select\", \"value\": \"O2\", \"options\": [\"O2\", \"N2\", \"Ar\", \"\"], \"group_id\": 4, \"position\": 1}, \"Buffer gas Pre\": {\"type\": \"select\", \"value\": \"O2\", \"options\": [\"O2\", \"N2\", \"Ar\", \"\"], \"group_id\": 3, \"position\": 1}, \"Heating Method\": {\"type\": \"select\", \"value\": \"Radiative Heater\", \"options\": [\"Radiative Heater\", \"Laser Heater\"], \"group_id\": 1, \"position\": 9}, \"Laser Intensity\": {\"type\": \"number\", \"unit\": \"J/(s cm^2)\", \"units\": [\"J/(s cm^2)\"], \"value\": \"1.5\", \"group_id\": 2, \"position\": 0}, \"Repetition rate\": {\"type\": \"number\", \"unit\": \"Hz\", \"units\": [\"Hz\"], \"value\": \"1\", \"group_id\": 2, \"position\": 1}, \"Process pressure\": {\"type\": \"number\", \"unit\": \"mbar\", \"units\": [\"mbar\"], \"value\": \"1e-3\", \"group_id\": 1, \"position\": 6}, \"Heater temperature\": {\"type\": \"number\", \"unit\": \"\u00b0C\", \"units\": [\"\u00b0C\"], \"value\": \"650\", \"group_id\": 1, \"position\": 7}, \"Process pressure PA\": {\"type\": \"number\", \"unit\": \"mbar\", \"units\": [\"mbar\"], \"value\": \"\", \"group_id\": 4, \"position\": 2}, \"Process pressure Pre\": {\"type\": \"number\", \"unit\": \"mbar\", \"units\": [\"mbar\"], \"value\": \"\", \"group_id\": 3, \"position\": 2}, \"Heater temperature PA\": {\"type\": \"number\", \"unit\": \"\u00b0C\", \"units\": [\"\u00b0C\"], \"value\": \"\", \"group_id\": 4, \"position\": 3}, \"Laser Rastering Speed\": {\"type\": \"number\", \"unit\": \"\", \"units\": [], \"value\": \"\", \"group_id\": 2, \"position\": 4}, \"Heater temperature Pre\": {\"type\": \"number\", \"unit\": \"\u00b0C\", \"units\": [\"\u00b0C\"], \"value\": \"\", \"group_id\": 3, \"position\": 3}, \"Heater-target distance\": {\"type\": \"number\", \"unit\": \"mm\", \"units\": [\"mm\"], \"value\": \"45\", \"group_id\": 1, \"position\": 8}, \"Laser Rastering Geometry\": {\"type\": \"select\", \"value\": \"none\", \"options\": [\"none\", \"on a square\", \"on a rectangle\", \"on a line\", \"other\"], \"group_id\": 2, \"position\": 3}, \"Laser Rastering Position\": {\"type\": \"number\", \"unit\": \"\", \"units\": [], \"value\": \"\", \"group_id\": 2, \"position\": 5}, \"Layer Progressive Number\": {\"type\": \"number\", \"unit\": \"\", \"units\": [], \"value\": \"2\", \"group_id\": 1, \"position\": 1, \"required\": true}}}",
|
||||||
|
"metadata_decoded": {
|
||||||
|
"elabftw": {
|
||||||
|
"extra_fields_groups": [
|
||||||
|
{
|
||||||
|
"id": 1,
|
||||||
|
"name": "Process"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 2,
|
||||||
|
"name": "Laser"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 3,
|
||||||
|
"name": "Pre Annealing"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 4,
|
||||||
|
"name": "Post Annealing"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 5,
|
||||||
|
"name": "Instruments"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"extra_fields": {
|
||||||
|
"Sample": {
|
||||||
|
"type": "items",
|
||||||
|
"value": 1111,
|
||||||
|
"group_id": 1,
|
||||||
|
"position": 0,
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
"Target": {
|
||||||
|
"type": "items",
|
||||||
|
"value": 1075,
|
||||||
|
"group_id": 1,
|
||||||
|
"position": 2,
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
"Chamber": {
|
||||||
|
"type": "items",
|
||||||
|
"value": 1096,
|
||||||
|
"group_id": 5,
|
||||||
|
"position": 0,
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
"Duration": {
|
||||||
|
"type": "number",
|
||||||
|
"unit": "s",
|
||||||
|
"units": [
|
||||||
|
"s",
|
||||||
|
"min"
|
||||||
|
],
|
||||||
|
"value": "45",
|
||||||
|
"group_id": 1,
|
||||||
|
"position": 3,
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
"Spot Area": {
|
||||||
|
"type": "number",
|
||||||
|
"unit": "mm^2",
|
||||||
|
"units": [
|
||||||
|
"mm^2"
|
||||||
|
],
|
||||||
|
"value": "0.8",
|
||||||
|
"group_id": 2,
|
||||||
|
"position": 2
|
||||||
|
},
|
||||||
|
"Thickness": {
|
||||||
|
"type": "number",
|
||||||
|
"unit": "u.c.",
|
||||||
|
"units": [
|
||||||
|
"u.c.",
|
||||||
|
"nm"
|
||||||
|
],
|
||||||
|
"value": "3",
|
||||||
|
"group_id": 1,
|
||||||
|
"position": 4
|
||||||
|
},
|
||||||
|
"Buffer gas": {
|
||||||
|
"type": "select",
|
||||||
|
"value": "O2",
|
||||||
|
"options": [
|
||||||
|
"O2",
|
||||||
|
"N2",
|
||||||
|
"Ar",
|
||||||
|
""
|
||||||
|
],
|
||||||
|
"group_id": 1,
|
||||||
|
"position": 5
|
||||||
|
},
|
||||||
|
"Duration PA": {
|
||||||
|
"type": "number",
|
||||||
|
"unit": "s",
|
||||||
|
"units": [
|
||||||
|
"s",
|
||||||
|
"min"
|
||||||
|
],
|
||||||
|
"value": "",
|
||||||
|
"group_id": 4,
|
||||||
|
"position": 0
|
||||||
|
},
|
||||||
|
"Duration Pre": {
|
||||||
|
"type": "number",
|
||||||
|
"unit": "s",
|
||||||
|
"units": [
|
||||||
|
"s",
|
||||||
|
"min"
|
||||||
|
],
|
||||||
|
"value": "",
|
||||||
|
"group_id": 3,
|
||||||
|
"position": 0
|
||||||
|
},
|
||||||
|
"Laser System": {
|
||||||
|
"type": "items",
|
||||||
|
"value": 1099,
|
||||||
|
"group_id": 5,
|
||||||
|
"position": 1
|
||||||
|
},
|
||||||
|
"RHEED System": {
|
||||||
|
"type": "items",
|
||||||
|
"value": 1098,
|
||||||
|
"group_id": 5,
|
||||||
|
"position": 2
|
||||||
|
},
|
||||||
|
"Buffer gas PA": {
|
||||||
|
"type": "select",
|
||||||
|
"value": "O2",
|
||||||
|
"options": [
|
||||||
|
"O2",
|
||||||
|
"N2",
|
||||||
|
"Ar",
|
||||||
|
""
|
||||||
|
],
|
||||||
|
"group_id": 4,
|
||||||
|
"position": 1
|
||||||
|
},
|
||||||
|
"Buffer gas Pre": {
|
||||||
|
"type": "select",
|
||||||
|
"value": "O2",
|
||||||
|
"options": [
|
||||||
|
"O2",
|
||||||
|
"N2",
|
||||||
|
"Ar",
|
||||||
|
""
|
||||||
|
],
|
||||||
|
"group_id": 3,
|
||||||
|
"position": 1
|
||||||
|
},
|
||||||
|
"Heating Method": {
|
||||||
|
"type": "select",
|
||||||
|
"value": "Radiative Heater",
|
||||||
|
"options": [
|
||||||
|
"Radiative Heater",
|
||||||
|
"Laser Heater"
|
||||||
|
],
|
||||||
|
"group_id": 1,
|
||||||
|
"position": 9
|
||||||
|
},
|
||||||
|
"Laser Intensity": {
|
||||||
|
"type": "number",
|
||||||
|
"unit": "J/(s cm^2)",
|
||||||
|
"units": [
|
||||||
|
"J/(s cm^2)"
|
||||||
|
],
|
||||||
|
"value": "1.5",
|
||||||
|
"group_id": 2,
|
||||||
|
"position": 0
|
||||||
|
},
|
||||||
|
"Repetition rate": {
|
||||||
|
"type": "number",
|
||||||
|
"unit": "Hz",
|
||||||
|
"units": [
|
||||||
|
"Hz"
|
||||||
|
],
|
||||||
|
"value": "1",
|
||||||
|
"group_id": 2,
|
||||||
|
"position": 1
|
||||||
|
},
|
||||||
|
"Process pressure": {
|
||||||
|
"type": "number",
|
||||||
|
"unit": "mbar",
|
||||||
|
"units": [
|
||||||
|
"mbar"
|
||||||
|
],
|
||||||
|
"value": "1e-3",
|
||||||
|
"group_id": 1,
|
||||||
|
"position": 6
|
||||||
|
},
|
||||||
|
"Heater temperature": {
|
||||||
|
"type": "number",
|
||||||
|
"unit": "\u00b0C",
|
||||||
|
"units": [
|
||||||
|
"\u00b0C"
|
||||||
|
],
|
||||||
|
"value": "650",
|
||||||
|
"group_id": 1,
|
||||||
|
"position": 7
|
||||||
|
},
|
||||||
|
"Process pressure PA": {
|
||||||
|
"type": "number",
|
||||||
|
"unit": "mbar",
|
||||||
|
"units": [
|
||||||
|
"mbar"
|
||||||
|
],
|
||||||
|
"value": "",
|
||||||
|
"group_id": 4,
|
||||||
|
"position": 2
|
||||||
|
},
|
||||||
|
"Process pressure Pre": {
|
||||||
|
"type": "number",
|
||||||
|
"unit": "mbar",
|
||||||
|
"units": [
|
||||||
|
"mbar"
|
||||||
|
],
|
||||||
|
"value": "",
|
||||||
|
"group_id": 3,
|
||||||
|
"position": 2
|
||||||
|
},
|
||||||
|
"Heater temperature PA": {
|
||||||
|
"type": "number",
|
||||||
|
"unit": "\u00b0C",
|
||||||
|
"units": [
|
||||||
|
"\u00b0C"
|
||||||
|
],
|
||||||
|
"value": "",
|
||||||
|
"group_id": 4,
|
||||||
|
"position": 3
|
||||||
|
},
|
||||||
|
"Laser Rastering Speed": {
|
||||||
|
"type": "number",
|
||||||
|
"unit": "",
|
||||||
|
"units": [],
|
||||||
|
"value": "",
|
||||||
|
"group_id": 2,
|
||||||
|
"position": 4
|
||||||
|
},
|
||||||
|
"Heater temperature Pre": {
|
||||||
|
"type": "number",
|
||||||
|
"unit": "\u00b0C",
|
||||||
|
"units": [
|
||||||
|
"\u00b0C"
|
||||||
|
],
|
||||||
|
"value": "",
|
||||||
|
"group_id": 3,
|
||||||
|
"position": 3
|
||||||
|
},
|
||||||
|
"Heater-target distance": {
|
||||||
|
"type": "number",
|
||||||
|
"unit": "mm",
|
||||||
|
"units": [
|
||||||
|
"mm"
|
||||||
|
],
|
||||||
|
"value": "45",
|
||||||
|
"group_id": 1,
|
||||||
|
"position": 8
|
||||||
|
},
|
||||||
|
"Laser Rastering Geometry": {
|
||||||
|
"type": "select",
|
||||||
|
"value": "none",
|
||||||
|
"options": [
|
||||||
|
"none",
|
||||||
|
"on a square",
|
||||||
|
"on a rectangle",
|
||||||
|
"on a line",
|
||||||
|
"other"
|
||||||
|
],
|
||||||
|
"group_id": 2,
|
||||||
|
"position": 3
|
||||||
|
},
|
||||||
|
"Laser Rastering Position": {
|
||||||
|
"type": "number",
|
||||||
|
"unit": "",
|
||||||
|
"units": [],
|
||||||
|
"value": "",
|
||||||
|
"group_id": 2,
|
||||||
|
"position": 5
|
||||||
|
},
|
||||||
|
"Layer Progressive Number": {
|
||||||
|
"type": "number",
|
||||||
|
"unit": "",
|
||||||
|
"units": [],
|
||||||
|
"value": "2",
|
||||||
|
"group_id": 1,
|
||||||
|
"position": 1,
|
||||||
|
"required": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"modified_at": "2026-02-09 15:16:33",
|
||||||
|
"next_step": null,
|
||||||
|
"orcid": "0000-0003-4231-9776",
|
||||||
|
"page": "experiments",
|
||||||
|
"rating": 0,
|
||||||
|
"recent_comment": null,
|
||||||
|
"related_experiments_links": [],
|
||||||
|
"related_items_links": [],
|
||||||
|
"sharelink": "https://elabftw.fisica.unina.it:8080/experiments.php?mode=view&id=58",
|
||||||
|
"state": 1,
|
||||||
|
"status": null,
|
||||||
|
"status_color": null,
|
||||||
|
"status_title": null,
|
||||||
|
"steps": [
|
||||||
|
{
|
||||||
|
"id": 74,
|
||||||
|
"item_id": 58,
|
||||||
|
"body": "add process data",
|
||||||
|
"ordering": 1,
|
||||||
|
"finished": 1,
|
||||||
|
"finished_time": "2026-02-09 09:54:53",
|
||||||
|
"deadline": null,
|
||||||
|
"deadline_notif": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 75,
|
||||||
|
"item_id": 58,
|
||||||
|
"body": "add RHEED data",
|
||||||
|
"ordering": 2,
|
||||||
|
"finished": 1,
|
||||||
|
"finished_time": "2026-02-09 09:54:54",
|
||||||
|
"deadline": null,
|
||||||
|
"deadline_notif": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 76,
|
||||||
|
"item_id": 58,
|
||||||
|
"body": "add RHEED images",
|
||||||
|
"ordering": 3,
|
||||||
|
"finished": 1,
|
||||||
|
"finished_time": "2026-02-09 09:54:56",
|
||||||
|
"deadline": null,
|
||||||
|
"deadline_notif": 0
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"tags": null,
|
||||||
|
"tags_id": null,
|
||||||
|
"team": 1,
|
||||||
|
"team_name": "Default team",
|
||||||
|
"timestamped": 0,
|
||||||
|
"timestamped_at": null,
|
||||||
|
"timestampedby": null,
|
||||||
|
"title": "Na-26-015 eto on lao on sto",
|
||||||
|
"type": "experiments",
|
||||||
|
"uploads": [],
|
||||||
|
"userid": 2
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user