Add support for data collection parameters across layers
Introduced serialization for `data_collection_parameters` in backend models and processing. Added logic to parse and attach data collection parameters in the frontend. This ensures consistent handling and storage of these parameters throughout the application.
This commit is contained in:
@ -8,7 +8,7 @@ from sqlalchemy.orm import Session, joinedload
|
|||||||
from typing import List
|
from typing import List
|
||||||
import logging
|
import logging
|
||||||
from sqlalchemy.exc import SQLAlchemyError
|
from sqlalchemy.exc import SQLAlchemyError
|
||||||
from pydantic import ValidationError
|
from pydantic import ValidationError, BaseModel
|
||||||
from app.schemas import (
|
from app.schemas import (
|
||||||
Dewar as DewarSchema,
|
Dewar as DewarSchema,
|
||||||
DewarCreate,
|
DewarCreate,
|
||||||
@ -88,6 +88,26 @@ async def create_dewar(
|
|||||||
db.refresh(puck)
|
db.refresh(puck)
|
||||||
|
|
||||||
for sample_data in puck_data.samples:
|
for sample_data in puck_data.samples:
|
||||||
|
logging.debug(
|
||||||
|
f"data_collection_parameters: "
|
||||||
|
f"{sample_data.data_collection_parameters}"
|
||||||
|
)
|
||||||
|
if sample_data.data_collection_parameters is None:
|
||||||
|
serialized_params = {}
|
||||||
|
elif hasattr(sample_data.data_collection_parameters, "to_dict"):
|
||||||
|
serialized_params = sample_data.data_collection_parameters.to_dict()
|
||||||
|
elif isinstance(sample_data.data_collection_parameters, BaseModel):
|
||||||
|
serialized_params = sample_data.data_collection_parameters.dict(
|
||||||
|
exclude_unset=True
|
||||||
|
)
|
||||||
|
elif isinstance(sample_data.data_collection_parameters, dict):
|
||||||
|
serialized_params = sample_data.data_collection_parameters
|
||||||
|
else:
|
||||||
|
raise ValueError(
|
||||||
|
"data_collection_parameters must be a dictionary,"
|
||||||
|
"have a to_dict method, or be None"
|
||||||
|
)
|
||||||
|
|
||||||
sample = SampleModel(
|
sample = SampleModel(
|
||||||
puck_id=puck.id,
|
puck_id=puck.id,
|
||||||
sample_name=sample_data.sample_name,
|
sample_name=sample_data.sample_name,
|
||||||
@ -95,7 +115,7 @@ async def create_dewar(
|
|||||||
position=sample_data.position,
|
position=sample_data.position,
|
||||||
priority=sample_data.priority,
|
priority=sample_data.priority,
|
||||||
comments=sample_data.comments,
|
comments=sample_data.comments,
|
||||||
data_collection_parameters=sample_data.data_collection_parameters,
|
data_collection_parameters=serialized_params,
|
||||||
)
|
)
|
||||||
db.add(sample)
|
db.add(sample)
|
||||||
db.commit()
|
db.commit()
|
||||||
|
@ -91,6 +91,12 @@ class DataCollectionParameters(BaseModel):
|
|||||||
chiphiangles: Optional[float] = None # Optional float field between 0 and 30
|
chiphiangles: Optional[float] = None # Optional float field between 0 and 30
|
||||||
dose: Optional[float] = None # Optional float field
|
dose: Optional[float] = None # Optional float field
|
||||||
|
|
||||||
|
def to_dict(self):
|
||||||
|
"""Convert the model instance to a dictionary."""
|
||||||
|
return self.dict(
|
||||||
|
exclude_unset=True
|
||||||
|
) # Use this built-in method for serialization
|
||||||
|
|
||||||
class Config:
|
class Config:
|
||||||
from_attributes = True
|
from_attributes = True
|
||||||
|
|
||||||
@ -416,6 +422,7 @@ class Sample(BaseModel):
|
|||||||
positioninpuck: Optional[int] = Field(None)
|
positioninpuck: Optional[int] = Field(None)
|
||||||
priority: Optional[int] = None
|
priority: Optional[int] = None
|
||||||
comments: Optional[str] = None
|
comments: Optional[str] = None
|
||||||
|
data_collection_parameters: Optional[DataCollectionParameters]
|
||||||
events: List[SampleEventCreate] = []
|
events: List[SampleEventCreate] = []
|
||||||
|
|
||||||
|
|
||||||
@ -423,7 +430,7 @@ class SampleCreate(BaseModel):
|
|||||||
sample_name: str = Field(..., alias="crystalname")
|
sample_name: str = Field(..., alias="crystalname")
|
||||||
proteinname: Optional[str] = None
|
proteinname: Optional[str] = None
|
||||||
position: int = Field(..., alias="positioninpuck")
|
position: int = Field(..., alias="positioninpuck")
|
||||||
data_collection_parameters: Optional[DataCollectionParameters] = None
|
data_collection_parameters: Optional[DataCollectionParameters] = Field(default=None)
|
||||||
priority: Optional[int] = None
|
priority: Optional[int] = None
|
||||||
comments: Optional[str] = None
|
comments: Optional[str] = None
|
||||||
results: Optional[Results] = None
|
results: Optional[Results] = None
|
||||||
|
@ -247,6 +247,7 @@ const SpreadsheetTable = ({
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Extract values from the appropriate columns
|
||||||
const dewarName = typeof row.data[dewarNameIdx] === 'string' ? row.data[dewarNameIdx].trim() : null;
|
const dewarName = typeof row.data[dewarNameIdx] === 'string' ? row.data[dewarNameIdx].trim() : null;
|
||||||
const puckName = row.data[puckNameIdx] !== undefined && row.data[puckNameIdx] !== null ? String(row.data[puckNameIdx]).trim() : null;
|
const puckName = row.data[puckNameIdx] !== undefined && row.data[puckNameIdx] !== null ? String(row.data[puckNameIdx]).trim() : null;
|
||||||
const puckType = typeof row.data[puckTypeIdx] === 'string' ? row.data[puckTypeIdx] : 'Unipuck';
|
const puckType = typeof row.data[puckTypeIdx] === 'string' ? row.data[puckTypeIdx] : 'Unipuck';
|
||||||
@ -256,6 +257,34 @@ const SpreadsheetTable = ({
|
|||||||
const priority = row?.data?.[priorityIdx] ? Number(row.data[priorityIdx]) : null;
|
const priority = row?.data?.[priorityIdx] ? Number(row.data[priorityIdx]) : null;
|
||||||
const comments = typeof row.data[commentsIdx] === 'string' ? row.data[commentsIdx].trim() : null;
|
const comments = typeof row.data[commentsIdx] === 'string' ? row.data[commentsIdx].trim() : null;
|
||||||
|
|
||||||
|
// Create data_collection_parameters object
|
||||||
|
const dataCollectionParameters = {
|
||||||
|
directory: row.data[fieldToCol['directory']],
|
||||||
|
oscillation: row.data[fieldToCol['oscillation']] ? parseFloat(row.data[fieldToCol['oscillation']]) : undefined,
|
||||||
|
aperture: row.data[fieldToCol['aperture']] ? row.data[fieldToCol['aperture']].trim() : undefined,
|
||||||
|
exposure: row.data[fieldToCol['exposure']] ? parseFloat(row.data[fieldToCol['exposure']]) : undefined,
|
||||||
|
totalrange: row.data[fieldToCol['totalrange']] ? parseInt(row.data[fieldToCol['totalrange']], 10) : undefined,
|
||||||
|
transmission: row.data[fieldToCol['transmission']] ? parseInt(row.data[fieldToCol['transmission']], 10) : undefined,
|
||||||
|
dose: row.data[fieldToCol['dose']] ? parseFloat(row.data[fieldToCol['dose']]) : undefined,
|
||||||
|
targetresolution: row.data[fieldToCol['targetresolution']] ? parseFloat(row.data[fieldToCol['targetresolution']]) : undefined,
|
||||||
|
datacollectiontype: row.data[fieldToCol['datacollectiontype']],
|
||||||
|
processingpipeline: row.data[fieldToCol['processingpipeline']],
|
||||||
|
spacegroupnumber: row.data[fieldToCol['spacegroupnumber']] ? parseInt(row.data[fieldToCol['spacegroupnumber']], 10) : undefined,
|
||||||
|
cellparameters: row.data[fieldToCol['cellparameters']],
|
||||||
|
rescutkey: row.data[fieldToCol['rescutkey']],
|
||||||
|
rescutvalue: row.data[fieldToCol['rescutvalue']] ? parseFloat(row.data[fieldToCol['rescutvalue']]) : undefined,
|
||||||
|
userresolution: row.data[fieldToCol['userresolution']] ? parseFloat(row.data[fieldToCol['userresolution']]) : undefined,
|
||||||
|
pdbid: row.data[fieldToCol['pdbid']],
|
||||||
|
autoprocfull: row.data[fieldToCol['autoprocfull']] === true,
|
||||||
|
procfull: row.data[fieldToCol['procfull']] === true,
|
||||||
|
adpenabled: row.data[fieldToCol['adpenabled']] === true,
|
||||||
|
noano: row.data[fieldToCol['noano']] === true,
|
||||||
|
ffcscampaign: row.data[fieldToCol['ffcscampaign']] === true,
|
||||||
|
trustedhigh: row.data[fieldToCol['trustedhigh']] ? parseFloat(row.data[fieldToCol['trustedhigh']]) : undefined,
|
||||||
|
autoprocextraparams: row.data[fieldToCol['autoprocextraparams']],
|
||||||
|
chiphiangles: row.data[fieldToCol['chiphiangles']] ? parseFloat(row.data[fieldToCol['chiphiangles']]) : undefined,
|
||||||
|
};
|
||||||
|
|
||||||
if (dewarName && puckName) {
|
if (dewarName && puckName) {
|
||||||
let dewar;
|
let dewar;
|
||||||
if (!dewars.has(dewarName)) {
|
if (!dewars.has(dewarName)) {
|
||||||
@ -301,7 +330,7 @@ const SpreadsheetTable = ({
|
|||||||
position: samplePosition,
|
position: samplePosition,
|
||||||
priority: priority,
|
priority: priority,
|
||||||
comments: comments,
|
comments: comments,
|
||||||
data_collection_parameters: null,
|
data_collection_parameters: dataCollectionParameters, // Attach the parameters
|
||||||
results: null // Placeholder for results field
|
results: null // Placeholder for results field
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user