Coverage for /opt/conda/envs/apienv/lib/python3.10/site-packages/daiquiri/core/metadata/ispyalchemy/dc.py: 80%
298 statements
« prev ^ index » next coverage.py v7.6.10, created at 2025-02-06 02:13 +0000
« prev ^ index » next coverage.py v7.6.10, created at 2025-02-06 02:13 +0000
1# -*- coding: utf-8 -*-
2import os
3import json
5from flask import g
7import sqlalchemy
8from sqlalchemy import func, or_
9from sqlalchemy.sql.expression import cast
11from daiquiri.core.metadata.ispyalchemy.handler import IspyalchemyHandler
12from daiquiri.core.metadata.ispyalchemy.utils import page, order
15class DCHandler(IspyalchemyHandler):
16 exported = [
17 "get_datacollections",
18 "add_datacollection",
19 "update_datacollection",
20 "get_datacollection_attachments",
21 "add_datacollection_attachment",
22 "add_sampleaction",
23 "update_sampleaction",
24 "get_sampleactions",
25 "get_sampleaction_positions",
26 "add_sampleaction_position",
27 "remove_sampleaction_position",
28 "get_scanqualityindicators",
29 "add_scanqualityindicators",
30 "get_datacollectionplans",
31 "add_datacollectionplan",
32 "update_datacollectionplan",
33 "remove_datacollectionplan",
34 "_decode_scanparameters",
35 ]
37 def get_datacollections(self, datacollectionid=None, **kwargs):
38 with self.session_scope() as ses:
39 duration = func.time_to_sec(
40 func.timediff(
41 self.DataCollection.endtime,
42 self.DataCollection.starttime,
43 )
44 )
45 dcid = self.DataCollection.datacollectionid
46 starttime = self.DataCollection.starttime
47 endtime = self.DataCollection.endtime
49 if not kwargs.get("datacollectiongroupid") and not kwargs.get("ungroup"):
50 duration = func.sum(duration)
51 dcid = func.min(self.DataCollection.datacollectionid).label(
52 "datacollectionid"
53 )
54 starttime = func.min(self.DataCollection.starttime).label("starttime")
55 endtime = func.max(self.DataCollection.endtime).label("endtime")
57 datacollections = (
58 ses.query(
59 dcid,
60 self.DataCollectionGroup.datacollectiongroupid,
61 self.DataCollectionGroup.blsampleid.label("sampleid"),
62 self.BLSample.name.label("sample"),
63 self.DataCollection.blsubsampleid.label("subsampleid"),
64 self.DataCollection.datacollectionnumber,
65 self.DataCollection.comments,
66 starttime,
67 endtime,
68 self.DataCollection.xtalsnapshotfullpath1,
69 self.DataCollection.xtalsnapshotfullpath2,
70 self.DataCollection.xtalsnapshotfullpath3,
71 self.DataCollection.xtalsnapshotfullpath4,
72 self.DataCollection.filetemplate,
73 self.DataCollection.imagedirectory,
74 duration.label("duration"),
75 self.DataCollection.runstatus,
76 self.DataCollectionGroup.experimenttype,
77 self.DataCollection.exposuretime,
78 self.DataCollection.numberofimages,
79 self.DataCollection.numberofpasses,
80 self.DataCollection.wavelength,
81 self.DataCollection.xbeam,
82 self.DataCollection.ybeam,
83 self.DataCollection.beamsizeatsamplex,
84 self.DataCollection.beamsizeatsampley,
85 cast(self.GridInfo.steps_x, sqlalchemy.Integer).label("steps_x"),
86 cast(self.GridInfo.steps_y, sqlalchemy.Integer).label("steps_y"),
87 self.GridInfo.patchesx,
88 self.GridInfo.patchesy,
89 self.GridInfo.dx_mm.label("dx_mm"),
90 self.GridInfo.dy_mm.label("dy_mm"),
91 self.GridInfo.snaked,
92 self.DataCollection.datacollectionplanid,
93 )
94 .join(
95 self.DataCollectionGroup,
96 self.DataCollectionGroup.datacollectiongroupid
97 == self.DataCollection.datacollectiongroupid,
98 )
99 .outerjoin(
100 self.BLSample,
101 self.BLSample.blsampleid == self.DataCollectionGroup.blsampleid,
102 )
103 .join(self.BLSession)
104 .outerjoin(
105 self.GridInfo,
106 self.GridInfo.datacollectionid
107 == self.DataCollection.datacollectionid,
108 )
109 )
111 if kwargs.get("datacollectiongroupid"):
112 datacollections = datacollections.filter(
113 self.DataCollection.datacollectiongroupid
114 == kwargs["datacollectiongroupid"]
115 )
116 elif kwargs.get("ungroup") is not None:
117 pass
118 else:
119 datacollections = datacollections.add_columns(
120 func.count(
121 func.distinct(self.DataCollection.datacollectionid)
122 ).label("datacollections")
123 )
124 datacollections = datacollections.group_by(
125 self.DataCollection.datacollectiongroupid
126 )
128 if not kwargs.get("no_context"):
129 datacollections = datacollections.filter(
130 self.BLSession.sessionid == g.blsession.get("sessionid")
131 )
133 if not g.user.staff():
134 datacollections = datacollections.join(
135 self.Session_has_Person
136 ).filter(self.Session_has_Person.personid == g.user.get("personid"))
138 if kwargs.get("sampleid"):
139 datacollections = datacollections.filter(
140 self.DataCollectionGroup.blsampleid == kwargs.get("sampleid")
141 )
143 if kwargs.get("subsampleid"):
144 datacollections = datacollections.filter(
145 self.DataCollection.blsubsampleid == kwargs.get("subsampleid")
146 )
148 if kwargs.get("status"):
149 datacollections = datacollections.filter(
150 self.DataCollection.runstatus == kwargs.get("status")
151 )
153 if datacollectionid:
154 datacollections = datacollections.filter(
155 self.DataCollection.datacollectionid == datacollectionid
156 )
157 datacollection = datacollections.first()
158 if datacollection:
159 datacollection = datacollection._asdict()
160 return self._check_snapshots(datacollection)
162 else:
163 total = datacollections.count()
164 datacollections = order(
165 datacollections,
166 {
167 "id": self.DataCollection.datacollectionid,
168 "starttime": self.DataCollection.starttime,
169 "runstatus": self.DataCollection.runstatus,
170 "experimenttype": self.DataCollectionGroup.experimenttype,
171 "duration": duration,
172 },
173 default=["id", "desc"],
174 **kwargs,
175 )
176 datacollections = page(datacollections, **kwargs)
178 dcs = [r._asdict() for r in datacollections.all()]
179 for dc in dcs:
180 dc = self._check_snapshots(dc)
182 return {"total": total, "rows": dcs}
184 def add_datacollection(self, **kwargs):
185 with self.session_scope() as ses:
186 dcg_id = kwargs.get("datacollectiongroupid")
187 if dcg_id is None:
188 dcg = self.DataCollectionGroup(
189 sessionid=kwargs.get("sessionid"),
190 # New location of sampleid
191 blsampleid=kwargs.get("sampleid"),
192 experimenttype=kwargs.get("experimenttype"),
193 scanparameters=kwargs.get("scanparameters"),
194 )
196 ses.add(dcg)
197 ses.commit()
199 dcg_id = dcg.datacollectiongroupid
201 dc = self.DataCollection(
202 datacollectiongroupid=dcg_id,
203 filetemplate=kwargs.get("filetemplate"),
204 imagedirectory=kwargs.get("imagedirectory"),
205 starttime=kwargs.get("starttime"),
206 # This is set in dcg, not dc
207 # experimenttype=kwargs.get("experimenttype"),
208 datacollectionplanid=kwargs.get("datacollectionplanid"),
209 # Legacy, but still used in synchweb, should be in dcg above
210 blsampleid=kwargs.get("sampleid"),
211 blsubsampleid=kwargs.get("subsampleid"),
212 datacollectionnumber=kwargs.get("datacollectionnumber", None),
213 exposuretime=kwargs.get("exposuretime", None),
214 numberofimages=kwargs.get("numberofimages", None),
215 xtalsnapshotfullpath1=kwargs.get("xtalsnapshotfullpath1"),
216 beamsizeatsamplex=kwargs.get("beamsizeatsamplex"),
217 beamsizeatsampley=kwargs.get("beamsizeatsampley"),
218 )
220 ses.add(dc)
221 ses.commit()
223 if kwargs.get("steps_x") or kwargs.get("steps_y"):
224 grid = self.GridInfo(
225 datacollectionid=dc.datacollectionid,
226 steps_x=kwargs.get("steps_x"),
227 steps_y=kwargs.get("steps_y"),
228 patchesx=kwargs.get("patchesx"),
229 patchesy=kwargs.get("patchesy"),
230 dx_mm=kwargs.get("dx_mm"),
231 dy_mm=kwargs.get("dy_mm"),
232 pixelspermicronx=kwargs.get("pixelspermicronx"),
233 pixelspermicrony=kwargs.get("pixelspermicrony"),
234 snapshot_offsetxpixel=kwargs.get("snapshot_offsetxpixel"),
235 snapshot_offsetypixel=kwargs.get("snapshot_offsetypixel"),
236 snaked=kwargs.get("snaked"),
237 )
239 ses.add(grid)
240 ses.commit()
242 return self.get_datacollections(
243 datacollectionid=dc.datacollectionid, no_context=True
244 )
246 def update_datacollection(self, datacollectionid, **kwargs):
247 with self.session_scope() as ses:
248 chk = self.get_datacollections(
249 datacollectionid=datacollectionid, no_context=kwargs.get("no_context")
250 )
251 if chk:
252 dc = (
253 ses.query(self.DataCollection)
254 .filter(self.DataCollection.datacollectionid == datacollectionid)
255 .first()
256 )
258 updatable = [
259 "runstatus",
260 "endtime",
261 "comments",
262 "datacollectionnumber",
263 "numberofimages",
264 "numberofpasses",
265 "xtalsnapshotfullpath1",
266 "xtalsnapshotfullpath2",
267 "xtalsnapshotfullpath3",
268 "xtalsnapshotfullpath4",
269 "wavelength",
270 "transmission",
271 "xbeam",
272 "ybeam",
273 "beamsizeatsamplex",
274 "beamsizeatsampley",
275 "imageprefix",
276 "imagedirectory",
277 "imagesuffix",
278 "filetemplate",
279 "imagecontainersubpath",
280 "detectordistance",
281 "detectorid",
282 "flux",
283 "exposuretime",
284 ]
285 for kw in kwargs:
286 if kw in updatable:
287 setattr(dc, kw, kwargs[kw])
289 gridinfo = (
290 ses.query(self.GridInfo)
291 .filter(self.GridInfo.datacollectionid == dc.datacollectionid)
292 .first()
293 )
295 gr_updatable = [
296 "orientation",
297 "steps_x",
298 "steps_y",
299 "patchesx",
300 "patchesy",
301 "dx_mm",
302 "dy_mm",
303 "pixelspermicronx",
304 "pixelspermicrony",
305 "snapshot_offsetxpixel",
306 "snapshot_offsetypixel",
307 "snaked",
308 ]
309 update_grid = False
310 for kw in kwargs:
311 if kw in gr_updatable:
312 update_grid = True
314 if update_grid:
315 if not gridinfo:
316 gridinfo = self.GridInfo(datacollectionid=dc.datacollectionid)
317 ses.add(gridinfo)
318 ses.commit()
320 for kw in kwargs:
321 if kw in gr_updatable:
322 setattr(gridinfo, kw, kwargs[kw])
324 ses.commit()
326 return self.get_datacollections(
327 datacollectionid=datacollectionid,
328 no_context=kwargs.get("no_context"),
329 )
331 def get_datacollection_attachments(self, datacollectionattachmentid=None, **kwargs):
332 with self.session_scope() as ses:
333 attachments = (
334 ses.query(
335 self.DataCollectionFileAttachment.datacollectionfileattachmentid,
336 self.DataCollectionFileAttachment.filefullpath,
337 self.DataCollectionFileAttachment.filetype,
338 )
339 .join(self.DataCollection)
340 .join(self.DataCollectionGroup)
341 )
343 if not kwargs.get("no_context"):
344 attachments = attachments.filter(
345 self.DataCollectionGroup.sessionid == g.blsession.get("sessionid")
346 )
348 if kwargs.get("datacollectionid"):
349 attachments = attachments.filter(
350 self.DataCollection.datacollectionid == kwargs["datacollectionid"]
351 )
353 if kwargs.get("filetype"):
354 attachments = attachments.filter(
355 self.DataCollectionFileAttachment.filetype == kwargs["filetype"]
356 )
358 if datacollectionattachmentid:
359 attachments = attachments.filter(
360 self.DataCollectionFileAttachment.datacollectionfileattachmentid
361 == datacollectionattachmentid
362 )
363 attachment = attachments.first()
364 if attachment:
365 return self._add_file_to_attachment(attachment._asdict())
367 else:
368 attachments = [
369 self._add_file_to_attachment(r._asdict()) for r in attachments.all()
370 ]
371 return {"total": len(attachments), "rows": attachments}
373 def _add_file_to_attachment(self, attachment):
374 attachment["filename"] = os.path.basename(attachment["filefullpath"])
375 attachment["extension"] = (
376 os.path.splitext(attachment["filename"])[1][1:].strip().lower()
377 )
378 return attachment
380 def add_datacollection_attachment(self, **kwargs):
381 dc = self.get_datacollections(
382 datacollectionid=kwargs.get("datacollectionid"),
383 no_context=kwargs.get("no_context"),
384 )
386 if dc:
387 with self.session_scope() as ses:
388 attachment = self.DataCollectionFileAttachment(
389 datacollectionid=kwargs.get("datacollectionid"),
390 filetype=kwargs.get("filetype"),
391 filefullpath=kwargs.get("filepath"),
392 )
394 ses.add(attachment)
395 ses.commit()
397 return self.get_datacollection_attachments(
398 attachment.datacollectionfileattachmentid,
399 no_context=kwargs.get("no_context"),
400 )
402 def get_sampleactions(self, sampleactionid=None, **kwargs):
403 with self.session_scope() as ses:
404 sampleactions = ses.query(
405 self.RobotAction.robotactionid.label("sampleactionid"),
406 self.RobotAction.blsessionid.label("sessionid"),
407 self.RobotAction.blsampleid.label("sampleid"),
408 self.RobotAction.actiontype,
409 self.RobotAction.starttimestamp,
410 self.RobotAction.endtimestamp,
411 self.RobotAction.status,
412 self.RobotAction.message,
413 self.RobotAction.xtalsnapshotbefore,
414 self.RobotAction.xtalsnapshotafter,
415 self.RobotAction.resultfilepath,
416 )
418 if not kwargs.get("no_context"):
419 sampleactions = sampleactions.filter(
420 self.RobotAction.blsessionid == g.blsession.get("sessionid")
421 )
423 if kwargs.get("actiontype"):
424 sampleactions = sampleactions.filter(
425 self.RobotAction.actiontype == kwargs["actiontype"]
426 )
428 if kwargs.get("sampleid"):
429 sampleactions = sampleactions.filter(
430 self.RobotAction.blsampleid == kwargs["sampleid"]
431 )
433 if sampleactionid:
434 sampleactions = sampleactions.filter(
435 self.RobotAction.robotactionid == sampleactionid
436 )
437 sampleaction = sampleactions.first()
438 if sampleaction:
439 sampleaction = sampleaction._asdict()
440 sampleaction = self._check_result(sampleaction)
441 return sampleaction
443 else:
444 sampleactions = [r._asdict() for r in sampleactions.all()]
445 for sampleaction in sampleactions:
446 sampleaction = self._check_result(sampleaction)
447 return {"total": len(sampleactions), "rows": sampleactions}
449 def _check_result(self, sampleaction):
450 sampleaction["has_result"] = (
451 os.path.exists(sampleaction["resultfilepath"])
452 if sampleaction["resultfilepath"]
453 else False
454 )
455 return sampleaction
457 def add_sampleaction(self, **kwargs):
458 with self.session_scope() as ses:
459 sample = self.get_samples(
460 sampleid=kwargs["sampleid"], no_context=kwargs.get("no_context")
461 )
463 if sample:
464 sampleaction = self.RobotAction(
465 blsessionid=kwargs.get("sessionid"),
466 blsampleid=kwargs.get("sampleid"),
467 actiontype=kwargs.get("actiontype"),
468 starttimestamp=kwargs.get("starttime"),
469 status=kwargs.get("status"),
470 message=kwargs.get("message"),
471 xtalsnapshotbefore=kwargs.get("xtalsnapshotbefore"),
472 xtalsnapshotafter=kwargs.get("xtalsnapshotafter"),
473 )
475 ses.add(sampleaction)
476 ses.commit()
478 return self.get_sampleactions(
479 sampleactionid=sampleaction.robotactionid,
480 no_context=kwargs.get("no_context"),
481 )
483 def update_sampleaction(self, sampleactionid, **kwargs):
484 with self.session_scope() as ses:
485 chk = self.get_sampleactions(
486 sampleactionid=sampleactionid, no_context=kwargs.get("no_context")
487 )
488 if chk:
489 sampleaction = (
490 ses.query(self.RobotAction)
491 .filter(self.RobotAction.robotactionid == sampleactionid)
492 .first()
493 )
495 updatable = [
496 "starttimestamp",
497 "endtimestamp",
498 "status",
499 "message",
500 "xtalsnapshotbefore",
501 "xtalsnapshotafter",
502 "resultfilepath",
503 ]
504 for kw in kwargs:
505 if kw in updatable:
506 val = kwargs[kw]
508 if kw == "message":
509 val = val[:255]
511 setattr(sampleaction, kw, val)
513 ses.commit()
515 return self.get_sampleactions(
516 sampleactionid=sampleactionid, no_context=kwargs.get("no_context")
517 )
519 def get_sampleaction_positions(
520 self,
521 sampleactionpositionid=None,
522 sampleactionid=None,
523 type=None,
524 no_context=None,
525 ):
526 with self.session_scope() as ses:
527 sampleactionspositions = (
528 ses.query(
529 self.RobotActionPosition.robotactionpositionid.label(
530 "sampleactionpositionid"
531 ),
532 self.RobotActionPosition.type,
533 self.RobotActionPosition.id,
534 self.RobotActionPosition.posx,
535 self.RobotActionPosition.posy,
536 )
537 .join(
538 self.RobotAction,
539 self.RobotAction.robotactionid
540 == self.RobotActionPosition.robotactionid,
541 )
542 .group_by(self.RobotActionPosition.robotactionpositionid)
543 )
545 if not no_context:
546 sampleactionspositions = sampleactionspositions.filter(
547 self.RobotAction.blsessionid == g.blsession.get("sessionid")
548 )
550 if sampleactionid:
551 sampleactionspositions = sampleactionspositions.filter(
552 self.RobotActionPosition.robotactionid == sampleactionid
553 )
555 if type:
556 sampleactionspositions = sampleactionspositions.filter(
557 self.RobotActionPosition.type == type
558 )
560 if sampleactionpositionid:
561 sampleactionspositions = sampleactionspositions.filter(
562 self.RobotActionPosition.robotactionpositionid
563 == sampleactionpositionid
564 )
565 sampleactionspositions = sampleactionspositions.first()
566 if sampleactionspositions:
567 return sampleactionspositions._asdict()
569 else:
570 sampleactionspositions = [
571 r._asdict() for r in sampleactionspositions.all()
572 ]
573 return {
574 "total": len(sampleactionspositions),
575 "rows": sampleactionspositions,
576 }
578 def add_sampleaction_position(self, *, sampleactionid, posx, posy, type, id):
579 sampleaction = self.get_sampleactions(sampleactionid=sampleactionid)
580 if not sampleaction:
581 return
583 with self.session_scope() as ses:
584 sampleactionposition = self.RobotActionPosition(
585 robotactionid=sampleactionid,
586 posx=posx,
587 posy=posy,
588 type=type,
589 id=id,
590 )
591 ses.add(sampleactionposition)
592 ses.commit()
594 return self.get_sampleaction_positions(
595 sampleactionpositionid=sampleactionposition.robotactionpositionid
596 )
598 def remove_sampleaction_position(self, sampleactionpositionid, **kargs) -> bool:
599 with self.session_scope() as ses:
600 chk = self.get_sampleaction_positions(
601 sampleactionpositionid=sampleactionpositionid
602 )
603 if chk:
604 sampleactionposition = (
605 ses.query(self.RobotActionPosition)
606 .filter(
607 self.RobotActionPosition.robotactionpositionid
608 == sampleactionpositionid
609 )
610 .first()
611 )
613 ses.delete(sampleactionposition)
614 ses.commit()
616 return True
618 return False
620 def get_scanqualityindicators(self, **kwargs):
621 with self.session_scope() as ses:
622 sqis = (
623 ses.query(
624 self.ImageQualityIndicators.imagenumber.label("point"),
625 self.ImageQualityIndicators.totalintegratedsignal.label("total"),
626 self.ImageQualityIndicators.spottotal.label("spots"),
627 self.ImageQualityIndicators.autoprocprogramid,
628 )
629 .join(
630 self.DataCollection,
631 self.DataCollection.datacollectionid
632 == self.ImageQualityIndicators.datacollectionid,
633 )
634 .join(self.DataCollectionGroup)
635 )
637 if not kwargs.get("no_context"):
638 sqis = sqis.filter(
639 self.DataCollectionGroup.sessionid == g.blsession.get("sessionid")
640 )
642 sqis = sqis.filter(
643 self.DataCollection.datacollectionid == kwargs.get("datacollectionid")
644 )
646 sqis = sqis.order_by(self.ImageQualityIndicators.imagenumber)
648 data = {}
649 for sqi in sqis.all():
650 row = sqi._asdict()
651 for k in ["point", "total", "spots", "autoprocprogramid"]:
652 if k not in data:
653 data[k] = []
655 data[k].append(row[k])
657 return data
659 def add_scanqualityindicators(self, **kwargs):
660 with self.session_scope() as ses:
661 dc = self.get_datacollections(
662 datacollectionid=kwargs["datacollectionid"],
663 no_context=kwargs.get("no_context"),
664 )
666 if dc:
667 args = {}
668 for key in ["total", "spots"]:
669 args[key] = None
670 if kwargs.get(key) is not None:
671 args[key] = float(kwargs[key])
673 sqi = self.ImageQualityIndicators(
674 datacollectionid=kwargs["datacollectionid"],
675 imagenumber=kwargs["point"],
676 totalintegratedsignal=args["total"],
677 spottotal=args["spots"],
678 )
680 ses.add(sqi)
681 ses.commit()
683 return f"{sqi.datacollectionid}-{sqi.imagenumber}"
685 def get_datacollectionplans(
686 self,
687 datacollectionplanid=None,
688 blsampleid=None,
689 status=None,
690 queued=None,
691 no_context=False,
692 **kwargs,
693 ):
694 with self.session_scope() as ses:
695 datacollectionplans = (
696 ses.query(
697 self.DiffractionPlan.diffractionplanid.label(
698 "datacollectionplanid"
699 ),
700 self.DiffractionPlan.scanparameters,
701 self.DiffractionPlan.experimentkind,
702 self.DiffractionPlan.recordtimestamp.label("timestamp"),
703 self.DiffractionPlan.energy,
704 self.DiffractionPlan.exposuretime,
705 self.BLSample.blsampleid.label("sampleid"),
706 self.BLSubSample.blsubsampleid.label("subsampleid"),
707 self.BLSample.name.label("sample"),
708 self.Protein.acronym.label("component"),
709 self.BLSample_has_DataCollectionPlan.planorder,
710 self.DataCollection.datacollectionid,
711 self.ContainerQueueSample.containerqueuesampleid,
712 func.IF(
713 self.DataCollection.datacollectionid, "executed", "pending"
714 ).label("status"),
715 func.IF(
716 self.ContainerQueueSample.containerqueuesampleid, True, False
717 ).label("queued"),
718 func.IF(
719 self.BLSample_has_DataCollectionPlan.blsampleid,
720 True,
721 False,
722 ).label("linked"),
723 )
724 .outerjoin(
725 self.BLSample_has_DataCollectionPlan,
726 self.DiffractionPlan.diffractionplanid
727 == self.BLSample_has_DataCollectionPlan.datacollectionplanid,
728 )
729 .outerjoin(
730 self.ContainerQueueSample,
731 self.ContainerQueueSample.datacollectionplanid
732 == self.DiffractionPlan.diffractionplanid,
733 )
734 .outerjoin(
735 self.BLSubSample,
736 self.BLSubSample.blsubsampleid
737 == self.ContainerQueueSample.blsubsampleid,
738 )
739 .outerjoin(
740 self.BLSample,
741 or_(
742 self.BLSample.blsampleid
743 == self.BLSample_has_DataCollectionPlan.blsampleid,
744 self.BLSample.blsampleid
745 == self.ContainerQueueSample.blsampleid,
746 self.BLSample.blsampleid == self.BLSubSample.blsampleid,
747 ),
748 )
749 .outerjoin(
750 self.Crystal, self.Crystal.crystalid == self.BLSample.crystalid
751 )
752 .outerjoin(
753 self.Protein, self.Crystal.proteinid == self.Protein.proteinid
754 )
755 .outerjoin(
756 self.DataCollection,
757 self.DataCollection.datacollectionplanid
758 == self.DiffractionPlan.diffractionplanid,
759 )
760 )
762 if not no_context:
763 datacollectionplans = datacollectionplans.filter(
764 self.Protein.proposalid == g.blsession.get("proposalid")
765 )
767 if blsampleid:
768 datacollectionplans = datacollectionplans.filter(
769 self.BLSample_has_DataCollectionPlan.blsampleid == blsampleid
770 )
772 if status:
773 if status == "executed":
774 datacollectionplans = datacollectionplans.filter(
775 self.DataCollection.datacollectionid != None # noqa: E711
776 )
777 else:
778 datacollectionplans = datacollectionplans.filter(
779 self.DataCollection.datacollectionid == None # noqa: E711
780 )
782 if queued:
783 datacollectionplans = datacollectionplans.filter(
784 self.ContainerQueueSample.containerqueuesampleid
785 != None # noqa: E711
786 )
788 if datacollectionplanid:
789 datacollectionplans = datacollectionplans.filter(
790 self.DiffractionPlan.diffractionplanid == datacollectionplanid
791 )
792 datacollectionplan = datacollectionplans.first()
793 if datacollectionplan:
794 return self._decode_scanparameters(datacollectionplan._asdict())
796 else:
797 datacollectionplans = order(
798 datacollectionplans,
799 {
800 "sampleid": self.BLSample.blsampleid,
801 "planorder": self.BLSample_has_DataCollectionPlan.planorder,
802 "datacollectionplanid": self.DiffractionPlan.diffractionplanid,
803 },
804 default=["datacollectionplanid", "desc"],
805 **kwargs,
806 )
808 datacollectionplans = [
809 self._decode_scanparameters(r._asdict())
810 for r in datacollectionplans.all()
811 ]
812 return {"total": len(datacollectionplans), "rows": datacollectionplans}
814 def _decode_scanparameters(self, datacollectionplan):
815 if datacollectionplan["scanparameters"]:
816 datacollectionplan["scanparameters"] = json.loads(
817 datacollectionplan["scanparameters"]
818 )
819 return datacollectionplan
821 def add_datacollectionplan(
822 self,
823 *,
824 scanparameters,
825 sampleid=None,
826 energy=None,
827 exposuretime=None,
828 experimentkind=None,
829 planorder=None,
830 no_context=False,
831 ):
832 with self.session_scope() as ses:
833 datacollectionplan = self.DiffractionPlan(
834 scanparameters=json.dumps(scanparameters),
835 experimentkind=experimentkind,
836 energy=energy,
837 exposuretime=exposuretime,
838 )
840 ses.add(datacollectionplan)
841 ses.commit()
843 if sampleid:
844 sample_has_datacollectionplan = self.BLSample_has_DataCollectionPlan(
845 blsampleid=sampleid,
846 datacollectionplanid=datacollectionplan.diffractionplanid,
847 planorder=planorder,
848 )
850 ses.add(sample_has_datacollectionplan)
851 ses.commit()
853 return self.get_datacollectionplans(
854 datacollectionplanid=datacollectionplan.diffractionplanid,
855 no_context=no_context,
856 )
858 def update_datacollectionplan(
859 self, datacollectionplanid, no_context=False, **kwargs
860 ):
861 with self.session_scope() as ses:
862 chk = self.get_datacollectionplans(
863 datacollectionplanid=datacollectionplanid,
864 no_context=kwargs.get("no_context"),
865 )
866 if chk:
867 datacollectionplan = (
868 ses.query(self.DiffractionPlan)
869 .filter(
870 self.DiffractionPlan.diffractionplanid == datacollectionplanid
871 )
872 .first()
873 )
875 updatable = [
876 "scanparameters",
877 "experimentkind",
878 "exposuretime",
879 "energy",
880 ]
881 for kw in kwargs:
882 if kw in updatable:
883 val = kwargs[kw]
885 if kw == "scanparameters":
886 val = json.dumps(val)
888 setattr(datacollectionplan, kw, val)
890 sample_has_datacollectionplan = (
891 ses.query(self.BLSample_has_DataCollectionPlan)
892 .filter(
893 self.BLSample_has_DataCollectionPlan.datacollectionplanid
894 == datacollectionplanid,
895 )
896 .first()
897 )
899 updatable_in_sample = ["planorder"]
900 for kw in kwargs:
901 if kw in updatable_in_sample:
902 val = kwargs[kw]
904 setattr(sample_has_datacollectionplan, kw, val)
906 ses.commit()
908 return self.get_datacollectionplans(
909 datacollectionplanid=datacollectionplanid, no_context=no_context
910 )
912 def remove_datacollectionplan(self, datacollectionplanid, **kwargs):
913 with self.session_scope() as ses:
914 chk = self.get_datacollectionplans(
915 datacollectionplanid=datacollectionplanid,
916 no_context=kwargs.get("no_context"),
917 )
919 if chk:
920 if chk["datacollectionid"]:
921 raise RuntimeError(
922 "Data collection plan has been executed, it cannot be deleted"
923 )
925 if chk["queued"]:
926 raise RuntimeError(
927 "Data collection plan has been queued, it cannot be deleted without being unqueued"
928 )
930 dp = (
931 ses.query(
932 self.DiffractionPlan,
933 )
934 .filter(
935 self.DiffractionPlan.diffractionplanid == datacollectionplanid,
936 )
937 .first()
938 )
940 sample_has_datacollectionplan = (
941 ses.query(self.BLSample_has_DataCollectionPlan)
942 .filter(
943 self.BLSample_has_DataCollectionPlan.datacollectionplanid
944 == datacollectionplanid
945 )
946 .first()
947 )
949 if sample_has_datacollectionplan:
950 ses.delete(sample_has_datacollectionplan)
951 ses.commit()
953 ses.delete(dp)
954 ses.commit()
956 return True