-
Notifications
You must be signed in to change notification settings - Fork 51
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fixes #2439 Misleading info in global POP PK Analysis if no parameter… #2459
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -27,9 +27,7 @@ | |
using static PKSim.Core.CoreConstants.PKAnalysis; | ||
using static PKSim.Core.CoreConstants.Species; | ||
using static PKSim.Core.CoreConstants.Units; | ||
using Compound = PKSim.Core.Model.Compound; | ||
using IParameterFactory = PKSim.Core.Model.IParameterFactory; | ||
using PKAnalysis = PKSim.Core.Model.PKAnalysis; | ||
|
||
namespace PKSim.Core.Services | ||
{ | ||
|
@@ -110,7 +108,7 @@ public PKAnalysesTask(ILazyLoadTask lazyLoadTask, | |
IStatisticalDataCalculator statisticalDataCalculator, | ||
IRepresentationInfoRepository representationInfoRepository, | ||
IParameterFactory parameterFactory, IProtocolToSchemaItemsMapper protocolToSchemaItemsMapper, IProtocolFactory protocolFactory, | ||
IGlobalPKAnalysisRunner globalPKAnalysisRunner, IVSSCalculator vssCalculator, IInteractionTask interactionTask, ICloner cloner, IEntityPathResolver entityPathResolver) : | ||
IGlobalPKAnalysisRunner globalPKAnalysisRunner, IVSSCalculator vssCalculator, IInteractionTask interactionTask, ICloner cloner, IEntityPathResolver entityPathResolver) : | ||
base(lazyLoadTask, pkValuesCalculator, pkParameterRepository, pkCalculationOptionsFactory) | ||
{ | ||
_lazyLoadTask = lazyLoadTask; | ||
|
@@ -145,10 +143,7 @@ public PopulationSimulationPKAnalyses CalculateFor(PopulationSimulation populati | |
{ | ||
var globalPKAnalysesForIndividuals = new Cache<int, GlobalPKAnalysis>(); | ||
var analyses = base.CalculateFor(populationSimulation, populationSimulation.Results, | ||
individualId => | ||
{ | ||
updateBodyWeightForIndividual(bodyWeightParameter, allBodyWeights, individualId); | ||
}, | ||
individualId => { updateBodyWeightForIndividual(bodyWeightParameter, allBodyWeights, individualId); }, | ||
(individualId, options, compoundName) => | ||
{ | ||
var globalPKAnalysis = globalPkAnalysisForIndividual(globalPKAnalysesForIndividuals, individualId); | ||
|
@@ -234,6 +229,7 @@ private static CompoundPKContext createCompoundPKContext(Compound compound, Indi | |
compoundPK.AddDDIAucInf(individualId, individualSimulation.AucDDI[compound.Name]); | ||
compoundPK.AddDDICMax(individualId, individualSimulation.CMaxDDI[compound.Name]); | ||
} | ||
|
||
return compoundPKContext; | ||
} | ||
|
||
|
@@ -247,7 +243,7 @@ private Container createCompoundContainer(PopulationSimulation populationSimulat | |
var compoundContainer = new Container().WithName(compoundName); | ||
populationSimulation.PKAnalyses.AllPKParametersFor(compoundName).Each(quantityPKParameter => | ||
{ | ||
double? defaultValue = new SortedFloatArray(quantityPKParameter.ValuesAsArray, alreadySorted:false).Median(); | ||
double? defaultValue = new SortedFloatArray(quantityPKParameter.ValuesAsArray, alreadySorted: false).Median(); | ||
if (double.IsNaN(defaultValue.Value)) | ||
defaultValue = null; | ||
|
||
|
@@ -319,7 +315,7 @@ private IContainer calculateGlobalPKAnalysisFor(Simulation simulation, Compound | |
var vssPlasmaOverF = createParameter(VssPlasmaOverF, bloodPlasmaPK[Vss], VolumePerBodyWeight); | ||
var vdPlasma = createParameter(VdPlasma, bloodPlasmaPK[Vd], VolumePerBodyWeight); | ||
var vdPlasmaOverF = createParameter(VdPlasmaOverF, bloodPlasmaPK[Vd], VolumePerBodyWeight); | ||
if(simulation is IndividualSimulation) | ||
if (simulation is IndividualSimulation) | ||
vssPhysChem = createParameter(VssPhysChem, calculateVSSPhysChemFor(simulation, compoundName), VolumePerBodyWeight); | ||
|
||
var totalPlasmaCL = createParameter(TotalPlasmaCL, bloodPlasmaPK[PKParameters.CL], FlowPerWeight); | ||
|
@@ -346,7 +342,7 @@ private IContainer calculateGlobalPKAnalysisFor(Simulation simulation, Compound | |
if (isIntravenous(schemaItem)) | ||
{ | ||
container.AddChildren(vssPlasma, vdPlasma, totalPlasmaCL); | ||
if(vssPhysChem != null) | ||
if (vssPhysChem != null) | ||
container.Add(vssPhysChem); | ||
|
||
return container; | ||
|
@@ -398,13 +394,7 @@ private static IEnumerable<QuantityPKParameter> mapQuantityPKParametersFromIndiv | |
// use the first in series as a template to retrieve from all individual results. | ||
// The list of parameters should be identical for all the individual global analyses. | ||
var aPKAnalysis = globalIndividualPKParameterCache.FirstOrDefault(); | ||
aPKAnalysis?.AllPKParameters.GroupBy(moleculeNameFrom).Each(group => | ||
{ | ||
group.Each(pKParameter => | ||
{ | ||
quantityPKList.Add(quantityPKParameterFor(globalIndividualPKParameterCache, pKParameter, group.Key)); | ||
}); | ||
}); | ||
aPKAnalysis?.AllPKParameters.GroupBy(moleculeNameFrom).Each(group => { group.Each(pKParameter => { quantityPKList.Add(quantityPKParameterFor(globalIndividualPKParameterCache, pKParameter, group.Key)); }); }); | ||
|
||
return quantityPKList; | ||
} | ||
|
@@ -530,9 +520,8 @@ public void CalculateBioavailabilityFor(Simulation simulation, string compoundNa | |
// We know this is a valid cast because it is cloned from simulation | ||
var populationSimulation = simulation.DowncastTo<PopulationSimulation>(); | ||
CalculateFor(ivPopulationSimulation, ivCompoundPKContext); | ||
var contextForPopulationSimulation = createContextForPopulationSimulation(ivCompoundPKContext, mapFromBioavailabilityCompoundPK, compoundName, populationSimulation, new []{Bioavailability}); | ||
var contextForPopulationSimulation = createContextForPopulationSimulation(ivCompoundPKContext, mapFromBioavailabilityCompoundPK, compoundName, populationSimulation, new[] { Bioavailability }); | ||
populationSimulation.PKAnalyses = CalculateFor(populationSimulation, contextForPopulationSimulation); | ||
|
||
} | ||
else if (ivSimulation is IndividualSimulation ivIndividualSimulation) | ||
{ | ||
|
@@ -648,20 +637,20 @@ private bool isMultipleOral(Simulation simulation, Compound compound) | |
return allSchemaItems.Any() && allSchemaItems.All(isOral); | ||
} | ||
|
||
private static bool isOral(ISchemaItem schemaItem) | ||
private static bool isOral(SchemaItem schemaItem) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why this chnage from Interface to not interface? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I implemented a bool property on SchemaItem that matches 'IsOral' and 'IsUserDefined' (IsIV) and like those ones, I did not pull them up to interface. I'm pretty sure all those conversions are local in this class. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I am wondering if we need the ISchemaItem at all. Another day |
||
{ | ||
if (schemaItem == null) | ||
return false; | ||
|
||
return schemaItem.ApplicationType == ApplicationTypes.Oral; | ||
} | ||
|
||
private static bool isIntravenous(ISchemaItem schemaItem) | ||
private static bool isIntravenous(SchemaItem schemaItem) | ||
{ | ||
if (schemaItem == null) | ||
return false; | ||
|
||
return schemaItem.ApplicationType == ApplicationTypes.Intravenous || schemaItem.ApplicationType == ApplicationTypes.IntravenousBolus; | ||
return schemaItem.IsIV; | ||
} | ||
|
||
private ApplicationType applicationTypeFor(Simulation simulation, Compound compound) | ||
|
@@ -673,17 +662,17 @@ private ApplicationType applicationTypeFor(Simulation simulation, Compound compo | |
return numberOfApplications > 1 ? ApplicationType.Multiple : ApplicationType.Empty; | ||
} | ||
|
||
private ISchemaItem singleDosingItem(Simulation simulation, Compound compound) | ||
private SchemaItem singleDosingItem(Simulation simulation, Compound compound) | ||
{ | ||
//this may be null for compound created by metabolization process only | ||
return schemaItemsFrom(simulation, compound).FirstOrDefault(); | ||
} | ||
|
||
private IReadOnlyList<ISchemaItem> schemaItemsFrom(Simulation simulation, Compound compound) | ||
private IReadOnlyList<SchemaItem> schemaItemsFrom(Simulation simulation, Compound compound) | ||
{ | ||
var protocol = simulation.CompoundPropertiesFor(compound).ProtocolProperties.Protocol; | ||
if (protocol == null) | ||
return new List<ISchemaItem>(); | ||
return new List<SchemaItem>(); | ||
|
||
return _protocolToSchemaItemsMapper.MapFrom(protocol); | ||
} | ||
|
@@ -778,8 +767,8 @@ private IEnumerable<DataColumn> columnsFor(CurveData<TimeProfileXValue, TimeProf | |
new DataColumn(curveData.Caption, curveData.YAxis.Dimension, baseGrid) | ||
{ | ||
Values = curveData.YValues.Select(y => y.Y).ToList(), | ||
DataInfo = {MolWeight = populationDataCollector.MolWeightFor(curveData.QuantityPath)}, | ||
QuantityInfo = {Path = curveData.QuantityPath.ToPathArray()} | ||
DataInfo = { MolWeight = populationDataCollector.MolWeightFor(curveData.QuantityPath) }, | ||
QuantityInfo = { Path = curveData.QuantityPath.ToPathArray() } | ||
} | ||
}; | ||
} | ||
|
@@ -857,11 +846,13 @@ public PKAnalysis CreatePKAnalysisFromValues(PKValues pkValues, Simulation simul | |
} | ||
|
||
/// <summary> | ||
/// Returns the range strings when the <paramref name="text"/> contains 'Range 2.5% to 97.5%' language | ||
/// Returns the range strings when the <paramref name="text" /> contains 'Range 2.5% to 97.5%' language | ||
/// </summary> | ||
/// <param name="text">The text being split</param> | ||
/// <returns>The individual range descriptions as a tuple containing low range and high range. | ||
/// If the string cannot be split on 'Range', returns the original text in both members of the tuple</returns> | ||
/// <returns> | ||
/// The individual range descriptions as a tuple containing low range and high range. | ||
/// If the string cannot be split on 'Range', returns the original text in both members of the tuple | ||
/// </returns> | ||
private (string lowerRange, string upperRange) rangeDescriptions(string text) | ||
{ | ||
var splitStrings = text.Split(new[] { "Range" }, StringSplitOptions.None); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,21 +1,22 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using PKSim.Assets; | ||
using OSPSuite.Core.Domain; | ||
using OSPSuite.Core.Domain.UnitSystem; | ||
using OSPSuite.Core.Services; | ||
using OSPSuite.Presentation.Core; | ||
using OSPSuite.Presentation.Presenters; | ||
using OSPSuite.Presentation.Services; | ||
using OSPSuite.Utility.Extensions; | ||
using PKSim.Assets; | ||
using PKSim.Core; | ||
using PKSim.Core.Mappers; | ||
using PKSim.Core.Model; | ||
using PKSim.Core.Repositories; | ||
using PKSim.Core.Services; | ||
using PKSim.Presentation.DTO.Mappers; | ||
using PKSim.Presentation.DTO.Simulations; | ||
using PKSim.Presentation.Views.Simulations; | ||
using OSPSuite.Core.Domain; | ||
using OSPSuite.Core.Domain.UnitSystem; | ||
using OSPSuite.Core.Services; | ||
using OSPSuite.Presentation.Core; | ||
using OSPSuite.Presentation.Presenters; | ||
using OSPSuite.Presentation.Services; | ||
|
||
namespace PKSim.Presentation.Presenters.Simulations | ||
{ | ||
|
@@ -29,6 +30,7 @@ public interface IGlobalPKAnalysisPresenter : IPresenter<IGlobalPKAnalysisView>, | |
void CalculateDDIRatioFor(string compoundName); | ||
string DisplayNameFor(string parameterName); | ||
bool HasParameters(); | ||
bool CanCalculateGlobalPK(); | ||
} | ||
|
||
public class GlobalPKAnalysisPresenter : AbstractSubPresenter<IGlobalPKAnalysisView, IGlobalPKAnalysisPresenter>, IGlobalPKAnalysisPresenter | ||
|
@@ -43,15 +45,17 @@ public class GlobalPKAnalysisPresenter : AbstractSubPresenter<IGlobalPKAnalysisV | |
private GlobalPKAnalysisDTO _globalPKAnalysisDTO; | ||
private DefaultPresentationSettings _settings; | ||
private readonly IPresentationSettingsTask _presentationSettingsTask; | ||
private readonly IProtocolToSchemaItemsMapper _protocolToSchemaItemsMapper; | ||
|
||
public GlobalPKAnalysisPresenter(IGlobalPKAnalysisView view, IPKAnalysesTask pkAnalysesTask, | ||
IGlobalPKAnalysisToGlobalPKAnalysisDTOMapper globalPKAnalysisDTOMapper, IHeavyWorkManager heavyWorkManager, IRepresentationInfoRepository representationInfoRepository, IPresentationSettingsTask presentationSettingsTask) : base(view) | ||
IGlobalPKAnalysisToGlobalPKAnalysisDTOMapper globalPKAnalysisDTOMapper, IHeavyWorkManager heavyWorkManager, IRepresentationInfoRepository representationInfoRepository, IPresentationSettingsTask presentationSettingsTask, IProtocolToSchemaItemsMapper protocolToSchemaItemsMapper) : base(view) | ||
{ | ||
_pkAnalysesTask = pkAnalysesTask; | ||
_globalPKAnalysisDTOMapper = globalPKAnalysisDTOMapper; | ||
_heavyWorkManager = heavyWorkManager; | ||
_representationInfoRepository = representationInfoRepository; | ||
_presentationSettingsTask = presentationSettingsTask; | ||
_protocolToSchemaItemsMapper = protocolToSchemaItemsMapper; | ||
_settings = new DefaultPresentationSettings(); | ||
} | ||
|
||
|
@@ -78,7 +82,7 @@ public bool ShouldCalculateDDIRatio(string compoundName, string parameterName) | |
shouldCalculateGlobalPKParameter(compoundName, parameterName, CoreConstants.PKAnalysis.C_maxRatio); | ||
} | ||
|
||
private bool shouldCalculateGlobalPKParameter(string compoundName, string parameterName,string globalPKParameterName) | ||
private bool shouldCalculateGlobalPKParameter(string compoundName, string parameterName, string globalPKParameterName) | ||
{ | ||
if (!string.Equals(parameterName, globalPKParameterName)) | ||
return false; | ||
|
@@ -119,10 +123,7 @@ private void loadPreferredUnitsForPKAnalysis() | |
|
||
private void updateParameterDisplayUnits(string parameterName) | ||
{ | ||
GlobalPKAnalysis.PKParameters(parameterName).Each(parameter => | ||
{ | ||
parameter.DisplayUnit = parameter.Dimension.Unit(_settings.GetSetting(parameterName, DisplayUnitFor(parameterName).Name)); | ||
}); | ||
GlobalPKAnalysis.PKParameters(parameterName).Each(parameter => { parameter.DisplayUnit = parameter.Dimension.Unit(_settings.GetSetting(parameterName, DisplayUnitFor(parameterName).Name)); }); | ||
} | ||
|
||
private Simulation firstSimulation => _simulations.FirstOrDefault(); | ||
|
@@ -164,6 +165,20 @@ public bool HasParameters() | |
return false; | ||
} | ||
|
||
public bool CanCalculateGlobalPK() | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I ran resharper to auto-format so there's some noise in this PR. The gist is we need to calculate when a simulation contains only multiple IV applications of all compounds. If there's only single IV, oral, or a mix we want to show the global panel. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. it this how it was doen for individual simulation? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. for individual, the global is calculated on demand, so if it can calculate a global, the presenter just indicates that the datatable has rows and the view should show the panel. For populations, you might have to re-run if the results are from an older version because the global would not have been calculated, and will not be calculated just because you show it. |
||
{ | ||
return firstSimulation.Compounds.Any(compound => | ||
{ | ||
var schemaItems = _protocolToSchemaItemsMapper.MapFrom(firstSimulation.CompoundPropertiesFor(compound).ProtocolProperties.Protocol); | ||
return !isMultipleIV(schemaItems); | ||
}); | ||
} | ||
|
||
private bool isMultipleIV(IReadOnlyList<SchemaItem> schemaItems) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. On the other hand, those small methods can really be on one line. no { } etc... makes sense to me There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's similar. In Individual => There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fixed |
||
{ | ||
return schemaItems.Count(schemaItem => schemaItem.IsIV) > 1; | ||
} | ||
|
||
public void LoadSettingsForSubject(IWithId subject) | ||
{ | ||
_settings = _presentationSettingsTask.PresentationSettingsFor<DefaultPresentationSettings>(this, subject); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks very hard to read. Why is this all on one line suddenly?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ah, shoot. That's a Resharper.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed