44import logging
55import subprocess # noqa: S404
66import uuid
7+ from datetime import UTC , datetime
78from enum import StrEnum
89from pathlib import Path
910from typing import Any , ClassVar , Literal
1516from pydantic import Field , NonNegativeFloat
1617
1718from obi_one .core .block import Block
19+ from obi_one .core .exception import OBIONEError
1820from obi_one .core .info import Info
1921from obi_one .core .scan_config import ScanConfig
2022from obi_one .core .single import SingleConfigMixin
@@ -405,17 +407,49 @@ def create_campaign_entity_with_config(
405407 output_root : Path ,
406408 multiple_value_parameters_dictionary : dict | None = None ,
407409 db_client : entitysdk .client .Client = None ,
408- ) -> None :
410+ ) -> entitysdk . models . IonChannelModelingCampaign :
409411 """Initializes the ion channel modeling campaign in the database."""
410- # TODO: and implement related entities on entitysdk
412+ L .info ("1. Initializing ion channel modeling campaign in the database..." )
413+ if multiple_value_parameters_dictionary is None :
414+ multiple_value_parameters_dictionary = {}
415+
416+ L .info ("-- Register IonChannelModelingCampaign Entity" )
417+ self ._campaign = db_client .register_entity (
418+ entitysdk .models .IonChannelModelingCampaign (
419+ name = self .info .campaign_name ,
420+ description = self .info .campaign_description ,
421+ input_recording_ids = [rec .id_str for rec in self .initialize .recordings ],
422+ scan_parameters = multiple_value_parameters_dictionary ,
423+ )
424+ )
425+
426+ L .info ("-- Upload campaign_generation_config" )
427+ _ = db_client .upload_file (
428+ entity_id = self ._campaign .id ,
429+ entity_type = entitysdk .models .IonChannelModelingCampaign ,
430+ file_path = output_root / "run_scan_config.json" ,
431+ file_content_type = "application/json" ,
432+ asset_label = "campaign_generation_config" ,
433+ )
434+
435+ return self ._campaign
411436
412437 def create_campaign_generation_entity (
413438 self ,
414- ion_channel_modelings : list ,
439+ ion_channel_modelings : list [ entitysdk . models . IonChannelModelingConfig ] ,
415440 db_client : entitysdk .client .Client ,
416441 ) -> None :
417442 """Register the activity generating the ion channel modeling tasks in the database."""
418- # TODO: also implement entitysdk related entities
443+ L .info ("3. Saving completed ion channel modeling campaign generation" )
444+
445+ L .info ("-- Register IonChannelModelingGeneration Entity" )
446+ db_client .register_entity (
447+ entitysdk .models .IonChannelModelingConfigGeneration (
448+ start_time = datetime .now (UTC ),
449+ used = [self ._campaign ],
450+ generated = ion_channel_modelings ,
451+ )
452+ )
419453
420454
421455class IonChannelFittingSingleConfig (IonChannelFittingScanConfig , SingleConfigMixin ):
@@ -429,11 +463,39 @@ def single_entity(self) -> Any:
429463
430464 def create_single_entity_with_config (
431465 self ,
432- campaign : Any ,
466+ campaign : entitysdk . models . IonChannelModelingCampaign ,
433467 db_client : entitysdk .client .Client ,
434- ) -> None :
468+ ) -> entitysdk . models . IonChannelModelingConfig :
435469 """Saves the simulation to the database."""
436- # TODO: also add related entities in entitysdk
470+ L .info (f"2.{ self .idx } Saving ion channel modeling config { self .idx } to database..." )
471+
472+ for recording in self .initialize .recordings :
473+ if not isinstance (recording , IonChannelRecordingFromID ):
474+ msg = (
475+ "IonChannelModeling can only be saved to entitycore if all input recordings "
476+ "are IonChannelRecordingFromID"
477+ )
478+ raise OBIONEError (msg )
479+
480+ L .info ("-- Register IonChannelModeling Entity" )
481+ self ._single_entity = db_client .register_entity (
482+ entitysdk .models .IonChannelModelingConfig (
483+ name = f"IonChannelModelingConfig { self .idx } " ,
484+ description = f"IonChannelModelingConfig { self .idx } " ,
485+ scan_parameters = self .single_coordinate_scan_params .dictionary_representaiton (),
486+ input_recording_ids = [rec .id_str for rec in self .initialize .recordings ],
487+ ion_channel_modeling_campaign_id = campaign .id ,
488+ )
489+ )
490+
491+ L .info ("-- Upload ion_channel_modeling_generation_config" )
492+ _ = db_client .upload_file (
493+ entity_id = self .single_entity .id ,
494+ entity_type = entitysdk .models .IonChannelModelingConfig ,
495+ file_path = Path (self .coordinate_output_root , "run_coordinate_instance.json" ),
496+ file_content_type = "application/json" ,
497+ asset_label = "ion_channel_modeling_generation_config" ,
498+ )
437499
438500
439501class IonChannelFittingTask (Task ):
@@ -573,8 +635,14 @@ def save(
573635 self .register_plots_and_json (db_client , figure_filepaths , model .id )
574636
575637 # register the Activity
576- L .info ("-- Register IonChannelExecution Entity" )
577- # TODO: re-implement this when entitysdk is ready
638+ L .info ("-- Register IonChannelModelingExecution Entity" )
639+ db_client .register_entity (
640+ entitysdk .models .IonChannelModelingExecution (
641+ start_time = datetime .now (UTC ),
642+ used = [self .config .single_entity ],
643+ generated = [model ],
644+ )
645+ )
578646
579647 return model .id
580648
0 commit comments