diff --git a/src/PKSim.Core/Model/SimulationFactory.cs b/src/PKSim.Core/Model/SimulationFactory.cs index 0c8f5cae8..8f84597e7 100644 --- a/src/PKSim.Core/Model/SimulationFactory.cs +++ b/src/PKSim.Core/Model/SimulationFactory.cs @@ -109,6 +109,7 @@ public Simulation CreateFrom(ISimulationSubject simulationSubject, IReadOnlyList _simulationBuildingBlockUpdater.UpdateUsedBuildingBlockInSimulationFromTemplate(simulation, simulationSubject, PKSimBuildingBlockType.SimulationSubject); _simulationBuildingBlockUpdater.UpdateMultipleUsedBuildingBlockInSimulationFromTemplate(simulation, compounds, PKSimBuildingBlockType.Compound); + _simulationBuildingBlockUpdater.UpdateMultipleUsedBuildingBlockInSimulationFromTemplate(simulation, simulationSubject.AllExpressionProfiles(), PKSimBuildingBlockType.ExpressionProfile); //set basic properties if (originalSimulation != null) diff --git a/src/PKSim.Core/Services/BuildingBlockParametersToSimulationUpdater.cs b/src/PKSim.Core/Services/BuildingBlockParametersToSimulationUpdater.cs index 51b6dc27d..bc22207bd 100644 --- a/src/PKSim.Core/Services/BuildingBlockParametersToSimulationUpdater.cs +++ b/src/PKSim.Core/Services/BuildingBlockParametersToSimulationUpdater.cs @@ -1,19 +1,20 @@ using System.Collections.Generic; using System.Linq; -using PKSim.Assets; using OSPSuite.Core.Commands.Core; +using OSPSuite.Core.Domain; +using OSPSuite.Core.Domain.Services; +using OSPSuite.Core.Events; using OSPSuite.Utility.Collections; +using PKSim.Assets; using PKSim.Core.Commands; using PKSim.Core.Model; -using OSPSuite.Core.Domain; -using OSPSuite.Core.Domain.Services; namespace PKSim.Core.Services { public interface IBuildingBlockParametersToSimulationUpdater { /// - /// Updates the parameter values into the building block given as parameter in the simulation + /// Updates the parameter values from the building block given as parameter into the simulation /// /// Template building block containing the original values /// Simulation whose parameter will be updated @@ -25,12 +26,18 @@ public class BuildingBlockParametersToSimulationUpdater : IBuildingBlockParamete private readonly IExecutionContext _executionContext; private readonly IContainerTask _containerTask; private readonly IParameterSetUpdater _parameterSetUpdater; + private readonly IExpressionProfileUpdater _expressionProfileUpdater; - public BuildingBlockParametersToSimulationUpdater(IExecutionContext executionContext, IContainerTask containerTask, IParameterSetUpdater parameterSetUpdater) + public BuildingBlockParametersToSimulationUpdater( + IExecutionContext executionContext, + IContainerTask containerTask, + IParameterSetUpdater parameterSetUpdater, + IExpressionProfileUpdater expressionProfileUpdater) { _executionContext = executionContext; _containerTask = containerTask; _parameterSetUpdater = parameterSetUpdater; + _expressionProfileUpdater = expressionProfileUpdater; } public ICommand UpdateParametersFromBuildingBlockInSimulation(IPKSimBuildingBlock templateBuildingBlock, Simulation simulation) @@ -38,7 +45,7 @@ public ICommand UpdateParametersFromBuildingBlockInSimulation(IPKSimBuildingBloc //Update the building block in the simulation based on the same template var usedBuildingBlock = simulation.UsedBuildingBlockByTemplateId(templateBuildingBlock.Id); //Template was not used in the simulation...return - if (usedBuildingBlock == null) + if (usedBuildingBlock == null) return null; var buildingBlockType = _executionContext.TypeFor(templateBuildingBlock); @@ -65,9 +72,28 @@ public ICommand UpdateParametersFromBuildingBlockInSimulation(IPKSimBuildingBloc updateCommands.CommandType = PKSimConstants.Command.CommandTypeUpdate; updateCommands.Description = PKSimConstants.Command.UpdateBuildingBlockCommandDescription(buildingBlockType, templateBuildingBlock.Name, simulation.Name); _executionContext.UpdateBuildingBlockPropertiesInCommand(updateCommands, simulation); + + synchronizeBuildingBlocks(templateBuildingBlock, simulation); return updateCommands; } + /// + /// We need to make sure that once the simulation has been updated with the building block, depending building blocks + /// are also updated + /// For instance, if we update the individual in the simulation, we will also update all expression profile (since + /// expression profile are linked to the individual) + /// + private void synchronizeBuildingBlocks(IPKSimBuildingBlock templateBuildingBlock, Simulation simulation) + { + if (templateBuildingBlock is not ISimulationSubject simulationSubject) + return; + + _expressionProfileUpdater.SynchronizeExpressionProfilesUsedInSimulationSubjectWithSimulation(simulationSubject, simulation); + + //we need to raise an event here to ensure that the UI reflects the fact that we have synchronized our building blocks + _executionContext.PublishEvent(new SimulationStatusChangedEvent(simulation)); + } + /// /// Update parameter values from the used building block into the simulation /// @@ -88,9 +114,9 @@ private IEnumerable updateParameterValues(IEnumerable used } return from parameter in usedBuildingBlockParameters.OrderBy(x => x.IsDistributed()) - let simParams = simulationParameterCache[parameter.Id] - from simParam in simParams - select _parameterSetUpdater.UpdateValue(parameter, simParam); + let simParams = simulationParameterCache[parameter.Id] + from simParam in simParams + select _parameterSetUpdater.UpdateValue(parameter, simParam); } private ICommand updateParameterValues(PathCache sourceParameters, PathCache targetParameters) @@ -99,6 +125,5 @@ private ICommand updateParameterValues(PathCache sourceParameters, P } private PathCache parametersToUpdateFrom(IPKSimBuildingBlock buildingBlock) => _containerTask.CacheAllChildren(buildingBlock); - } } \ No newline at end of file diff --git a/src/PKSim.Core/Services/ExpressionProfileUpdater.cs b/src/PKSim.Core/Services/ExpressionProfileUpdater.cs index 5912524ed..658191d5f 100644 --- a/src/PKSim.Core/Services/ExpressionProfileUpdater.cs +++ b/src/PKSim.Core/Services/ExpressionProfileUpdater.cs @@ -53,6 +53,19 @@ public interface IExpressionProfileUpdater /// Expression profile to update used as source /// Expression profile to update void SynchronizeExpressionProfileWithExpressionProfile(ExpressionProfile sourceExpressionProfile, ExpressionProfile targetExpressionProfile); + + /// + /// Updates the values from all expression profiles used by the into the + /// + /// This is required for instance when synchronizing and individual with a simulation=>Underlying building block may + /// need to be updated as well + /// + /// + /// Template simulation subject (building block) that should be used to update the + /// expression profile in the simulation + /// + /// Simulation to update + void SynchronizeExpressionProfilesUsedInSimulationSubjectWithSimulation(ISimulationSubject templateSimulationSubject, Simulation simulation); } public class ExpressionProfileUpdater : IExpressionProfileUpdater @@ -170,6 +183,21 @@ public void SynchronizeExpressionProfileWithExpressionProfile(ExpressionProfile synchronizeExpressionProfiles(sourceMolecule, sourceIndividual, targetMolecule, targetIndividual, updateParameterOriginId: false); } + public void SynchronizeExpressionProfilesUsedInSimulationSubjectWithSimulation(ISimulationSubject templateSimulationSubject, Simulation simulation) + { + templateSimulationSubject.AllExpressionProfiles().Each(template => + { + var usedBuildingBlock = simulation.UsedBuildingBlockByTemplateId(template.Id); + if (usedBuildingBlock?.BuildingBlock is not ExpressionProfile simulationExpressionProfile) + return; + + SynchronizeExpressionProfileWithExpressionProfile(template, simulationExpressionProfile); + //They are supposed to be the same => same version + simulationExpressionProfile.Version = template.Version; + usedBuildingBlock.Version = template.Version; + }); + } + private void updateMoleculeParameters(IndividualMolecule sourceMolecule, ISimulationSubject sourceSimulationSubject, IndividualMolecule targetMolecule, ISimulationSubject targetSimulationSubject, bool updateParameterOriginId) { var allTargetMoleculeParameters = allMoleculeParametersFor(targetSimulationSubject, targetMolecule); diff --git a/src/PKSim.Core/Services/SimulationParametersToBuildingBlockUpdater.cs b/src/PKSim.Core/Services/SimulationParametersToBuildingBlockUpdater.cs index c7206ae7e..e5fcdb0ee 100644 --- a/src/PKSim.Core/Services/SimulationParametersToBuildingBlockUpdater.cs +++ b/src/PKSim.Core/Services/SimulationParametersToBuildingBlockUpdater.cs @@ -69,7 +69,7 @@ public ICommand UpdateParametersFromSimulationInBuildingBlock(Simulation simulat updateCommands.Add(updateTemplateParametersCommand); //Last, see if we have some special cases to handle - var synchronizeCommand = synchronizeBuildingBlocks(templateBuildingBlock, updateTemplateParametersCommand); + var synchronizeCommand = synchronizeBuildingBlocks(templateBuildingBlock, updateTemplateParametersCommand, simulation); updateCommands.Add(synchronizeCommand); //now make sure that the used building block is updated with the template building block info @@ -79,11 +79,10 @@ public ICommand UpdateParametersFromSimulationInBuildingBlock(Simulation simulat return updateCommands; } - private ICommand synchronizeBuildingBlocks(IPKSimBuildingBlock templateBuildingBlock, IPKSimMacroCommand updateTemplateParametersCommand) + private ICommand synchronizeBuildingBlocks(IPKSimBuildingBlock templateBuildingBlock, IPKSimMacroCommand updateTemplateParametersCommand, Simulation simulation) { - var simulationSubject = templateBuildingBlock as ISimulationSubject; //For now, deal with update from Individual or Population into Expression Profile - if (simulationSubject == null) + if (templateBuildingBlock is not ISimulationSubject simulationSubject) return new PKSimEmptyCommand(); var allExpressionProfileParameterValueCommand = updateTemplateParametersCommand.All() @@ -126,6 +125,8 @@ private ICommand synchronizeBuildingBlocks(IPKSimBuildingBlock templateBuildingB //Now that our expression profile are updated, we need to trigger the synchronization in all building blocks expressionProfilesToUpdate.Each(x => _expressionProfileUpdater.SynchronizeAllSimulationSubjectsWithExpressionProfile(x)); + //last, synchronize the expression profile in the simulation as well + _expressionProfileUpdater.SynchronizeExpressionProfilesUsedInSimulationSubjectWithSimulation(simulationSubject, simulation); return macroCommand; } diff --git a/src/PKSim.Infrastructure/Services/LazyLoadTask.cs b/src/PKSim.Infrastructure/Services/LazyLoadTask.cs index 5c4abf1cf..462ac7dcd 100644 --- a/src/PKSim.Infrastructure/Services/LazyLoadTask.cs +++ b/src/PKSim.Infrastructure/Services/LazyLoadTask.cs @@ -1,11 +1,11 @@ -using PKSim.Assets; +using OSPSuite.Core.Domain; +using OSPSuite.Core.Domain.ParameterIdentifications; +using OSPSuite.Core.Domain.SensitivityAnalyses; using OSPSuite.Utility.Events; using OSPSuite.Utility.Extensions; +using PKSim.Assets; using PKSim.Core.Model; using PKSim.Core.Services; -using OSPSuite.Core.Domain; -using OSPSuite.Core.Domain.ParameterIdentifications; -using OSPSuite.Core.Domain.SensitivityAnalyses; namespace PKSim.Infrastructure.Services { @@ -22,12 +22,12 @@ public class LazyLoadTask : ILazyLoadTask private readonly ISensitivityAnalysisContentLoader _sensitivityAnalysisContentLoader; public LazyLoadTask( - IContentLoader contentLoader, - ISimulationResultsLoader simulationResultsLoader, + IContentLoader contentLoader, + ISimulationResultsLoader simulationResultsLoader, ISimulationChartsLoader simulationChartsLoader, - ISimulationComparisonContentLoader simulationComparisonContentLoader, + ISimulationComparisonContentLoader simulationComparisonContentLoader, ISimulationAnalysesLoader simulationAnalysesLoader, - IParameterIdentificationContentLoader parameterIdentificationContentLoader, + IParameterIdentificationContentLoader parameterIdentificationContentLoader, ISensitivityAnalysisContentLoader sensitivityAnalysisContentLoader, IRegistrationTask registrationTask, IProgressManager progressManager) @@ -69,7 +69,7 @@ public void LoadResults(TSimulation simulation) where TSimulation : { if (simulation == null) return; - + Load(simulation); if (simulation.HasResults) @@ -113,7 +113,7 @@ private void loadSimulations(Simulation simulation) //updating results may triggered update of has changed flag that is not accurate. We save the original state and update it at the end var hasChanged = simulation.HasChanged; - + //Only load results for individual simulations if (simulation.IsAnImplementationOf()) _simulationResultsLoader.LoadResultsFor(simulation.DowncastTo()); @@ -121,6 +121,13 @@ private void loadSimulations(Simulation simulation) else if (simulation.IsAnImplementationOf()) _simulationAnalysesLoader.LoadAnalysesFor(simulation.DowncastTo()); + //make sure each individual gets the expression profile defined in the simulation) + var simulationSubject = simulation.BuildingBlock(); + + //this can happen for an imported simulation + if (simulationSubject != null) + simulation.AllBuildingBlocks().Each(simulationSubject.AddExpressionProfile); + //in all cases, load the charts _simulationChartsLoader.LoadChartsFor(simulation); diff --git a/src/PKSim.Presentation/Presenters/ContextMenus/UsedBuildingBlockInSimulationTreeNodeContextMenuFactory.cs b/src/PKSim.Presentation/Presenters/ContextMenus/UsedBuildingBlockInSimulationTreeNodeContextMenuFactory.cs index 5d75f3290..476550eca 100644 --- a/src/PKSim.Presentation/Presenters/ContextMenus/UsedBuildingBlockInSimulationTreeNodeContextMenuFactory.cs +++ b/src/PKSim.Presentation/Presenters/ContextMenus/UsedBuildingBlockInSimulationTreeNodeContextMenuFactory.cs @@ -45,6 +45,19 @@ protected override IContextMenu CreateFor(Simulation simulation, UsedBuildingBlo } } + + public class UsedExpressionProfileInSimulationTreeNodeContextMenuFactory : UsedBuildingBlockInSimulationTreeNodeContextMenuFactory + { + public UsedExpressionProfileInSimulationTreeNodeContextMenuFactory(IContainer container) : base(container) + { + } + + protected override IContextMenu CreateFor(Simulation simulation, UsedBuildingBlock usedBuildingBlock, ExpressionProfile expressionProfile) + { + return new UsedBuildingBlockInSimulationContextMenu(simulation, usedBuildingBlock, expressionProfile, _container); + } + } + public class UsedCompoundInSimulationTreeNodeContextMenuFactory : UsedBuildingBlockInSimulationTreeNodeContextMenuFactory { public UsedCompoundInSimulationTreeNodeContextMenuFactory(IContainer container) : base(container) diff --git a/src/PKSim.Presentation/Presenters/Main/SimulationExplorerPresenter.cs b/src/PKSim.Presentation/Presenters/Main/SimulationExplorerPresenter.cs index 2549bfc6c..bce4b888e 100644 --- a/src/PKSim.Presentation/Presenters/Main/SimulationExplorerPresenter.cs +++ b/src/PKSim.Presentation/Presenters/Main/SimulationExplorerPresenter.cs @@ -184,6 +184,7 @@ private void addUsedBuildingBlockNodes(Simulation simulation, ITreeNode simulati .Under(simulationNode); addUsedBuildingBlock(simulation, simulationNode, PKSimBuildingBlockType.SimulationSubject); + //Used for debug purposes for now addUsedBuildingBlock(simulation, simulationNode, PKSimBuildingBlockType.ExpressionProfile); addUsedBuildingBlock(simulation, simulationNode, PKSimBuildingBlockType.Compound); addUsedBuildingBlock(simulation, simulationNode, PKSimBuildingBlockType.Protocol); addUsedBuildingBlock(simulation, simulationNode, PKSimBuildingBlockType.Formulation); diff --git a/src/PKSim.Presentation/Presenters/Simulations/SimulationWizardPresenter.cs b/src/PKSim.Presentation/Presenters/Simulations/SimulationWizardPresenter.cs index bb0f9176d..2fcfb826d 100644 --- a/src/PKSim.Presentation/Presenters/Simulations/SimulationWizardPresenter.cs +++ b/src/PKSim.Presentation/Presenters/Simulations/SimulationWizardPresenter.cs @@ -35,6 +35,7 @@ protected SimulationWizardPresenter(TView view, ISubPresenterItemManager(); _simulationComparisonContentLoader = A.Fake(); _simulationAnalysesLoader = A.Fake(); - _parameterIdentificationContentendLoader = A.Fake(); + _parameterIdentificationContentLoader = A.Fake(); _sensitivityAnalysisContentLoader = A.Fake(); A.CallTo(() => _progressManager.Create()).Returns(_progressUpdater); sut = new LazyLoadTask(_contentLoader, _simulationResultsLoader, _simulationChartsLoader, - _simulationComparisonContentLoader, _simulationAnalysesLoader, _parameterIdentificationContentendLoader, _sensitivityAnalysisContentLoader, + _simulationComparisonContentLoader, _simulationAnalysesLoader, _parameterIdentificationContentLoader, _sensitivityAnalysisContentLoader, _registrationTask, _progressManager); _objectToLoad = A.Fake(); _objectToLoad.Id = "objectId"; @@ -141,11 +142,29 @@ public void should_register_the_object_in_the_factory() public class When_loading_an_individual_simulation : concern_for_LazyLoadTask { private IndividualSimulation _individualSimulation; + private Individual _individual; + private ExpressionProfile _exp1; + private ExpressionProfile _exp2; protected override void Context() { base.Context(); - _individualSimulation = A.Fake(); + _individualSimulation = new IndividualSimulation(); + _individual = new Individual(); + _exp1 = new ExpressionProfile(); + _exp2 = new ExpressionProfile(); + _individualSimulation.AddUsedBuildingBlock(new UsedBuildingBlock("ind", PKSimBuildingBlockType.Individual) + { + BuildingBlock = _individual + }); + _individualSimulation.AddUsedBuildingBlock(new UsedBuildingBlock("exp1", PKSimBuildingBlockType.ExpressionProfile) + { + BuildingBlock = _exp1 + }); + _individualSimulation.AddUsedBuildingBlock(new UsedBuildingBlock("exp2", PKSimBuildingBlockType.ExpressionProfile) + { + BuildingBlock = _exp2 + }); } protected override void Because() @@ -158,6 +177,12 @@ public void should_also_load_the_simulation_results() { A.CallTo(() => _simulationResultsLoader.LoadResultsFor(_individualSimulation)).MustHaveHappened(); } + + [Observation] + public void should_add_all_expression_profiles_defined_as_used_building_block_as_building_block_of_the_individual() + { + _individual.AllExpressionProfiles().ShouldOnlyContain(_exp1, _exp2); + } } public class When_loading_a_population_simulation : concern_for_LazyLoadTask diff --git a/tests/PKSim.Tests/IntegrationTests/BuildingBlockParametersToSimulationUpdaterSpecs.cs b/tests/PKSim.Tests/IntegrationTests/BuildingBlockParametersToSimulationUpdaterSpecs.cs index 53b9cf4f1..79f3e1119 100644 --- a/tests/PKSim.Tests/IntegrationTests/BuildingBlockParametersToSimulationUpdaterSpecs.cs +++ b/tests/PKSim.Tests/IntegrationTests/BuildingBlockParametersToSimulationUpdaterSpecs.cs @@ -15,11 +15,19 @@ public abstract class concern_for_BuildingBlockParametersToSimulationUpdater : C { protected Individual _templateIndividual; private ICoreWorkspace _workspace; + protected ExpressionProfile _templateExpressionProfile; + private IMoleculeExpressionTask _moleculeExpressionTask; public override void GlobalContext() { base.GlobalContext(); + _moleculeExpressionTask = IoC.Resolve>(); + _templateIndividual = DomainFactoryForSpecs.CreateStandardIndividual(); + _templateExpressionProfile = DomainFactoryForSpecs.CreateExpressionProfile(); + _moleculeExpressionTask.AddExpressionProfile(_templateIndividual, _templateExpressionProfile); + + var compound = DomainFactoryForSpecs.CreateStandardCompound(); var protocol = DomainFactoryForSpecs.CreateStandardIVBolusProtocol(); _simulation = DomainFactoryForSpecs.CreateSimulationWith(_templateIndividual, compound, protocol) as IndividualSimulation; @@ -29,6 +37,7 @@ public override void GlobalContext() project.AddBuildingBlock(protocol); project.AddBuildingBlock(_simulation); project.AddBuildingBlock(_templateIndividual); + project.AddBuildingBlock(_templateExpressionProfile); _workspace.Project = project; } } @@ -42,6 +51,9 @@ public override void GlobalContext() base.GlobalContext(); var templateParameter = _templateIndividual.Organism.Organ(CoreConstants.Organ.LIVER).Parameter(CoreConstants.Parameters.ALLOMETRIC_SCALE_FACTOR); templateParameter.Value = 3; + + var templateExpressionProfileParameter = _templateExpressionProfile.Molecule.HalfLifeLiver; + templateExpressionProfileParameter.Value = 5; } protected override void Because() @@ -59,6 +71,15 @@ public void should_have_updated_the_parameter_values_in_the_simulation_and_in_th //now parameter in simulation var simParameter = _simulation.All().First(x => string.Equals(x.Origin.ParameterId, parameter.Id)); simParameter.Value.ShouldBeEqualTo(3); + + } + + [Observation] + public void should_have_synchronized_value_in_the_expression_profile() + { + var simExpressionProfile = _simulation.BuildingBlockByTemplateId(_templateExpressionProfile.Id); + var parameter = simExpressionProfile.Molecule.HalfLifeLiver; + parameter.Value.ShouldBeEqualTo(5); } [Observation] diff --git a/tests/PKSim.Tests/IntegrationTests/ExpressionProfileUpdaterSpecs.cs b/tests/PKSim.Tests/IntegrationTests/ExpressionProfileUpdaterSpecs.cs index c21260fef..59390810c 100644 --- a/tests/PKSim.Tests/IntegrationTests/ExpressionProfileUpdaterSpecs.cs +++ b/tests/PKSim.Tests/IntegrationTests/ExpressionProfileUpdaterSpecs.cs @@ -155,4 +155,57 @@ public void should_synchronize_transporter_direction() _individualTransporter.BloodCellsContainer.TransportDirection.ShouldBeEqualTo(TransportDirectionId.EffluxBloodCellsToPlasma); } } + + public class When_synchronizing_all_expression_profile_used_in_a_simulation_subject_with_a_simulation : concern_for_ExpressionProfileUpdater + { + private Simulation _simulation; + private Individual _individualInSimulation; + private ExpressionProfile _expressionProfileForEnzymeInSimulation; + private IndividualEnzyme _expressionProfileEnzymeInSimulation; + private UsedBuildingBlock _usedIndividualBuildingBLock; + private UsedBuildingBlock _usedExpressionProfileBuildingBlock; + + protected override void Context() + { + base.Context(); + _simulation = new IndividualSimulation(); + + _individualInSimulation = DomainFactoryForSpecs.CreateStandardIndividual(); + _expressionProfileForEnzymeInSimulation = DomainFactoryForSpecs.CreateExpressionProfile(); + _moleculeExpressionTask.AddExpressionProfile(_individualInSimulation, _expressionProfileForEnzymeInSimulation); + _expressionProfileEnzymeInSimulation = _expressionProfileForEnzymeInSimulation.Molecule.DowncastTo(); + _usedIndividualBuildingBLock = new UsedBuildingBlock(_individual.Id, PKSimBuildingBlockType.Individual) + { + BuildingBlock = _individualInSimulation + }; + _usedExpressionProfileBuildingBlock = new UsedBuildingBlock(_expressionProfileForEnzyme.Id, PKSimBuildingBlockType.ExpressionProfile) + { + BuildingBlock = _expressionProfileForEnzymeInSimulation + }; + + _simulation.AddUsedBuildingBlock(_usedIndividualBuildingBLock); + _simulation.AddUsedBuildingBlock(_usedExpressionProfileBuildingBlock); + + _expressionProfileForEnzyme.Version = 10; + _expressionProfileEnzyme.HalfLifeLiver.Value = 50; + + } + protected override void Because() + { + sut.SynchronizeExpressionProfilesUsedInSimulationSubjectWithSimulation(_individual, _simulation ); + } + + [Observation] + public void should_have_updated_all_values_of_the_expression_profiles_in_the_simulation_with_those_of_the_corresponding_template_expression_profile() + { + _expressionProfileEnzymeInSimulation.HalfLifeLiver.Value.ShouldBeEqualTo(50); + } + + [Observation] + public void should_have_updated_the_version_of_the_building_block_in_the_simulation_to_the_one_used_in_the_template() + { + _expressionProfileForEnzymeInSimulation.Version.ShouldBeEqualTo(_expressionProfileForEnzyme.Version); + _usedExpressionProfileBuildingBlock.Version.ShouldBeEqualTo(_expressionProfileForEnzyme.Version); + } + } } \ No newline at end of file