Now we will run an IV analysis on the device data we uploaded in the previous notebook.
As before, make sure you have the following environment variables set or added to a .env file:
GDSFACTORY_HUB_API_URL="https://{org}.gdsfactoryhub.com"
GDSFACTORY_HUB_QUERY_URL="https://query.{org}.gdsfactoryhub.com"
GDSFACTORY_HUB_KEY="<your-gdsfactoryplus-api-key>"
project_id = f"resistance-{getpass.getuser()}"
client = gfh.create_client_from_env(project_id=project_id)
api = client.api()
query = client.query()
utils = client.utils()
We have a bunch of pre-defined analysis functions in the dodata SDK. An analysis function is actually a stand-alone python module with a single run function inside (more helper functions in the file are allowed, but run will be executed). Let's have a look at the iv_resistance analysis.
Let's run this one locally, to see what it gives:
linear_fit.run(
device_data_pkey=device_data_pkey,
xname="i",
yname="v",
slopename="resistance",
xlabel="Current (A)",
ylabel="Voltage (V)",
)
{'output': {'resistance': 4.1555410510312895e-08},
'summary_plot': <Figure size 640x480 with 1 Axes>,
'device_data_pkey': '3c4950a3-3d61-4c28-84cb-c1abf10dccd9'}

This analysis function clearly fits a straight line to an IV curve to obtain the resistance. The function ran locally, but it's always good to check if it runs on the server too:
# don't error out when function already exists in DoData.
with gfh.suppress_api_error():
result = api.upload_function(
function_id="linear_fit",
target_model="device_data",
file=gfh.get_module_path(linear_fit),
test_target_model_pk=device_data_pkey,
test_kwargs={
"xname": "i",
"yname": "v",
"slopename": "resistance",
"xlabel": "Current (A)",
"ylabel": "Voltage (V)",
},
)
Duplicate function
Note
If this would have failed to upload to the server but succeeded locally, you probably have to update the 'uv-comment' at the top of the file with updated dependencies. Such a uv-comment ensures that the script can be run by uv and all necessary dependencies will be installed. It usually looks as follows:
# /// script
# requires-python = ">=3.12"
# dependencies = [
# "gdsfactoryhub-sdk",
# "matplotlib",
# "numpy",
# ]
# ///
We can now trigger an analysis for the uploaded function:
result = api.start_analysis(
analysis_id=f"device_iv_resistance_{device_data_pkey}",
function_id="linear_fit",
target_model="device_data",
target_model_pk=device_data_pkey,
kwargs={
"xname": "i",
"yname": "v",
"slopename": "resistance",
"xlabel": "Current (A)",
"ylabel": "Voltage (V)",
},
)
utils.analyses().wait_for_completion(pks=[result["pk"]])
analysis = query.analyses().eq("pk", result["pk"]).limit(1).execute().data[0]
img = api.download_plot(analysis["summary_plot"]["path"])
img.resize((530, 400))
Waiting for analyses: 0%| | 0/1 [00:00<?, ?it/s]

Now, let's run the analysis for all devices:
results = []
dd_pks = [d["pk"] for d in query.device_data().execute().data]
for dd_pk in tqdm(dd_pks):
with gfh.suppress_api_error():
result = api.start_analysis(
analysis_id=f"device_iv_resistance_{dd_pk}",
function_id="linear_fit",
target_model="device_data",
target_model_pk=dd_pk,
kwargs={
"xname": "i",
"yname": "v",
"slopename": "resistance",
"xlabel": "Current (A)",
"ylabel": "Voltage (V)",
},
)
results.append(result)
0%| | 0/189 [00:00<?, ?it/s]
Let's have a look at the last analysis:
analysis_pks = [r["pk"] for r in results]
utils.analyses().wait_for_completion(pks=analysis_pks)
analyses = query.analyses().in_("pk", analysis_pks).execute().data
succesful_analyses = [a for a in analyses if a["status"] == "COMPLETED"]
analysis = succesful_analyses[-1]
img = api.download_plot(analysis["summary_plot"]["path"])
img.resize((530, 400))
Waiting for analyses: 0%| | 0/189 [00:00<?, ?it/s]
