/* * This file is part of ADDIS (Aggregate Data Drug Information System). * ADDIS is distributed from http://drugis.org/. * Copyright © 2009 Gert van Valkenhoef, Tommi Tervonen. * Copyright © 2010 Gert van Valkenhoef, Tommi Tervonen, Tijs Zwinkels, * Maarten Jacobs, Hanno Koeslag, Florin Schimbinschi, Ahmad Kamal, Daniel * Reid. * Copyright © 2011 Gert van Valkenhoef, Ahmad Kamal, Daniel Reid, Florin * Schimbinschi. * Copyright © 2012 Gert van Valkenhoef, Daniel Reid, Joël Kuiper, Wouter * Reckman. * Copyright © 2013 Gert van Valkenhoef, Joël Kuiper. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package org.drugis.addis.entities.analysis; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.TreeMap; import org.drugis.addis.entities.Arm; import org.drugis.addis.entities.Entity; import org.drugis.addis.entities.Indication; import org.drugis.addis.entities.OutcomeMeasure; import org.drugis.addis.entities.Study; import org.drugis.addis.entities.treatment.TreatmentDefinition; import org.drugis.addis.util.EntityUtil; import org.drugis.common.threading.status.TaskTerminatedModel; import org.drugis.common.validation.BooleanAndModel; import org.drugis.mtc.ConsistencyModel; import org.drugis.mtc.DefaultModelFactory; import org.drugis.mtc.InconsistencyModel; import org.drugis.mtc.MCMCSettingsCache; import org.drugis.mtc.MixedTreatmentComparison; import org.drugis.mtc.NodeSplitModel; import org.drugis.mtc.Parameter; import org.drugis.mtc.model.Network; import org.drugis.mtc.model.NetworkBuilder; import org.drugis.mtc.model.Treatment; import org.drugis.mtc.parameterization.BasicParameter; import org.drugis.mtc.parameterization.ParameterComparator; import org.drugis.mtc.presentation.ConsistencyWrapper; import org.drugis.mtc.presentation.InconsistencyWrapper; import org.drugis.mtc.presentation.MCMCModelWrapper; import org.drugis.mtc.presentation.NodeSplitWrapper; import org.drugis.mtc.presentation.SavedConsistencyWrapper; import org.drugis.mtc.presentation.SavedInconsistencyWrapper; import org.drugis.mtc.presentation.SavedNodeSplitWrapper; import org.drugis.mtc.presentation.SimulationConsistencyWrapper; import org.drugis.mtc.presentation.SimulationInconsistencyWrapper; import org.drugis.mtc.presentation.SimulationNodeSplitWrapper; import org.drugis.mtc.summary.ConvergenceSummary; import org.drugis.mtc.summary.MultivariateNormalSummary; import org.drugis.mtc.summary.NodeSplitPValueSummary; import org.drugis.mtc.summary.ProxyMultivariateNormalSummary; import org.drugis.mtc.summary.QuantileSummary; import org.drugis.mtc.summary.RankProbabilitySummary; import org.drugis.mtc.util.MCMCResultsAvailableModel; import com.jgoodies.binding.value.ValueModel; public class NetworkMetaAnalysis extends AbstractMetaAnalysis implements MetaAnalysis { private static final String PROPERTY_MCMC_RESULTS = "MCMCResults"; private static final String ANALYSIS_TYPE = "Markov Chain Monte Carlo Network Meta-Analysis"; private InconsistencyWrapper<TreatmentDefinition> d_inconsistencyModel; private ConsistencyWrapper<TreatmentDefinition> d_consistencyModel; protected NetworkBuilder<TreatmentDefinition> d_builder; protected Map<Parameter, NodeSplitPValueSummary> d_nodeSplitPValueSummaries = new HashMap<Parameter, NodeSplitPValueSummary>(); private final Map<BasicParameter, NodeSplitWrapper<TreatmentDefinition>> d_nodeSplitModels = new TreeMap<BasicParameter, NodeSplitWrapper<TreatmentDefinition>>(new ParameterComparator()); private final ProxyMultivariateNormalSummary d_relativeEffectsSummary = new ProxyMultivariateNormalSummary(); public NetworkMetaAnalysis(final String name, final Indication indication, final OutcomeMeasure om, final List<Study> studies, final Collection<TreatmentDefinition> alternatives, final Map<Study, Map<TreatmentDefinition, Arm>> armMap) throws IllegalArgumentException { super(ANALYSIS_TYPE, name, indication, om, studies, sortAlternatives(alternatives), armMap); } public NetworkMetaAnalysis(final String name, final Indication indication, final OutcomeMeasure om, final Map<Study, Map<TreatmentDefinition, Arm>> armMap) throws IllegalArgumentException { super(ANALYSIS_TYPE, name, indication, om, armMap); } private static List<TreatmentDefinition> sortAlternatives(final Collection<TreatmentDefinition> alternatives) { final ArrayList<TreatmentDefinition> list = new ArrayList<TreatmentDefinition>(alternatives); Collections.sort(list); return list; } private InconsistencyWrapper<TreatmentDefinition> createInconsistencyModel() { final InconsistencyModel inconsistencyModel = (DefaultModelFactory.instance()).getInconsistencyModel(getBuilder().buildNetwork()); attachModelSavableListener(inconsistencyModel); return new SimulationInconsistencyWrapper<TreatmentDefinition>(inconsistencyModel, getBuilder().getTreatmentMap()); } private ConsistencyWrapper<TreatmentDefinition> createConsistencyModel() { final ConsistencyModel consistencyModel = (DefaultModelFactory.instance()).getConsistencyModel(getBuilder().buildNetwork()); final SimulationConsistencyWrapper<TreatmentDefinition> model = new SimulationConsistencyWrapper<TreatmentDefinition>(consistencyModel, getAlternatives(), getBuilder().getTreatmentMap()); d_relativeEffectsSummary.setNested(model.getRelativeEffectsSummary()); attachModelSavableListener(consistencyModel); return model; } private NodeSplitWrapper<TreatmentDefinition> createNodeSplitModel(final BasicParameter node) { final NodeSplitModel nodeSplitModel = (DefaultModelFactory.instance()).getNodeSplitModel(getBuilder().buildNetwork(), node); d_nodeSplitPValueSummaries.put(node, new NodeSplitPValueSummary(nodeSplitModel.getResults(), nodeSplitModel.getDirectEffect(), nodeSplitModel.getIndirectEffect())); attachModelSavableListener(nodeSplitModel); return new SimulationNodeSplitWrapper<TreatmentDefinition>(nodeSplitModel, getBuilder().getTreatmentMap()); } private NetworkBuilder<TreatmentDefinition> createBuilder(final OutcomeMeasure outcomeMeasure, final List<Study> studies, final List<TreatmentDefinition> alternatives, final Map<Study, Map<TreatmentDefinition, Arm>> armMap) { return NetworkBuilderFactory.createBuilder(outcomeMeasure, studies, alternatives, armMap); } private void attachModelSavableListener(final MixedTreatmentComparison model) { final MCMCResultsAvailableModel resultsAvailableModel = new MCMCResultsAvailableModel(model.getResults()); final TaskTerminatedModel modelTerminated = new TaskTerminatedModel(model.getActivityTask()); final BooleanAndModel modelFinishedAndResults = new BooleanAndModel(Arrays.<ValueModel>asList(modelTerminated, resultsAvailableModel)); modelFinishedAndResults.addPropertyChangeListener(new PropertyChangeListener() { @Override public void propertyChange(final PropertyChangeEvent evt) { firePropertyChange(PROPERTY_MCMC_RESULTS, false, true); } }); } public synchronized InconsistencyWrapper<TreatmentDefinition> getInconsistencyModel() { if (d_inconsistencyModel == null || d_inconsistencyModel.isDestroyed()) { d_inconsistencyModel = createInconsistencyModel(); } return d_inconsistencyModel; } public synchronized ConsistencyWrapper<TreatmentDefinition> getConsistencyModel() { if (d_consistencyModel == null || d_consistencyModel.isDestroyed()) { d_consistencyModel = createConsistencyModel(); } return d_consistencyModel; } public synchronized NodeSplitWrapper<TreatmentDefinition> getNodeSplitModel(final BasicParameter p) { if (!d_nodeSplitModels.containsKey(p) || d_nodeSplitModels.get(p).isDestroyed()) { d_nodeSplitModels.put(p, createNodeSplitModel(p)); } return d_nodeSplitModels.get(p); } public synchronized void loadInconsistencyModel(final MCMCSettingsCache settings, final Map<Parameter, QuantileSummary> quantileSummaries, final Map<Parameter, ConvergenceSummary> convergenceSummaries) { d_inconsistencyModel = new SavedInconsistencyWrapper<TreatmentDefinition>(settings, quantileSummaries, convergenceSummaries, d_builder.getTreatmentMap()); } public synchronized void loadConsistencyModel(final MCMCSettingsCache mcmcSettingsCache, final HashMap<Parameter, QuantileSummary> quantileSummaries, final HashMap<Parameter, ConvergenceSummary> convergenceSummaries, final MultivariateNormalSummary relativeEffectsSummary, final RankProbabilitySummary rankProbabilitySummary) { d_consistencyModel = new SavedConsistencyWrapper<TreatmentDefinition>(mcmcSettingsCache, quantileSummaries, convergenceSummaries, relativeEffectsSummary, rankProbabilitySummary, getAlternatives(), getBuilder().getTreatmentMap()); d_relativeEffectsSummary.setNested(d_consistencyModel.getRelativeEffectsSummary()); } public void loadNodeSplitModel(final BasicParameter splitParameter, final MCMCSettingsCache settings, final HashMap<Parameter, QuantileSummary> quantileSummaries, final HashMap<Parameter, ConvergenceSummary> convergenceSummaries, final NodeSplitPValueSummary nodeSplitPValueSummary) { final SavedNodeSplitWrapper<TreatmentDefinition> nodeSplitModel = new SavedNodeSplitWrapper<TreatmentDefinition>(settings, quantileSummaries, convergenceSummaries, splitParameter, nodeSplitPValueSummary, d_builder.getTreatmentMap()); d_nodeSplitModels.put(splitParameter, nodeSplitModel); } public void resetNodeSplitModels() { d_nodeSplitModels.clear(); for(final BasicParameter p : getSplitParameters()) { getNodeSplitModel(p); } } public NetworkBuilder<TreatmentDefinition> getBuilder() { if (d_builder == null) { d_builder = createBuilder(d_outcome, d_studies, getAlternatives(), d_armMap); } return d_builder; } public Network getNetwork() { return getBuilder().buildNetwork(); } @Override public MultivariateNormalSummary getRelativeEffectsSummary() { return d_relativeEffectsSummary; } public boolean isContinuous() { return NetworkBuilderFactory.isContinuous(d_outcome); } public Treatment getTreatment(final TreatmentDefinition d) { return getBuilder().getTreatmentMap().get(d); } public TreatmentDefinition getTreatmentDefinition(final Treatment t) { return getBuilder().getTreatmentMap().getKey(t); } public List<BasicParameter> getSplitParameters() { return DefaultModelFactory.instance().getSplittableNodes(getBuilder().buildNetwork()); } public Collection<NodeSplitWrapper<TreatmentDefinition>> getNodeSplitModels() { return d_nodeSplitModels.values(); } @Override public boolean deepEquals(final Entity other) { if (!super.deepEquals(other)) { return false; } final NetworkMetaAnalysis o = (NetworkMetaAnalysis) other; for (final TreatmentDefinition d : o.getAlternatives()) { for (final Study s : o.getIncludedStudies()) { if (!EntityUtil.deepEqual(getArm(s, d), o.getArm(s, d))) { return false; } } } return true; } public void reset(final MCMCModelWrapper m) { m.selfDestruct(); firePropertyChange(PROPERTY_MCMC_RESULTS, true, false); } }