├── .gitignore ├── LICENSE.md ├── QSPToolbox ├── bakery │ ├── convertResultTableToStruct.m │ ├── createSimResultTable.m │ ├── exampleWfSteps_scratch │ │ ├── axes.txt │ │ ├── pointsRT.txt │ │ ├── step1_burst_simulation.m │ │ ├── step2_set_up_mapel_options.m │ │ ├── step3_screen_worksheet.m │ │ └── step4_vpop_expansion.m │ ├── plotInterventionVPopOverlay.m │ ├── plotVarsAcrossVPIntervention.m │ ├── plotVarsOptions.m │ ├── prccSensitivityOptions.m │ ├── readAllResultStruct.m │ ├── removeVPopInterventions.m │ ├── runPRCCSensitivity.m │ └── simulateWorksheetIndDoses.m ├── cohort │ ├── addVariedVPs.m │ ├── bestNofM.m │ ├── calculateControlCoefficients.m │ ├── classes │ │ ├── bestNofMOptions.m │ │ ├── calculateControlCoefficientsOptions.m │ │ ├── clusterPickOptions.m │ │ ├── clusterTestOptions.m │ │ ├── runControlCoefficientsSimulationsOptions.m │ │ ├── sobolSampleOptions.m │ │ ├── sobolSensitivityOptions.m │ │ ├── univariateSweepOptions.m │ │ ├── univariateSweepOutputAnalysisOptions.m │ │ └── varyAxesOptions.m │ ├── createResponseSummaryTable.m │ ├── createScreenTable.m │ ├── pickClusterVPs.m │ ├── runControlCoefficientsSimulations.m │ ├── runSobolSample.m │ ├── runSobolSensitivity.m │ ├── runUnivariateSweep.m │ ├── runUnivariateSweepOutputAnalysis.m │ ├── screenWorksheetVPs.m │ ├── testClusterSizes.m │ └── utility │ │ ├── getLinearIndependentVectors.m │ │ ├── getMinimalEdgeSet.m │ │ ├── resamplePCASpace.m │ │ ├── selectNbest.m │ │ └── varyAxes.m ├── deprecationManagement │ ├── checkUpdateObjectVersion.m │ ├── deprecated │ │ ├── VPopRECISTnoBin.m │ │ ├── expandVPopEffNAutoSplitSave.m │ │ └── mapelOptionsRECISTnoBin.m │ ├── updateBinTableFormat.m │ ├── updateTablesWithSubpopReference.m │ └── updateTablesWithSubpopformat.m ├── docs │ └── Cheng_2017_AAPSJ.pdf ├── examples │ ├── data │ │ ├── fluorescence_quench_internalization_data_n87_ab1.txt │ │ ├── xenograft_data_1200115_n87_buffer_only.txt │ │ ├── xenograft_data_1200147_n87_ab1_only.txt │ │ ├── xenograft_data_1200147_n87_buffer_only.txt │ │ ├── xenograft_data_95305073_hep3b.txt │ │ └── xenograft_data_95305073_n87.txt │ ├── example01.m │ ├── example02.m │ ├── example03.m │ ├── example04.m │ ├── example05.m │ ├── example06.m │ ├── example07.m │ └── miscellaneous │ │ ├── adc_platform_public_v0p15p1.sbproj │ │ ├── calculateGFunctionSi.m │ │ ├── example_cohort_worksheet1.mat │ │ ├── example_intervention_file.txt │ │ ├── example_vp_file.txt │ │ ├── example_vpop.mat │ │ └── gfunction_test.sbproj ├── external │ ├── compare_correlation_coefficients │ │ ├── compare_correlation_coefficients.m │ │ └── license.txt │ ├── genpath_exclude │ │ ├── genpath_exclude.m │ │ └── license.txt │ ├── herrorbar │ │ ├── herrorbar.m │ │ └── license.txt │ ├── kstest_2s_2d │ │ ├── kstest_2s_2d.m │ │ ├── license.txt │ │ ├── quadrantCount.m │ │ └── weightedKS2D.m │ ├── myfisher │ │ ├── LICENSE │ │ ├── README.md │ │ └── myfisher.m │ ├── myfisher22 │ │ ├── LICENSE │ │ ├── README.md │ │ └── myfisher22.m │ ├── myfisher23 │ │ ├── LICENSE │ │ ├── README.md │ │ └── myfisher23.m │ ├── myfisher24 │ │ ├── license.txt │ │ └── myfisher24.m │ ├── nnls │ │ ├── Readme.txt │ │ ├── license.txt │ │ ├── nnls.m │ │ └── nnlstest1.m │ └── weightedcorrs │ │ ├── license.txt │ │ └── weightedcorrs.m ├── initQSPToolbox.m ├── io │ ├── loadMapelOptions.m │ ├── loadVPop.m │ ├── loadWorksheet.m │ ├── loadWorksheetAutoMerge.m │ ├── readExperimentData.m │ ├── readInterventionTable.m │ ├── readQSPModel.m │ ├── readVPTable.m │ ├── saveMapelOptions.m │ ├── saveVPop.m │ ├── saveWorksheet.m │ ├── saveWorksheetAutoSplit.m │ ├── saveWorksheetNoCompression.m │ └── writeResultStruct.m ├── misc │ └── oncology_trial_data_integration.R ├── plotting │ ├── classes │ │ ├── plotAcrossVPOptions.m │ │ ├── plotCoefficientsOptions.m │ │ └── plotOptions.m │ ├── plotAcrossIntervention.m │ ├── plotAcrossVP.m │ ├── plotBRVPop.m │ ├── plotBinVPop.m │ ├── plotBiomarker.m │ ├── plotCoefficients.m │ ├── plotDist2DVPop.m │ ├── plotDistCDFVPop.m │ ├── plotInterventionVPop.m │ ├── plotMnSDVPop.m │ ├── plotPWHist.m │ ├── plotSeparateAcrossIntervention.m │ └── plotSimExpDataVPop.m ├── population │ ├── adjustLambda.m │ ├── classes │ │ ├── @VPop │ │ │ ├── VPop.m │ │ │ ├── addPredTableVals.m │ │ │ ├── addTableSimVals.m │ │ │ ├── assignCoeffs.m │ │ │ ├── assignIndices.m │ │ │ ├── assignPWs.m │ │ │ ├── get.m │ │ │ ├── getSimData.m │ │ │ ├── startPWs.m │ │ │ └── startProbs.m │ │ ├── VPopRECIST.m │ │ ├── correlationOptions.m │ │ ├── expandVPopEffNOptions.m │ │ ├── mapelOptions.m │ │ └── mapelOptionsRECIST.m │ ├── createVPRangeTable.m │ ├── dataImport │ │ ├── convertExpDataTo2DDistTable.m │ │ ├── convertExpDataToBinTable.m │ │ ├── convertExpDataToCorTable.m │ │ ├── convertExpDataToDistTable.m │ │ ├── convertExpDataToMnSDTable.m │ │ ├── convertMapelOptionsToExpDataTable.m │ │ ├── convertResponseTypeToExpDataTable.m │ │ ├── createBinTable.m │ │ ├── createBinTableRECIST.m │ │ ├── createDistTable.m │ │ ├── createDistTableRECIST.m │ │ ├── createExpDataTable.m │ │ ├── createExpDataTableRECIST.m │ │ ├── createMnSDTable.m │ │ ├── createMnSDTableRECIST.m │ │ ├── createResponseTablesRECIST.m │ │ └── createSubpopTable.m │ ├── evaluateCorrelations.m │ ├── evaluateGOF.m │ ├── evaluateMSE.m │ ├── expandVPopEffN.m │ ├── linearCalibration │ │ ├── classes │ │ │ ├── LinearCalibration.m │ │ │ └── LinearCalibrationOptions.m │ │ └── increaseEffNWithLinearCalibrate.m │ ├── mapel.m │ ├── mapelLinearExpand.m │ ├── restartMapel.m │ ├── restartMapelLinearExpand.m │ ├── statistics │ │ ├── addPD2Vals.m │ │ ├── alignCDFs.m │ │ ├── alignCDFsPreGrid.m │ │ ├── alignSamples.m │ │ ├── checkExpDataCorrelations.m │ │ ├── checkLN.m │ │ ├── compositeGOF.m │ │ ├── compositeGOFRECIST.m │ │ ├── contingency2N.m │ │ ├── hbe.m │ │ ├── predNPDTFLS.m │ │ ├── regressPD2ScaleFactor.m │ │ ├── weightedKS.m │ │ ├── weightedKSPreGrid.m │ │ ├── woodF.m │ │ ├── wtdBinProb.m │ │ ├── wtdMean.m │ │ └── wtdStd.m │ ├── testExpandVPopSettings.m │ └── utility │ │ ├── align2DPDFs.m │ │ ├── calculateExpWeight.m │ │ ├── calculateExpWeightFix.m │ │ ├── calculateExpWeightFixSingle.m │ │ ├── combineBins.m │ │ ├── createRECISTSimFilter.m │ │ ├── evaluateObjective.m │ │ ├── evaluateObjectiveNoBin.m │ │ ├── expandWorksheetVPsFromVPop.m │ │ ├── extractLowPs.m │ │ ├── findFit.m │ │ ├── getInitialPWs.m │ │ ├── hyperTransform.m │ │ ├── initializeOptionPropertiesToVPop.m │ │ ├── initializeVPopPropertiesToOption.m │ │ ├── invHyperTransform.m │ │ ├── loadCommonNames.m │ │ ├── normalizeWeights.m │ │ ├── probsToProbVect.m │ │ ├── scoreWorksheetVPs.m │ │ ├── scoreWorksheetVPsLC.m │ │ ├── spreadPWsToNeighbors.m │ │ ├── subsetWorksheetVPop.m │ │ ├── transferPWtoChildren.m │ │ └── updateSubpopTableVPs.m ├── test │ └── unitTests.m ├── visp │ ├── createViSPInput.m │ ├── loadViSPResult.m │ └── utility │ │ ├── CreateExportedModel.m │ │ ├── GetDoseNames.m │ │ ├── GetIndices.m │ │ ├── GetParamNamesAndValuesToStoreInDB.m │ │ ├── SetSimulationOptionsInExportedModel.m │ │ └── UpdateSimBioModel.m └── worksheet │ ├── axis │ ├── addAxisDef.m │ ├── getAxisDef.m │ ├── getAxisDefBounds.m │ ├── getAxisDefIDs.m │ ├── getVPCoeffs.m │ ├── getVPValues.m │ ├── resetAxis.m │ ├── resetAxisBounds.m │ └── utility │ │ └── setAxisDefBounds.m │ ├── classes │ ├── axisDef.m │ ├── axisVP.m │ ├── responseTypeElementAxis.m │ ├── responseTypeElementBounds.m │ ├── responseTypeElementPoints.m │ ├── responseTypeResult.m │ ├── resultTable.m │ └── simulateOptions.m │ ├── convertVPCoefficientsToVariants.m │ ├── copyWorksheet.m │ ├── createWorksheet.m │ ├── data │ ├── getExpData.m │ └── getExpDataIDs.m │ ├── diffWorksheets.m │ ├── getResultOutputforIntervention.m │ ├── intervention │ ├── createIntervention.m │ ├── extractInterventionTypeElements.m │ ├── getDoseNames.m │ ├── getInterventionIDs.m │ └── removeInterventions.m │ ├── mergeWorksheets.m │ ├── model │ ├── compileModel.m │ ├── getModelCompartmentIDs.m │ ├── getModelObservableIDs.m │ ├── getModelParameterIDs.m │ └── getModelSpeciesIDs.m │ ├── removeDuplicateVPs.m │ ├── responseType │ ├── addResponseTypeElement.m │ ├── createResponseType.m │ ├── getResponseType.m │ ├── getResponseTypeElementIDs.m │ ├── getResponseTypeIDs.m │ ├── utility │ │ ├── evaluateAxisObjective.m │ │ ├── evaluateBoundsObjectiveWtIntRangeCE.m │ │ ├── evaluatePointObjectiveCV.m │ │ ├── evaluatePointObjectiveRange.m │ │ ├── evaluatePointObjectiveWtIntMedCE.m │ │ ├── evaluatePointObjectiveWtIntRangeCE.m │ │ ├── evaluatePointObjectiveWtRange.m │ │ ├── evaluatePointObjectiveWtRangeCE.m │ │ ├── evaluateResponseType.m │ │ └── evaluateResponseTypeElement.m │ └── verifyResponseType.m │ ├── results │ ├── convertSimData.m │ └── filterResults.m │ ├── simulateWorksheet.m │ ├── simulateWorksheetIterateTolerance.m │ ├── utility │ ├── calculateIndividualElementValues.m │ ├── checkNWorkers.m │ ├── getOptimizationAxes.m │ ├── getSimulateValuesDoses.m │ ├── getSimulateValuesDosesSep.m │ ├── getUniqueBaseVPVariantSets.m │ ├── particleSwarmCohortWrapper.m │ ├── runModelforOptimization.m │ ├── runSimulations.m │ ├── runSingleSimulation.m │ ├── runWorksheetCohortOptimization.m │ ├── runWorksheetVPOptimization.m │ ├── verifyFullResults.m │ └── verifySimData.m │ ├── variant │ ├── getVariantNames.m │ ├── getVariantTypeElements.m │ ├── getVariantTypes.m │ └── utility │ │ ├── flattenVariantstoElements.m │ │ └── updateElementAxisValues.m │ └── vp │ ├── createVP.m │ ├── createVPs.m │ ├── getPatientgroup.m │ ├── getVP.m │ ├── getVPIDs.m │ ├── keepVPs.m │ └── removeVPs.m └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | # Mac files 2 | .DS_Store 3 | *.asv 4 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Copyright (c) 2018, Bristol-Myers Squibb 2 | All rights reserved. 3 | 4 | 'Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 5 | 6 | 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 7 | 8 | 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 9 | 10 | 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 11 | 12 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.' -------------------------------------------------------------------------------- /QSPToolbox/bakery/exampleWfSteps_scratch/axes.txt: -------------------------------------------------------------------------------- 1 | axisID elementNames elementTypes bounds1_1 bounds1_2 scale1 2 | axisShedding par_ag_shed_rate_t parameter 0 10 linear 3 | axisInternalization par_ag_endocytosis parameter 0 3.5 linear 4 | axisWallPoreA par_fraction_capillary_pore_area_per_unit_thickness_a parameter 5 50 linear 5 | axisWallPoreB par_fraction_capillary_pore_area_per_unit_thickness_b parameter 0.2 1.95 linear 6 | axisShedClearance par_shed_antigen_clearance_p1 parameter 5 300 linear 7 | axisLabelExport par_payload_secretion_rate parameter 0 24 linear 8 | axisICFFraction par_tumor_extravascular_volume_fraction_icf parameter 0.5 0.8 linear 9 | axisVascularFraction par_tumor_volume_fraction_vascular parameter 0.005 0.05 linear 10 | axisRCapRange par_capillary_radius_max parameter 8 15 linear 11 | axisVCapRange par_capillary_radius_exponent parameter 2.43e-05 0.000219 linear 12 | axisLesionLinGrowth par_tumor_grow_rate_linear parameter 8.3 74.7 linear 13 | axisLesionExpGrowth par_tumor_grow_rate_exp parameter 0.0244 0.219 linear 14 | axisInitialTumorMass par_initial_tumor_mass parameter 0.0763 0.24 linear 15 | -------------------------------------------------------------------------------- /QSPToolbox/bakery/exampleWfSteps_scratch/pointsRT.txt: -------------------------------------------------------------------------------- 1 | rtID elementNames modelYVar modelYVarType interventionID expDataID expDataTimeVar expDataYVar objectiveType weight 2 | culture_internalized N87_agx parrule_payload_fraction_of_initial_bound_intracellular parameter culture_internalization fluorescence_quench_internalization_data_n87_ab1 time_day internalized_fr wtintrangece 1 3 | buffer_injection_1200147_growth_assay N87_agx parrule_tumor_volume parameter buffer_injection_1200147_shed_assay xenograft_data_1200147_n87_buffer_only TIME_PLUS_11_DAY TUMOR_VOLUME_L wtintrangece 1 4 | buffer_injection_1200147_shed_assay N87_agx parrule_shed_total_plasma_concentration parameter buffer_injection_1200147_shed_assay xenograft_data_1200147_n87_buffer_only TIME_PLUS_11_DAY SOLAG_NANOMOLEPL wtintrangece 1 5 | antibody_injection_1200147_growth_assay N87_agx parrule_tumor_volume parameter antibody_injection_1200147_shed_assay xenograft_data_1200147_n87_ab1_only TIME_PLUS_11_DAY TUMOR_VOLUME_L wtintrangece 1 6 | antibody_injection_1200147_shed_assay N87_agx parrule_shed_total_plasma_concentration parameter antibody_injection_1200147_shed_assay xenograft_data_1200147_n87_ab1_only TIME_PLUS_11_DAY SOLAG_NANOMOLEPL wtintrangece 1 7 | agxab1pet_injection N87_agx parrule_payload_total_apparent_pet_tumor_nanomole_per_gram parameter agxab1pet_injection xenograft_data_95305073_n87 time_10delayed_day accumulation_N87_nmole_per_gram_tumor wtintrangece 1 8 | -------------------------------------------------------------------------------- /QSPToolbox/cohort/utility/getLinearIndependentVectors.m: -------------------------------------------------------------------------------- 1 | function [VPCoeffsLI, VPind] = getLinearIndependentVectors(VPCoeffs) 2 | % This function takes an input matrix where columns are 3 | % VPs and tested for linear independence. 4 | % It will preferentially pick out columns in the order provided. 5 | % 6 | % ARGUMENTS 7 | % VPCoeffs: A matrix of VP coefficients 8 | % 9 | % RETURNS 10 | % VPCoeffsLI: A matrix of VP coefficients 11 | % that are linearly independent. 12 | % VPind: Indices of the VPs in the returned 13 | % matrix from the input matrix 14 | % 15 | 16 | % This will force to select the first vector of 17 | % collinar vector pairs, if any 18 | %VPCoeffs = fliplr(VPCoeffs); 19 | [nRows, nCols] = size(VPCoeffs); 20 | VPCoeffsT = VPCoeffs'; 21 | R1=1; 22 | % We will force what is probably a larger tolerance value to 23 | % be more conservative 24 | tolerance = 1E-8; 25 | excludeInd = nan(1,0); 26 | for I=1:size(VPCoeffsT,1) 27 | R2=rank(VPCoeffsT(1:I,:),tolerance); 28 | if R2~=R1 29 | excludeInd = [excludeInd,I]; 30 | end 31 | R1=R2+1; 32 | end 33 | VPind = [1:nCols]; 34 | VPind(excludeInd) = []; 35 | VPCoeffsLI = VPCoeffs(:,VPind); 36 | end -------------------------------------------------------------------------------- /QSPToolbox/cohort/utility/getMinimalEdgeSet.m: -------------------------------------------------------------------------------- 1 | function edgeVPIDs = getMinimalEdgeSet(parentVPs) 2 | % This function takes a cell array of cell arrays of identification strings 3 | % as an imput and returns a cell of identification strings 4 | % including at least one indentificaiton string from each set in the 5 | % original cell array of cell arrays. 6 | % 7 | % This function was written to help with the selection of a minimum set of 8 | % edge VPs. i.e. where each inner array 9 | % {{VPID1, VPID2}; {VPID2, VPID3, VPID4}; ... } 10 | % Could have multiple VPs that are a tied for some characteristic, i.e. 11 | % being and edge, and we want to provide a cell array of VPIDs that 12 | % includes one VP from all the edges, preferably the smallest set possible. 13 | % 14 | % Arguments: 15 | % parentVPs A cell array of cell array of strings. i.e.: 16 | % {{VPID1, VPID2}; {VPID2, VPID3, VPID4}; {VPID5}; ... } 17 | % 18 | % Returns: 19 | % edgeVPIDs A cell array of strings containing at least one entry from 20 | % from every set in parentVPs. i.e.: 21 | % {VPID2, VPID5, ... } 22 | % 23 | 24 | nParentCandidates = length(parentVPs); 25 | parentVPsPass = cell(1,length(parentVPs)); 26 | parentsPassCounter = 1; 27 | for checkCounter =1 : nParentCandidates 28 | curCheckParents = parentVPs{checkCounter}; 29 | % We need to compare to other parents in the list to 30 | % 1. pick the best parent that might cover multiple edges and 31 | % 2. minimize double counting for edges 32 | [~, curCheckSize] = size(curCheckParents); 33 | 34 | if checkCounter < nParentCandidates 35 | curCheckscore = zeros(nParentCandidates-(checkCounter),curCheckSize); 36 | % First check the current set of parents against the ones 37 | % further down the list in case one of the parents 38 | % in the current set appears there. 39 | for otherParentCounter = (checkCounter + 1) : nParentCandidates 40 | testParents = parentVPs{otherParentCounter}; 41 | curCheckscore(otherParentCounter - checkCounter,:) = ismember(curCheckParents,testParents); 42 | end 43 | otherParentIndices = (checkCounter + 1) : nParentCandidates; 44 | % After we have the comparison for the current parents, 45 | % we pick the one with highest score as compared to 46 | % other rows 47 | sumParentScores = sum(curCheckscore,1); 48 | bestIndex = find(sumParentScores == max(sumParentScores)); 49 | if length(bestIndex) > 1 50 | % In case of a tie 51 | bestIndex = bestIndex(1); 52 | end 53 | % Now we note the other VP sets that contained the best 54 | % parent 55 | curCheckscore = curCheckscore(:,bestIndex); 56 | % These are the rows where we found a match and can 57 | % substitute in the current best parent 58 | substituteOtherParentIndex = otherParentIndices(find(curCheckscore)); 59 | if length(substituteOtherParentIndex) > 0 60 | parentVPs(substituteOtherParentIndex) = {{curCheckParents{bestIndex}}}; 61 | end 62 | parentVPsPass{checkCounter} = curCheckParents{bestIndex}; 63 | 64 | else 65 | % For the last entry, we do no comparison 66 | parentVPsPass{checkCounter} = curCheckParents{1}; 67 | end 68 | 69 | end 70 | edgeVPIDs = unique(parentVPsPass,'stable'); 71 | end -------------------------------------------------------------------------------- /QSPToolbox/cohort/utility/resamplePCASpace.m: -------------------------------------------------------------------------------- 1 | function myVPs = resamplePCASpace(myNeighborsAndSelf,myVPIndex,relStd,nChildren,outputBounds) 2 | % This function transform VPs into PCA space, resamples around the parent VP 3 | % according to their variance, and transforms the new VPs back. 4 | % 5 | % ARGUMENTS 6 | % myNeighborsAndSelf: matrix with VP of interest and neightbording VPs. 7 | % VPs are assumed to be column vectors. 8 | % myVPIndex: column index of "parent" VP to sample around 9 | % relStd: Relative scaling of standard deviation for sampling. The value 10 | % will be squared to scale the relative variance of resampling in 11 | % PCA space, which will also take into account the variance 12 | % of each principal component 13 | % nChildren: number of children VPs 14 | % outputBounds: an nAxis x 2 matrix of bounds on the output 15 | % values above or below will be truncated to this 16 | % value. 17 | % i.e. a matrix with rows [0 1] if the input is 18 | % normalized between 0 and 1. 19 | % 20 | % RETURNS 21 | % myVPs: VPs that have been resampled 22 | % 23 | [nDim,nParents] = size(myNeighborsAndSelf); 24 | myNeighborsAndSelf=myNeighborsAndSelf'; 25 | myMean = mean(myNeighborsAndSelf,1); 26 | myNeighborsAndSelf=myNeighborsAndSelf-mean(myNeighborsAndSelf,1); 27 | 28 | % Use MATLAB's function 29 | [eigenV,transData,varV,tsd,varN] = pca(myNeighborsAndSelf,'Algorithm','eig'); 30 | 31 | % Now that we have eigenVectors, transform just the VPs of interest 32 | transData = myNeighborsAndSelf(myVPIndex,:)*eigenV; 33 | 34 | % Sample in PCA space taking the eigenvalues and 35 | % relative scaling into consideration 36 | % reScale = 1/sqrt((2*pi())^nDim*sum(varV)); 37 | reScale = 1/sqrt(sum(varV)); 38 | transData=transData+reScale*mvnrnd(zeros(1,nDim),(relStd^2)*(varV.*eye(nDim)),nChildren); 39 | 40 | % Transform back 41 | myVPs = transData * (eigenV') + myMean; 42 | myVPs = myVPs'; 43 | [replaceRow,replaceCol] = find(myVPs < outputBounds(:,1)); 44 | replaceIndices = find(myVPs < outputBounds(:,1)); 45 | if ~isempty(replaceRow) 46 | myVPs(replaceIndices) = outputBounds(replaceRow,1); 47 | end 48 | [replaceRow,replaceCol] = find(myVPs > outputBounds(:,2)); 49 | replaceIndices = find(myVPs > outputBounds(:,2)); 50 | if ~isempty(replaceIndices) 51 | myVPs(replaceIndices) = outputBounds(replaceRow,2); 52 | end 53 | 54 | end 55 | -------------------------------------------------------------------------------- /QSPToolbox/cohort/utility/varyAxes.m: -------------------------------------------------------------------------------- 1 | function newWorksheet = varyAxes(oldWorksheet, myVaryAxesOptions) 2 | % Create a worksheet by varying selected VPs randomly along their 3 | % mechanistic axes. 4 | % 5 | % ARGUMENTS 6 | % oldWorksheet: Starting worksheet. Note the mechanistic axes must be 7 | % defined first before calling this function. 8 | % myVaryAxesOptions: Options for creating new VPs with the varied axes 9 | % 10 | % RETURNS 11 | % newWorksheet: Worksheet that incudes the base VPs and the new VPs 12 | % 13 | 14 | % First check whether sufficient input arguments are provided 15 | continueFlag = false; 16 | if nargin > 2 17 | warning(['Too many input arguments to ',mfilename, '. Arguments should be: oldWorksheet; and optionally: myVaryAxesOptions.']) 18 | continueFlag = false; 19 | elseif nargin > 1 20 | continueFlag = true; 21 | elseif nargin > 0 22 | myVaryAxesOptions = varyAxesOptions(); 23 | myVaryAxesOptions.baseVPIDs = getVPIDs(oldWorksheet); 24 | myVaryAxesOptions.varyAxisIDs = getAxisDefIDs(oldWorksheet); 25 | continueFlag = true; 26 | else 27 | warning(['Insufficient input arguments to ',mfilename, '. Arguments should be: oldWorksheet; and optionally: myVaryAxesOptions.']) 28 | end 29 | 30 | % Check whether the input arguments make sense 31 | if continueFlag 32 | passTestFlag = myVaryAxesOptions.verify(oldWorksheet); 33 | if ~passTestFlag 34 | continueFlag = false; 35 | end 36 | if length(myVaryAxesOptions.varyAxisIDs) < 1 37 | continueFlag = false; 38 | warning(['Must vary at least one axis in ',mfilename, '.']) 39 | end 40 | if length(myVaryAxesOptions.baseVPIDs) < 1 41 | continueFlag = false; 42 | warning(['Must select at least one base VP in ',mfilename, '.']) 43 | end 44 | end 45 | 46 | if continueFlag 47 | myBaseVPIDs = myVaryAxesOptions.baseVPIDs; 48 | % If we pass the checks, we can create the new worksheet and add the 49 | % VPs. 50 | newWorksheet = copyWorksheet(oldWorksheet, myBaseVPIDs, false); 51 | for vpCounter = 1 : length(myBaseVPIDs) 52 | subCallVaryOptions = myVaryAxesOptions; 53 | subCallVaryOptions.baseVPIDs = {myBaseVPIDs{vpCounter}}; 54 | newWorksheet = addVariedVPs(newWorksheet, subCallVaryOptions); 55 | end 56 | else 57 | warning(['Unable to run ',mfilename,', returning input worksheet.']) 58 | newWorksheet = oldWorksheet; 59 | end -------------------------------------------------------------------------------- /QSPToolbox/deprecationManagement/updateBinTableFormat.m: -------------------------------------------------------------------------------- 1 | function myUpdatedObject = updateBinTableFormat(myInputObject) 2 | % This is a function to update the bin tables from the old 3 | % format to the new one with allowed variable bin numbers. 4 | % The transition was made around in-house rev1043. 5 | % 6 | % ARGUMENTS: 7 | % myInputObject: A VPop, VPopRECIST, VPopRECISTnoBin, 8 | % mapelOptions, mapelOptionsRECIST, or 9 | % mapelOptionsRECISTnoBin object to convert. 10 | % 11 | % RETURNS: 12 | % myUpdatedObject A VPop, VPopRECIST, VPopRECISTnoBin, 13 | % mapelOptions, mapelOptionsRECIST, or 14 | % mapelOptionsRECISTnoBin object with 15 | % the new binTable. 16 | 17 | 18 | 19 | continueFlag = true; 20 | if nargin > 1 21 | continueFlag = false; 22 | warning(['Too many input arguments for ',mfilename,'. Should provide: a VPop, VPopRECIST, VPopRECISTnoBin, mapelOptions, mapelOptionsRECIST, or mapelOptionsRECISTnoBin.']) 23 | continueFlag = false; 24 | elseif nargin > 0 25 | continueFlag = true; 26 | else 27 | warning(['Insufficient input arguments for ',mfilename,'. Should provide: a VPop, VPopRECIST, VPopRECISTnoBin, mapelOptions, mapelOptionsRECIST, or mapelOptionsRECISTnoBin.']) 28 | continueFlag = false; 29 | end 30 | 31 | if ~(isa(myInputObject,'VPop') || isa(myInputObject,'VPopRECIST') || isa(myInputObject,'VPopRECISTnoBin') || isa(myInputObject,'mapelOptions') || isa(myInputObject,'mapelOptionsRECIST') || isa(myInputObject,'mapelOptionsRECISTnoBin')) 32 | warning(['Wrong input arguments for ',mfilename,'. Should provide: a VPop, VPopRECIST, VPopRECISTnoBin, mapelOptions, mapelOptionsRECIST, or mapelOptionsRECISTnoBin.']) 33 | continueFlag = false; 34 | end 35 | 36 | if continueFlag 37 | myUpdatedObject = myInputObject; 38 | if ~isempty(myInputObject.binTable) 39 | [nRows, nCols] = size(myInputObject.binTable); 40 | if (isa(myInputObject,'VPop') || isa(myInputObject,'mapelOptions')) 41 | referenceCol = 9; 42 | else 43 | referenceCol = 12; 44 | end 45 | myUpdateTable = myInputObject.binTable(:,1:referenceCol); 46 | binEdges = cell(nRows,1); 47 | expBins = cell(nRows,1); 48 | predBins = cell(nRows,1); 49 | for rowCounter = 1 : nRows 50 | curEdges = [myInputObject.binTable{rowCounter,'binEdge1'},myInputObject.binTable{rowCounter,'binEdge2'},myInputObject.binTable{rowCounter,'binEdge3'}]; 51 | curExpBins = [myInputObject.binTable{rowCounter,'expBin1'}, myInputObject.binTable{rowCounter,'expBin2'}, myInputObject.binTable{rowCounter,'expBin3'}, myInputObject.binTable{rowCounter,'expBin4'}]; 52 | curPredBins = [myInputObject.binTable{rowCounter,'predBin1'}, myInputObject.binTable{rowCounter,'predBin2'}, myInputObject.binTable{rowCounter,'predBin3'}, myInputObject.binTable{rowCounter,'predBin4'}]; 53 | binEdges{rowCounter} = curEdges; 54 | expBins{rowCounter} = curExpBins; 55 | predBins{rowCounter} = curPredBins; 56 | end 57 | myUpdateTable = [myInputObject.binTable(:,1:referenceCol), table(binEdges), myInputObject.binTable(:,'expN'), table(expBins), myInputObject.binTable(:,'predN'), table(predBins)]; 58 | myUpdatedObject.binTable = myUpdateTable; 59 | end 60 | end 61 | end -------------------------------------------------------------------------------- /QSPToolbox/deprecationManagement/updateTablesWithSubpopReference.m: -------------------------------------------------------------------------------- 1 | function myUpdatedObject = updateTablesWithSubpopReference(myInputObject) 2 | % This is a function to update the tables attached to mapelOptions 3 | % and VPop objects to include a row for the subpopulation index. 4 | % The transition was made around in-house rev1100. 5 | % 6 | % ARGUMENTS: 7 | % myInputObject: A VPop, VPopRECIST, VPopRECISTnoBin, 8 | % mapelOptions, mapelOptionsRECIST, or 9 | % mapelOptionsRECISTnoBin object to convert. 10 | % 11 | % RETURNS: 12 | % myUpdatedObject A VPop, VPopRECIST, VPopRECISTnoBin, 13 | % mapelOptions, mapelOptionsRECIST, or 14 | % mapelOptionsRECISTnoBin object with 15 | % the tables. 16 | 17 | continueFlag = true; 18 | if nargin > 1 19 | continueFlag = false; 20 | warning(['Too many input arguments for ',mfilename,'. Should provide: a VPop, VPopRECIST, mapelOptions, or mapelOptionsRECIST.']) 21 | continueFlag = false; 22 | elseif nargin > 0 23 | continueFlag = true; 24 | else 25 | warning(['Insufficient input arguments for ',mfilename,'. Should provide: a VPop, VPopRECIST, mapelOptions, or mapelOptionsRECIST.']) 26 | continueFlag = false; 27 | end 28 | 29 | if ~(isa(myInputObject,'VPop') || isa(myInputObject,'VPopRECIST') || isa(myInputObject,'mapelOptions') || isa(myInputObject,'mapelOptionsRECIST') ) 30 | warning(['Wrong input arguments for ',mfilename,'. Should provide: a VPop, VPopRECIST, mapelOptions, mapelOptionsRECIST.']) 31 | continueFlag = false; 32 | end 33 | 34 | myUpdatedObject = myInputObject; 35 | 36 | if continueFlag 37 | updateFlag = false; 38 | if isa(myInputObject, 'VPopRECIST') || isa(myInputObject, 'mapelOptionsRECIST') 39 | updateTables = {'expData','mnSDTable','binTable','distTable','distTable2D','corTable','brTableRECIST','rTableRECIST'}; 40 | elseif isa(myInputObject, 'VPop') || isa(myInputObject, 'mapelOptions') 41 | updateTables = {'expData','mnSDTable','binTable','distTable','distTable2D','corTable'}; 42 | end 43 | for tableCounter = 1:length(updateTables) 44 | curTable = myInputObject.(updateTables{tableCounter}); 45 | [nRows, nCols] = size(curTable); 46 | if nRows > 0 47 | curNames = curTable.Properties.VariableNames; 48 | if ~isequal(curNames{1},'subpopNo') 49 | newCol = num2cell(ones(nRows,1)); 50 | newCol = cell2table(newCol); 51 | newCol.Properties.VariableNames = {'subpopNo'}; 52 | curTable = [newCol,curTable]; 53 | updateFlag = true; 54 | myUpdatedObject.(updateTables{tableCounter}) = curTable; 55 | end 56 | end 57 | end 58 | if updateFlag 59 | warning(['Detected missing columns and added subpopNo columns to update the ',class(myInputObject),' tables to the new format. Note that you will have to manually add a subpopTable to the object, which can be created by calling createSubpopTable with the appropriate worksheet.']) 60 | end 61 | else 62 | warning(['Unable to run ',mfilename,'. Returning input object.']) 63 | end -------------------------------------------------------------------------------- /QSPToolbox/docs/Cheng_2017_AAPSJ.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BMSQSP/QSPToolbox/42cb4425292c5ecdf4954b6251346503746671d0/QSPToolbox/docs/Cheng_2017_AAPSJ.pdf -------------------------------------------------------------------------------- /QSPToolbox/examples/data/fluorescence_quench_internalization_data_n87_ab1.txt: -------------------------------------------------------------------------------- 1 | time_min time_hr time_day USUBJID internalized_pct internalized_fr 2 | 0 0 0 n87_140530_1 -1.1777 -0.0118 3 | 5 0.083333333 0.003472222 n87_140530_1 5.5553 0.0556 4 | 15 0.25 0.010416667 n87_140530_1 3.9869 0.0399 5 | 30 0.5 0.020833333 n87_140530_1 2.2115 0.0221 6 | 60 1 0.041666667 n87_140530_1 8.261 0.0826 7 | 180 3 0.125 n87_140530_1 14.7973 0.148 8 | 360 10 0.25 n87_140530_1 17.5534 0.1755 9 | 960 16 0.666666667 n87_140530_1 35.4818 0.3548 10 | 0 0 0 n87_140530_2 3.5562 0.0356 11 | 5 0.083333333 0.003472222 n87_140530_2 1.622 0.0162 12 | 15 0.25 0.010416667 n87_140530_2 -0.1189 -0.0012 13 | 30 0.5 0.020833333 n87_140530_2 1.7725 0.0177 14 | 60 1 0.041666667 n87_140530_2 -2.565 -0.0256 15 | 180 3 0.125 n87_140530_2 12.6384 0.1264 16 | 360 10 0.25 n87_140530_2 12.4294 0.1243 17 | 960 16 0.666666667 n87_140530_2 13.5016 0.135 18 | 0 0 0 n87_140530_3 -2.4715 -0.0247 19 | 5 0.083333333 0.003472222 n87_140530_3 6.5642 0.0656 20 | 15 0.25 0.010416667 n87_140530_3 1.3601 0.0136 21 | 30 0.5 0.020833333 n87_140530_3 3.0604 0.0306 22 | 60 1 0.041666667 n87_140530_3 8.0236 0.0802 23 | 180 3 0.125 n87_140530_3 7.1955 0.072 24 | 360 10 0.25 n87_140530_3 22.5344 0.2253 25 | 960 16 0.666666667 n87_140530_3 11.438 0.1144 26 | -------------------------------------------------------------------------------- /QSPToolbox/examples/data/xenograft_data_95305073_hep3b.txt: -------------------------------------------------------------------------------- 1 | USUBJID LESIONID time_day time_10delayed_day mouse_weight_kg HEP3B_xenograft_volume_L HEP3B_xenograft_weight_g dose_nmole accumulation_HEP3B_nmole_per_gram_tumor accumulation_HEP3B_nM 2 | 95305073_01 95305073_01_HEP3B 0 10 0.0234 7.20E-05 0.0756 0.398222222 . . 3 | 95305073_01 95305073_01_HEP3B 0.904861111 10.90486111 . . . . 0.028533658 29.96034139 4 | 95305073_01 95305073_01_HEP3B 3.946527778 13.94652778 . . . . 0.019360283 20.32829666 5 | 95305073_01 95305073_01_HEP3B 4.985416667 14.98541667 . . . . 0.015274073 16.03777657 6 | 95305073_01 95305073_01_HEP3B 5.954166667 15.95416667 . . . . 0.014487834 15.21222525 7 | 95305073_01 95305073_01_HEP3B 6.842361111 16.84236111 . . . . 0.012779208 13.41816843 8 | 95305073_02 95305073_02_HEP3B 0 10 0.0231 0.000275 0.28875 0.384 . . 9 | 95305073_02 95305073_02_HEP3B 0.904861111 10.90486111 . . . . 0.021093635 22.14831705 10 | 95305073_02 95305073_02_HEP3B 3.946527778 13.94652778 . . . . 0.012500204 13.1252146 11 | 95305073_02 95305073_02_HEP3B 4.985416667 14.98541667 . . . . 0.010634318 11.16603431 12 | 95305073_02 95305073_02_HEP3B 5.954166667 15.95416667 . . . . 0.009731509 10.21808438 13 | 95305073_02 95305073_02_HEP3B 6.842361111 16.84236111 . . . . 0.009094142 9.5488486 14 | -------------------------------------------------------------------------------- /QSPToolbox/examples/data/xenograft_data_95305073_n87.txt: -------------------------------------------------------------------------------- 1 | USUBJID LESIONID time_day time_10delayed_day mouse_weight_kg N87_xenograft_volume_L N87_xenograft_weight_g dose_nmole accumulation_N87_nmole_per_gram_tumor accumulation_N87_nM 2 | 95305073_01 95305073_01_N87 0 10 0.0234 0.000275 0.28875 0.398222222 . . 3 | 95305073_01 95305073_01_N87 0.904861111 10.90486111 . . . . 0.043004686 45.15492015 4 | 95305073_01 95305073_01_N87 3.946527778 13.94652778 . . . . 0.036532076 38.35867968 5 | 95305073_01 95305073_01_N87 4.985416667 14.98541667 . . . . 0.031291797 32.85638648 6 | 95305073_01 95305073_01_N87 5.954166667 15.95416667 . . . . 0.028603717 30.03390327 7 | 95305073_01 95305073_01_N87 6.842361111 16.84236111 . . . . 0.027529224 28.90568513 8 | 95305073_02 95305073_02_N87 0 10 0.0231 0.000144 0.1512 0.384 . . 9 | 95305073_02 95305073_02_N87 0.904861111 10.90486111 . . . . 0.042124625 44.23085675 10 | 95305073_02 95305073_02_N87 3.946527778 13.94652778 . . . . 0.032647504 34.27987931 11 | 95305073_02 95305073_02_N87 4.985416667 14.98541667 . . . . 0.028955969 30.40376693 12 | 95305073_02 95305073_02_N87 5.954166667 15.95416667 . . . . 0.023960432 25.1584534 13 | 95305073_02 95305073_02_N87 6.842361111 16.84236111 . . . . 0.023771687 24.96027157 14 | -------------------------------------------------------------------------------- /QSPToolbox/examples/miscellaneous/adc_platform_public_v0p15p1.sbproj: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BMSQSP/QSPToolbox/42cb4425292c5ecdf4954b6251346503746671d0/QSPToolbox/examples/miscellaneous/adc_platform_public_v0p15p1.sbproj -------------------------------------------------------------------------------- /QSPToolbox/examples/miscellaneous/calculateGFunctionSi.m: -------------------------------------------------------------------------------- 1 | function [mySi,mySTi] = calculateGFunctionSi(aimatrix) 2 | % A simple function to calculate the analytical solutions for 3 | % first order (Si) and total (STi) sensitivity indices in 4 | % Sobol's G function, 5 | % given an nAi X 1 matrix of ai values 6 | % See: 7 | % Saltelli, A., et al. (2009). "Global Sensitivity Analysis: The Primer." 8 | % p. 123-125 for the analytical sensitivity index calculation. 9 | % 10 | % ARGUMENTS: 11 | % aimatrix 12 | % 13 | % RETURNS: 14 | % mySi 15 | % mySTi 16 | 17 | nAi = length(aimatrix); 18 | % vi is the variance in term 19 | vi = zeros(nAi,1); 20 | for curAiCounter = 1 : nAi 21 | vi(curAiCounter) = 1/(3*(1+aimatrix(curAiCounter))^2); 22 | end 23 | 24 | % We also calculat the total variances 25 | vti = zeros(nAi,1); 26 | for curAiCounter = 1 : nAi 27 | vti(curAiCounter) = vi(curAiCounter); 28 | for hotCounter = 2 : nAi 29 | curCombs = combnk([1:nAi],hotCounter); 30 | combFinder = (curCombs == curAiCounter); 31 | combFinder = find(sum(combFinder,2)>0); 32 | curCombs = curCombs(combFinder,:); 33 | [nRows, nCols] = size(curCombs); 34 | curTerm = 0; 35 | for curRow = 1 : nRows 36 | tempTerm = 1; 37 | for curCol = 1 : nCols 38 | tempTerm = tempTerm * vi(curCombs(curRow,curCol)); 39 | end 40 | curTerm = curTerm + tempTerm; 41 | end 42 | vti(curAiCounter) = vti(curAiCounter) + curTerm; 43 | end 44 | end 45 | 46 | vProd = 1; 47 | for i = 1 : nAi 48 | vProd = vProd * (1 + vi(i)); 49 | end 50 | 51 | vTot = -1 + vProd; 52 | 53 | mySi = vi / vTot; 54 | mySTi = vti / vTot; 55 | 56 | end -------------------------------------------------------------------------------- /QSPToolbox/examples/miscellaneous/example_cohort_worksheet1.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BMSQSP/QSPToolbox/42cb4425292c5ecdf4954b6251346503746671d0/QSPToolbox/examples/miscellaneous/example_cohort_worksheet1.mat -------------------------------------------------------------------------------- /QSPToolbox/examples/miscellaneous/example_intervention_file.txt: -------------------------------------------------------------------------------- 1 | ID culture_internalization buffer_injection_1200147_shed_assay antibody_injection_1200147_shed_assay agxab1pet_injection 2 | VARIANT cellular_disposition_payload___inert_disable_export initialization___10_day initialization___10_day initialization___10_day 3 | VARIANT tumor_pd___n87_culture_no_growth initial_masses___1200147_buffer_n87_body_mass_only initial_masses___1200147_ab1_n87_body_mass_only initial_masses___agxab1pet_95305073_n87_body_mass_only 4 | VARIANT linker_and_payload_chemistry___stable dosing_duration___ip_mouse_as_iv_infusion tumor_transport_settings_payload___null 5 | VARIANT fixed_lesion_characteristics___culture payload_adcc_effect_switches___activate_adcc_day_11 6 | VARIANT initialization___0_day 7 | VARIANT prebound_adc___all_1a 8 | VARIANT initial_masses___culture 9 | VARIANT tumor_transport_settings_payload___null 10 | DOSE antibody_injection_1200147_shed_assay agxab1_pet_20140711_avg 11 | -------------------------------------------------------------------------------- /QSPToolbox/examples/miscellaneous/example_vp_file.txt: -------------------------------------------------------------------------------- 1 | ID n87_xenograft_scenario_0006 2 | VARIANT molecular_and_plasma_pk_parameters_payload___null 3 | VARIANT molecular_and_plasma_pk_parameters_antibody___bmsaaaaaa_agxadc_mouse 4 | VARIANT tumor_transport_settings_payload___permeation_only 5 | VARIANT tumor_transport_settings_antibody___permeation_only 6 | VARIANT cellular_disposition_payload___secrete_and_degrade_150901_scenario_6 7 | VARIANT tumor_pd___bmsaaaaaa_n87_xenograft_1200115_control_estimate_150901_1200147_n87_ab1_adcc_death_effect 8 | VARIANT linker_and_payload_chemistry___stable 9 | VARIANT antigen_antibody_binding___ab1_agx_bivalent 10 | VARIANT fixed_lesion_characteristics___bmsaaaaaa_agxab1pet_95305073_150901_scenario_6_fg_alt 11 | VARIANT cellular_disposition_antibody___ab1_n87_estimate_150901_shedding_alt 12 | VARIANT antigen_shedding_and_transport___agx_a431h9_murine_xenograft_alt_tumor_degradation_no_peripheral_dissociation 13 | VARIANT initialization___10_day 14 | VARIANT size_dependent_clearance___null 15 | VARIANT prebound_adc___none 16 | VARIANT variable_shedding___off 17 | VARIANT tumor_transport_settings_shed___permeation_only 18 | VARIANT initial_masses___agxab1pet_95305073_n87 19 | VARIANT dosing_duration___iv_bolus 20 | VARIANT payload_adcc_effect_switches___off 21 | -------------------------------------------------------------------------------- /QSPToolbox/examples/miscellaneous/example_vpop.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BMSQSP/QSPToolbox/42cb4425292c5ecdf4954b6251346503746671d0/QSPToolbox/examples/miscellaneous/example_vpop.mat -------------------------------------------------------------------------------- /QSPToolbox/examples/miscellaneous/gfunction_test.sbproj: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BMSQSP/QSPToolbox/42cb4425292c5ecdf4954b6251346503746671d0/QSPToolbox/examples/miscellaneous/gfunction_test.sbproj -------------------------------------------------------------------------------- /QSPToolbox/external/compare_correlation_coefficients/compare_correlation_coefficients.m: -------------------------------------------------------------------------------- 1 | % This function compare if two correlation coefficients are significantly 2 | % different. 3 | % The correlation coefficients were tansfered to z scores using fisher's r 4 | % to z transformation. 5 | % ref: http://core.ecu.edu/psyc/wuenschk/docs30/CompareCorrCoeff.pdf 6 | %-------------------------------------------------------------------------- 7 | % Inputs: (1) r1: correlation coefficient of the first correlation (2) r2: 8 | % correlation coefficient of the second correlation (3) n1: number of 9 | % samples used to compute the first correlation (4) n2: number of samples 10 | % used to compute the second correlation 11 | %-------------------------------------------------------------------------- 12 | % Output: (1) p: p value, the probability that H0 (the correlation 13 | % coefficiets are not different) is correct 14 | %-------------------------------------------------------------------------- 15 | % Example : 16 | % x = rand(20,1); 17 | % y1= x+rand(20,1)*0.05; 18 | % y2= x+rand(20,1)*0.5; 19 | % r1=corr(x,y1); 20 | % r1=corr(x,y2); 21 | % p = compare_correlation_coefficients(r1,r2,length(x),length(x)); 22 | %-------------------------------------------------------------------------- 23 | function p = compare_correlation_coefficients(r1,r2,n1,n2) 24 | t_r1 = 0.5*log((1+r1)/(1-r1)); 25 | t_r2 = 0.5*log((1+r2)/(1-r2)); 26 | z = (t_r1-t_r2)/sqrt(1/(n1-3)+1/(n2-3)); 27 | p = (1-normcdf(abs(z),0,1))*2; 28 | end -------------------------------------------------------------------------------- /QSPToolbox/external/compare_correlation_coefficients/license.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2013, Sisi Ma 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are 6 | met: 7 | 8 | * Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | * Redistributions in binary form must reproduce the above copyright 11 | notice, this list of conditions and the following disclaimer in 12 | the documentation and/or other materials provided with the distribution 13 | 14 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 15 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 18 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 19 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 20 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 21 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 22 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 23 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24 | POSSIBILITY OF SUCH DAMAGE. 25 | -------------------------------------------------------------------------------- /QSPToolbox/external/genpath_exclude/genpath_exclude.m: -------------------------------------------------------------------------------- 1 | % pathStr = genpath_exclude(basePath,ignoreDirs) 2 | % 3 | % Extension of Matlab's "genpath" function, except this will exclude 4 | % directories (and their sub-tree) given by "ignoreDirs". 5 | % 6 | % 7 | % 8 | % Inputs: 9 | % basePath: string. The base path for which to generate path string. 10 | % 11 | % excludeDirs: cell-array of strings. all directory names to ignore. Note, 12 | % these strings are passed into regexp surrounded by 13 | % '^' and '$'. If your directory name contains special 14 | % characters to regexp, they must be escaped. For example, 15 | % use '\.svn' to ignore ".svn" directories. You may also 16 | % use regular expressions to ignore certian patterns. For 17 | % example, use '*._ert_rtw' to ignore all directories ending 18 | % with "_ert_rtw". 19 | % 20 | % Outputs: 21 | % pathStr: string. semicolon delimited string of paths. (see genpath) 22 | % 23 | % See also genpath 24 | % 25 | % ---CVS Keywords---- 26 | % $Author: jhopkin $ 27 | % $Date: 2009/10/27 19:06:19 $ 28 | % $Name: $ 29 | % $Revision: 1.5 $ 30 | 31 | % $Log: genpath_exclude.m,v $ 32 | % Revision 1.6 2020/11/26 19:06:19 bjs 33 | % Exclude MATLAB "package" directories, "+" 34 | % 35 | % Revision 1.5 2009/10/27 19:06:19 jhopkin 36 | % fixed regexp handling. added more help comments 37 | % 38 | % Revision 1.4 2008/11/25 19:04:29 jhopkin 39 | % minor cleanup. Made input more robust so that if user enters a string as 'excudeDir' rather than a cell array of strings this function will still work. (did this by moving the '^' and '$' to surround the entire regexp string, rather than wrapping them around each "excludeDir") 40 | % 41 | % Revision 1.3 2008/11/25 18:43:10 jhopkin 42 | % added help comments 43 | % 44 | % Revision 1.1 2008/11/22 00:23:01 jhopkin 45 | % *** empty log message *** 46 | % 47 | 48 | function p = genpath_exclude(d,excludeDirs) 49 | % if the input is a string, then use it as the searchstr 50 | if ischar(excludeDirs) 51 | excludeStr = excludeDirs; 52 | else 53 | excludeStr = ''; 54 | if ~iscellstr(excludeDirs) 55 | error('excludeDirs input must be a cell-array of strings'); 56 | end 57 | 58 | for i = 1:length(excludeDirs) 59 | excludeStr = [excludeStr '|^' excludeDirs{i} '$']; 60 | end 61 | end 62 | 63 | 64 | % Generate path based on given root directory 65 | files = dir(d); 66 | if isempty(files) 67 | return 68 | end 69 | 70 | % Add d to the path even if it is empty. 71 | p = [d pathsep]; 72 | 73 | % set logical vector for subdirectory entries in d 74 | isdir = logical(cat(1,files.isdir)); 75 | % 76 | % Recursively descend through directories which are neither 77 | % private nor "class" directories. 78 | % 79 | dirs = files(isdir); % select only directory entries from the current listing 80 | 81 | for i=1:length(dirs) 82 | dirname = dirs(i).name; 83 | %NOTE: regexp ignores '.', '..', '@.*', and 'private' directories by default. 84 | if ~any(regexp(dirname,['^\.$|^\.\.$|^\@.*|^\+.*|^private$|^resources$|' excludeStr ],'start')) 85 | p = [p genpath_exclude(fullfile(d,dirname),excludeStr)]; % recursive calling of this function. 86 | end 87 | end 88 | end 89 | -------------------------------------------------------------------------------- /QSPToolbox/external/genpath_exclude/license.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2009, Jesse Hopkins 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are 6 | met: 7 | 8 | * Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | * Redistributions in binary form must reproduce the above copyright 11 | notice, this list of conditions and the following disclaimer in 12 | the documentation and/or other materials provided with the distribution 13 | 14 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 15 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 18 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 19 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 20 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 21 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 22 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 23 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24 | POSSIBILITY OF SUCH DAMAGE. 25 | -------------------------------------------------------------------------------- /QSPToolbox/external/herrorbar/license.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2009, Jos van der Geest 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are 6 | met: 7 | 8 | * Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | * Redistributions in binary form must reproduce the above copyright 11 | notice, this list of conditions and the following disclaimer in 12 | the documentation and/or other materials provided with the distribution 13 | 14 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 15 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 18 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 19 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 20 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 21 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 22 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 23 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24 | POSSIBILITY OF SUCH DAMAGE. 25 | -------------------------------------------------------------------------------- /QSPToolbox/external/kstest_2s_2d/license.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2017, Dylan Muir 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are 6 | met: 7 | 8 | * Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | * Redistributions in binary form must reproduce the above copyright 11 | notice, this list of conditions and the following disclaimer in 12 | the documentation and/or other materials provided with the distribution 13 | 14 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 15 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 18 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 19 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 20 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 21 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 22 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 23 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24 | POSSIBILITY OF SUCH DAMAGE. 25 | -------------------------------------------------------------------------------- /QSPToolbox/external/kstest_2s_2d/quadrantCount.m: -------------------------------------------------------------------------------- 1 | function quadrantChecks = quadrantCount(x1, x2) 2 | % This function is roughly a 2D equivalent to creating the comparison grid for the 3 | % 1D KS test. Here, all of the quadrant comparisons are run for each point in 4 | % x1 as a reference against x2 5 | % 6 | % Arguments 7 | % x1: 2xN1 matrix of reference points 8 | % x2: 2xN2 matrix of reference points 9 | % 10 | % Returns 11 | % quadrantChecks N1x(4 quadrants * N2) 12 | % matrix of binary comparisons 13 | 14 | [~,nsample1] = size(x1); 15 | [~,nsample2] = size(x2); 16 | 17 | % - A function handle to perform comparisons in all possible directions 18 | pointCompare = @(x, point)([((x(1,:) > point(1)) & (x(2,:) > point(2))),... 19 | ((x(1, :) <= point(1)) & (x(2, :) > point(2))),... 20 | ((x(1, :) <= point(1)) & (x(2, :) <= point(2))),... 21 | ((x(1, :) > point(1)) & (x(2, :) <= point(2)))]); 22 | 23 | quadrantChecks = false(nsample1,4*nsample2); 24 | for j = 1:(nsample1) 25 | point = x1(:,j); 26 | quadrantChecks(j,:) = pointCompare(x2, point); 27 | end 28 | 29 | 30 | -------------------------------------------------------------------------------- /QSPToolbox/external/myfisher/README.md: -------------------------------------------------------------------------------- 1 | # myfisher 2 | Fisher's Exact Probability Test for a RxC matrix.
3 | Fisher's exact test permits calculation of precise probabilities in situation 4 | where, as a consequence of small cell frequencies, the much more rapid normal 5 | approximation and chi-square calculations are liable to be inaccurate. 6 | The Fisher's exact test involves the computations of several factorials 7 | to obtain the probability of the observed and each of the more extreme tables. 8 | Factorials growth quickly, so it's necessary use logarithms of factorials. 9 | This computations is very easy in Matlab because: 10 | x!=gamma(x+1) and log(x!)=gammaln(x+1). 11 | Moreover, when the matrix has many Rows and Columns, the computation of all the 12 | set of possible matrices is very time expensive. 13 | This function uses this strategy: 14 | 1) if the input is a 2x2, 2x3, 2x4 or 3x3 matrix it uses (or download) ad hoc, 15 | previously written by me, function; 16 | 2) else it uses a Monte Carlo approach. 17 | Finally, this function uses the Peter J. Acklam rldecode function, and so I 18 | want to acknowledge him. 19 | 20 | Created by Giuseppe Cardillo 21 | giuseppe.cardillo-edta@poste.it 22 | 23 | To cite this file, this would be an appropriate format: 24 | Cardillo G. (2010) MyFisher: the definitive function for the Fisher's exact 25 | and conditional test for any RxC matrix 26 | http://www.mathworks.com/matlabcentral/fileexchange/26883 27 | -------------------------------------------------------------------------------- /QSPToolbox/external/myfisher22/README.md: -------------------------------------------------------------------------------- 1 | # myfisher22 2 | Fisher's exact test onto a 2x2 matrix
3 | Fisher's exact test of 2x2 contingency tables permits calculation of 4 | precise probabilities in situation where, as a consequence of small cell 5 | frequencies, the much more rapid normal approximation and chi-square 6 | calculations are liable to be inaccurate. The Fisher's exact test involves 7 | the computations of several factorials to obtain the probability of the 8 | observed and each of the more extreme tables. Factorials growth quickly, 9 | so it's necessary use logarithms of factorials. This computations is very 10 | easy in Matlab because x!=gamma(x+1) and log(x!)=gammaln(x+1). This 11 | function is fully vectorized to speed up the computation. 12 | The routine coumputes the Power and, if necessary, the sample sizes needed 13 | to achieve a power=0.80 using a modified asymptotic normal method with 14 | continuity correction as described by Hardeo Sahai and Anwer Khurshid in 15 | Statistics in Medicine, 1996, Vol. 15, Issue 1: 1-21. 16 | 17 | Syntax: myfisher22(x,alpha,plts) 18 | 19 | Inputs: 20 | X - 2x2 data matrix 21 | ALPHA - significance level (default = 0.05). 22 | PLTS - Flag to set if you don't want (0) or want (1) view the plot 23 | of Wald Statistics distribution (default=0) 24 | Outputs: 25 | - Three p-values 26 | - Power and sample sizes 27 | 28 | Created by Giuseppe Cardillo 29 | giuseppe.cardillo-edta@poste.it 30 | 31 | To cite this file, this would be an appropriate format: 32 | Cardillo G. (2007) MyFisher22: a very compact routine for Fisher's exact 33 | test on 2x2 matrix 34 | http://www.mathworks.com/matlabcentral/fileexchange/15434 35 | -------------------------------------------------------------------------------- /QSPToolbox/external/myfisher23/README.md: -------------------------------------------------------------------------------- 1 | # myfisher23 2 | Fisher's Exact Probability Test on 2x3 matrix.
3 | Fisher's exact test of 2x3 contingency tables permits calculation of 4 | precise probabilities in situation where, as a consequence of small cell 5 | frequencies, the much more rapid normal approximation and chi-square 6 | calculations are liable to be inaccurate. The Fisher's exact test involves 7 | the computations of several factorials to obtain the probability of the 8 | observed and each of the more extreme tables. Factorials growth quickly, 9 | so it's necessary use logarithms of factorials. This computations is very 10 | easy in Matlab because x!=gamma(x+1) and log(x!)=gammaln(x+1). This 11 | function is fully vectorized to speed up the computation. 12 | 13 | Syntax: p=myfisher23(x) 14 | 15 | Inputs: 16 | X - 2x3 data matrix 17 | Outputs: 18 | - Three p-values 19 | 20 | Created by Giuseppe Cardillo 21 | giuseppe.cardillo-edta@poste.it 22 | 23 | To cite this file, this would be an appropriate format: 24 | Cardillo G. (2007) MyFisher23: a very compact routine for Fisher's exact 25 | test on 2x3 matrix 26 | http://www.mathworks.com/matlabcentral/fileexchange/15399 27 | -------------------------------------------------------------------------------- /QSPToolbox/external/myfisher24/license.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2008, Giuseppe Cardillo 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are 6 | met: 7 | 8 | * Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | * Redistributions in binary form must reproduce the above copyright 11 | notice, this list of conditions and the following disclaimer in 12 | the documentation and/or other materials provided with the distribution 13 | 14 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 15 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 18 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 19 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 20 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 21 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 22 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 23 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24 | POSSIBILITY OF SUCH DAMAGE. 25 | -------------------------------------------------------------------------------- /QSPToolbox/external/nnls/Readme.txt: -------------------------------------------------------------------------------- 1 | nnls - Alternative to lsqnonneg: can be faster on large problems, 2 | improved convergence control, optional restart vector 3 | 4 | Solves non negative least squares: 5 | min wrt x: (d-Cx)'*(d-Cx) subject to: x>=0 6 | 7 | This version of nnls aims to solve convergance problems that can occur 8 | with the 2011-2012 version of lsqnonneg, and provides a fast solution of 9 | large problems. Includes an option to give initial positive terms for x 10 | for faster solution of iterative problems using nnls. 11 | 12 | For some large problems nnls can be faster than lsqnonneg, 13 | see test file (nnlstest.m). 14 | 15 | 16 | Simple usage: x=nnls(C,d) 17 | 18 | [x,w,info]=nnls(C,d,opts) 19 | C Coefficient matrix 20 | d Rhs vector 21 | opts Struct containing options: (optional) 22 | .Accy 0 fast version, 1 refines final value (default), 23 | 2 uses accurate steps but very slow on large cases, 24 | faster on small cases, result usually identical to 1 25 | .Order True or [], or order to initially include positive terms 26 | if included will supply info.Order, if x0 available use 27 | find(x0>0), but best saved from previous run of nnls 28 | .Tol Tolerance test value, default zero, use multiple of eps 29 | .Iter Maximum number of iterations, should not be needed. 30 | 31 | x Positive solution vector x>=0 32 | w Lagrange multiplier vector w(x==0)<= approx zero 33 | info Struct with extra information: 34 | .iter Number of iterations used 35 | .wsc0 Estimated size of errors in w 36 | .wsc Maximum of test values for w 37 | .Order Order variables used, use to restart nnls with opts.Order 38 | 39 | Examples in nnlstest.m 40 | -------------------------------------------------------------------------------- /QSPToolbox/external/nnls/license.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2012, Bill Whiten 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are 6 | met: 7 | 8 | * Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | * Redistributions in binary form must reproduce the above copyright 11 | notice, this list of conditions and the following disclaimer in 12 | the documentation and/or other materials provided with the distribution 13 | 14 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 15 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 18 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 19 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 20 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 21 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 22 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 23 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24 | POSSIBILITY OF SUCH DAMAGE. 25 | -------------------------------------------------------------------------------- /QSPToolbox/external/weightedcorrs/license.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2008, Liber Eleutherios 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are 6 | met: 7 | 8 | * Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | * Redistributions in binary form must reproduce the above copyright 11 | notice, this list of conditions and the following disclaimer in 12 | the documentation and/or other materials provided with the distribution 13 | 14 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 15 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 18 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 19 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 20 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 21 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 22 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 23 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24 | POSSIBILITY OF SUCH DAMAGE. 25 | -------------------------------------------------------------------------------- /QSPToolbox/external/weightedcorrs/weightedcorrs.m: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BMSQSP/QSPToolbox/42cb4425292c5ecdf4954b6251346503746671d0/QSPToolbox/external/weightedcorrs/weightedcorrs.m -------------------------------------------------------------------------------- /QSPToolbox/initQSPToolbox.m: -------------------------------------------------------------------------------- 1 | function initQSPtoolbox() 2 | % Initialize Quantiative Systems Pharmacology Toolbox. This script should 3 | % be run from the command line when you want to start using the toolbox. 4 | % ARGUMENTS 5 | % None 6 | % 7 | % RETURNS 8 | % None 9 | % 10 | 11 | % Get the toolbox directory 12 | rootPath=which('initQSPToolbox.m'); 13 | global QSPTDIR 14 | QSPTDIR = rootPath(1:end-(length('initQSPToolbox.m')+1)); 15 | 16 | % Add QSP toolbox paths 17 | path(path,[QSPTDIR, filesep, 'external',filesep,'genpath_exclude']); 18 | myPaths = genpath_exclude(QSPTDIR,{'docs','\.svn'}); 19 | if (~isdeployed) 20 | addpath(myPaths); 21 | end 22 | -------------------------------------------------------------------------------- /QSPToolbox/io/loadMapelOptions.m: -------------------------------------------------------------------------------- 1 | function myMapelOptions = loadMapelOptions(myFileName, myPath, myFormat) 2 | % Load a mapelOptions object from file. 3 | % 4 | % ARGUMENTS 5 | % fileName: a filename, suffix will be appended based on format 6 | % path: (optional) save file path 7 | % format: (optional)save file format, currently only support 'mat' 8 | % 9 | % RETURNS 10 | % myMapelOptions 11 | % 12 | 13 | % Perform initial checks on the provided arguments 14 | flagContinue = true; 15 | if nargin > 3 16 | warning(['Too many arguments provided to ',mfilename,', require: fileName, and optionally path, format.']) 17 | flagContinue = false; 18 | elseif nargin > 2 19 | flagContinue = true; 20 | elseif nargin > 1 21 | myFormat = 'mat'; 22 | flagContinue = true; 23 | elseif nargin > 0 24 | myPath = ''; 25 | flagContinue = true; 26 | myFormat = 'mat'; 27 | else 28 | warning(['Insufficient arguments provided to ',mfilename,', require: fileName, and optionally path, format.']) 29 | flagContinue = false; 30 | end 31 | myMapelOptions = mapelOptions; 32 | 33 | if flagContinue 34 | if ~(sum(ismember({'mat'},lower(myFormat))) == 1) 35 | warning(['Unsupported file format specified in ',mfilename,'. Support: "mat".']) 36 | flagContinue = false; 37 | else 38 | myFormat = lower(myFormat); 39 | % This doesn't need to be specified for load 40 | % saveVersion = '-v7.3'; 41 | end 42 | end 43 | 44 | if flagContinue 45 | if strcmp('mat', myFormat) 46 | fullFileName = [myPath,myFileName,'.',myFormat]; 47 | myMapelOptions = load(fullFileName, '-mat'); 48 | myMapelOptions = myMapelOptions.myMapelOptions; 49 | myMapelOptions = checkUpdateObjectVersion(myMapelOptions); 50 | end 51 | else 52 | warning('Unable to load in ',mfilename,'. Returning a blank mapelOptions.') 53 | end 54 | end 55 | -------------------------------------------------------------------------------- /QSPToolbox/io/loadVPop.m: -------------------------------------------------------------------------------- 1 | function myVPop = loadVPop(myFileName, myPath, myFormat) 2 | % Load a virtual population from file. 3 | % 4 | % ARGUMENTS 5 | % fileName: a filename, suffix will be appended based on format 6 | % path: (optional) save file path 7 | % format: (optional)save file format, currently only support 'mat' 8 | % 9 | % RETURNS 10 | % myVPop 11 | % 12 | 13 | % Perform initial checks on the provided arguments 14 | flagContinue = true; 15 | if nargin > 3 16 | warning(['Too many arguments provided to ',mfilename,', require: fileName, and optionally path, format.']) 17 | flagContinue = false; 18 | elseif nargin > 2 19 | flagContinue = true; 20 | elseif nargin > 1 21 | myFormat = 'mat'; 22 | flagContinue = true; 23 | elseif nargin > 0 24 | myPath = ''; 25 | flagContinue = true; 26 | myFormat = 'mat'; 27 | else 28 | warning(['Insufficient arguments provided to ',mfilename,', require: fileName, and optionally path, format.']) 29 | flagContinue = false; 30 | end 31 | myVPop = VPop; 32 | 33 | if flagContinue 34 | if ~(sum(ismember({'mat'},lower(myFormat))) == 1) 35 | warning(['Unsupported file format specified in ',mfilename,'. Support: "mat".']) 36 | flagContinue = false; 37 | else 38 | myFormat = lower(myFormat); 39 | % This doesn't need to be specified for load 40 | % saveVersion = '-v7.3'; 41 | end 42 | end 43 | 44 | if flagContinue 45 | if strcmp('mat', myFormat) 46 | fullFileName = [myPath,myFileName,'.',myFormat]; 47 | myVPop = load(fullFileName, '-mat'); 48 | myVPop = myVPop.myVPop; 49 | myVPop = checkUpdateObjectVersion(myVPop); 50 | end 51 | else 52 | warning('Unable to load in ',mfilename,'. Returning a blank VPop.') 53 | end 54 | end 55 | -------------------------------------------------------------------------------- /QSPToolbox/io/loadWorksheetAutoMerge.m: -------------------------------------------------------------------------------- 1 | function myWorksheet = loadWorksheetAutoMerge(myFileName, myPath, myFormat) 2 | % Load a worksheet to file. 3 | % 4 | % ARGUMENTS 5 | % fileName: a filename, suffix will be appended based on format 6 | % path: (optional) save file path 7 | % format: (optional)save file format, currently only support 'mat' 8 | % 9 | % RETURNS 10 | % myWorksheet 11 | % 12 | 13 | % Perform initial checks on the provided arguments 14 | flagContinue = true; 15 | if nargin > 3 16 | warning(['Too many arguments provided to ',mfilename,', require: fileName, and optionally path, format.']) 17 | flagContinue = false; 18 | elseif nargin > 2 19 | flagContinue = true; 20 | elseif nargin > 1 21 | myFormat = 'mat'; 22 | flagContinue = true; 23 | elseif nargin > 0 24 | myPath = ''; 25 | flagContinue = true; 26 | myFormat = 'mat'; 27 | else 28 | warning(['Insufficient arguments provided to ',mfilename,', require: fileName, and optionally path, format.']) 29 | flagContinue = false; 30 | end 31 | %myWorksheet = createWorksheet(); 32 | 33 | if flagContinue 34 | if ~(sum(ismember({'mat'},lower(myFormat))) == 1) 35 | warning(['Unsupported file format specified in ',mfilename,'. Support: "mat".']) 36 | flagContinue = false; 37 | else 38 | myFormat = lower(myFormat); 39 | % saveVersion doesn't need to be specified for load 40 | end 41 | end 42 | 43 | if flagContinue 44 | if strcmp('mat', myFormat) 45 | checkFiles = 0; 46 | checkFileName = [myPath,[myFileName,'___',num2str(checkFiles+1)],'.',myFormat]; 47 | while exist(checkFileName,'file') == 2 48 | checkFiles = checkFiles + 1; 49 | checkFileName = [myPath,[myFileName,'___',num2str(checkFiles+1)],'.',myFormat]; 50 | end 51 | if checkFiles>0 52 | myWorksheet = loadWorksheet([myFileName,'___',num2str(1)], myPath, myFormat); 53 | for splitCounter=2:(checkFiles) 54 | curWorksheet = loadWorksheet([myFileName,'___',num2str(splitCounter)], myPath, myFormat); 55 | myWorksheet=mergeWorksheets(myWorksheet,curWorksheet); 56 | end 57 | else 58 | myWorksheet = loadWorksheet(myFileName, myPath, myFormat); 59 | end 60 | end 61 | else 62 | warning(['Unable to load in ',mfilename,'. Returning an empty worksheet.']) 63 | end 64 | end 65 | -------------------------------------------------------------------------------- /QSPToolbox/io/saveMapelOptions.m: -------------------------------------------------------------------------------- 1 | function saveMapelOptions(myMapelOptions,myFileName, myFormat, myPath) 2 | % Save a mapelOptions object to file. 3 | % 4 | % ARGUMENTS 5 | % myMapelOptions: a mapelOptions object 6 | % fileName: a filename, suffix will be appended based on format 7 | % format: (optional)save file format, currently only support 'mat' 8 | % path: (optional) save file path 9 | % 10 | % RETURNS 11 | % nothing 12 | % 13 | 14 | % Perform initial checks on the provided arguments 15 | flagContinue = true; 16 | if nargin > 4 17 | warning(['Too many arguments provided to ',mfilename,', require: myMapelOptions, fileName, and optionally format, path.']) 18 | flagContinue = false; 19 | elseif nargin > 3 20 | flagContinue = true; 21 | elseif nargin > 2 22 | myPath = ''; 23 | flagContinue = true; 24 | elseif nargin > 1 25 | myPath = ''; 26 | flagContinue = true; 27 | myFormat = 'mat'; 28 | else 29 | warning(['Insufficient arguments provided to ',mfilename,', require: myMapelOptions, fileName, and optionally format, path.']) 30 | flagContinue = false; 31 | end 32 | 33 | % Create the new worksheet and verify the IDs 34 | if flagContinue 35 | if ~(sum(ismember({'mat'},lower(myFormat))) == 1) 36 | warning(['Unsupported file format specified in ',mfilename,'. Support: "mat".']) 37 | flagContinue = false; 38 | else 39 | myFormat = lower(myFormat); 40 | % Force v7.3, which is needed to save files > 2GB. 41 | % However, the HDF5 format used by v7.3 may be slow. 42 | % I'm still exploring whether any optimization is possible or 43 | % needed to improve read/write times. 44 | saveVersion = '-v7.3'; 45 | end 46 | end 47 | 48 | if flagContinue 49 | if strcmp('mat', myFormat) 50 | fullFileName = [myPath,myFileName,'.',myFormat]; 51 | save(fullFileName, 'myMapelOptions', saveVersion); 52 | end 53 | else 54 | warning('Unable to save in ',mfilename,'. Exiting without save...') 55 | end 56 | end 57 | -------------------------------------------------------------------------------- /QSPToolbox/io/saveVPop.m: -------------------------------------------------------------------------------- 1 | function saveVPop(myVPop,myFileName, myFormat, myPath) 2 | % Save a VPop object to file. 3 | % 4 | % ARGUMENTS 5 | % myVPop: a VPop 6 | % fileName: a filename, suffix will be appended based on format 7 | % format: (optional)save file format, currently only support 'mat' 8 | % path: (optional) save file path 9 | % 10 | % RETURNS 11 | % nothing 12 | % 13 | 14 | % Perform initial checks on the provided arguments 15 | flagContinue = true; 16 | if nargin > 4 17 | warning(['Too many arguments provided to ',mfilename,', require: myVPop, fileName, and optionally format, path.']) 18 | flagContinue = false; 19 | elseif nargin > 3 20 | flagContinue = true; 21 | elseif nargin > 2 22 | myPath = ''; 23 | flagContinue = true; 24 | elseif nargin > 1 25 | myPath = ''; 26 | flagContinue = true; 27 | myFormat = 'mat'; 28 | else 29 | warning(['Insufficient arguments provided to ',mfilename,', require: myVPop, fileName, and optionally format, path.']) 30 | flagContinue = false; 31 | end 32 | 33 | % Create the new worksheet and verify the IDs 34 | if flagContinue 35 | if ~(sum(ismember({'mat'},lower(myFormat))) == 1) 36 | warning(['Unsupported file format specified in ',mfilename,'. Support: "mat".']) 37 | flagContinue = false; 38 | else 39 | myFormat = lower(myFormat); 40 | % Force v7.3, which is needed to save files > 2GB. 41 | % However, the HDF5 format used by v7.3 may be slow. 42 | % I'm still exploring whether any optimization is possible or 43 | % needed to improve read/write times. 44 | saveVersion = '-v7.3'; 45 | end 46 | end 47 | 48 | if flagContinue 49 | if strcmp('mat', myFormat) 50 | fullFileName = [myPath,myFileName,'.',myFormat]; 51 | % This is fast to recalculate and can take up space on disk 52 | myVPop.coeffsDist=''; 53 | save(fullFileName, 'myVPop', saveVersion); 54 | end 55 | else 56 | warning('Unable to save in ',mfilename,'. Exiting without save...') 57 | end 58 | end 59 | -------------------------------------------------------------------------------- /QSPToolbox/io/writeResultStruct.m: -------------------------------------------------------------------------------- 1 | function myFID = writeResultStruct(myResult, myFileName) 2 | % This function takes a results structure and writes it to a tab-delimited 3 | % text file. Note that you need to include the file extension in 4 | % myFileName and should be in the desired directory. 5 | % 6 | % ARGUMENTS 7 | % myResult: A struct with the desired data; 8 | % essentially a result struct. 9 | % myFileName: The name of the file to write to. 10 | % 11 | % RETURNS 12 | % myFID: A file identifier for MATLAB. 13 | % 14 | 15 | % Perform initial checks on the provided arguments 16 | flagContinue = true; 17 | 18 | myFID = 0; 19 | 20 | if nargin > 2 21 | warning(['Too many input arguments to ',mfilename,'. Require: mySimStruct, myFileName.']) 22 | flagContinue = false; 23 | elseif nargin < 2 24 | warning(['Insufficient input arguments to ',mfilename,'. Require: mySimStruct, myFileName.']) 25 | flagContinue = false; 26 | end 27 | 28 | if flagContinue 29 | if ~strcmp(class(myResult),'struct') 30 | warning(['Expecting a result structure with "Name" and "Data" fields in call to ',mfilename,'. Exiting.']) 31 | flagContinue = false; 32 | end 33 | if ~strcmp(class(myFileName),'char') 34 | warning(['Expecting a string for a filename in call to ',mfilename,'. Exiting.']) 35 | flagContinue = false; 36 | end 37 | end 38 | 39 | if flagContinue 40 | if ~((sum(ismember(fields(myResult),'Names')) == 1) & (sum(ismember(fields(myResult),'Data')) == 1)) 41 | warning(['Expecting a result structure with "Name" and "Data" fields in call to ',mfilename,'. Exiting.']) 42 | flagContinue = false; 43 | end 44 | end 45 | 46 | if flagContinue 47 | myFID=fopen(myFileName,'wt'); 48 | nCols = length(myResult.Names); 49 | for colCounter = 1:nCols-1 50 | fprintf(myFID,[myResult.Names{colCounter},'\t']); 51 | end 52 | fprintf(myFID, [myResult.Names{nCols},'\n']); 53 | [nRows,nCols] = size(myResult.Data); 54 | for rowCounter = 1:nRows 55 | fprintf(myFID,'%e\t',myResult.Data(rowCounter,1:(nCols-1))); 56 | fprintf(myFID,'%e\n',myResult.Data(rowCounter,nCols)); 57 | end 58 | fclose(myFID); 59 | else 60 | warning(['Unable to complete ', mfilename,', exiting.']) 61 | end 62 | end 63 | -------------------------------------------------------------------------------- /QSPToolbox/plotting/plotCoefficients.m: -------------------------------------------------------------------------------- 1 | function plotHandle = plotCoefficients(myWorksheet, myPlotCoefficientsOptions) 2 | % This function plots the axis coefficients for all of the VPs in a 3 | % worksheet. 4 | % 5 | % ARGUMENTS 6 | % myWorksheet: (required) Worksheet with coefficients 7 | % myPlotCoefficientsOptions: (optional) Optional structure to adjust the plotting 8 | % 9 | % RETURNS 10 | % plotHandle 11 | % 12 | plotHandle = []; 13 | flagExpData = false; 14 | 15 | if nargin > 2 16 | flagContinue = false; 17 | warning(['Too many input arguments to ',mfilename,'. Required: myWorksheet; optional: myPlotCoefficientsOptions.']) 18 | elseif nargin > 1 19 | flagContinue = true; 20 | elseif nargin > 0 21 | flagContinue = true; 22 | myPlotCoefficientsOptions = plotCoefficientsOptions; 23 | end 24 | 25 | if flagContinue 26 | if ~strcmp(class(myPlotCoefficientsOptions),'plotCoefficientsOptions') 27 | flagContinue = false; 28 | warning('Invalid plotOptions for ',mfilename,'.') 29 | end 30 | allCoefficients = (getVPCoeffs(myWorksheet)); 31 | [nAxis, nVP] = size(allCoefficients); 32 | if nAxis < 1 33 | flagContinue = false; 34 | warning('Worksheet contains no axes to plot for call to ',mfilename,'.') 35 | end 36 | end 37 | 38 | if (flagContinue) 39 | allCoefficients = transpose(allCoefficients); 40 | allAxisIDs = getAxisDefIDs(myWorksheet); 41 | nAxis = length(allAxisIDs); 42 | rng('default'); 43 | randColors = rand(nVP,3); 44 | jitterVals = 0.5*rand(nVP,1)-.25; 45 | plotHandle = figure; 46 | plotOrder = 1:nAxis; 47 | if myPlotCoefficientsOptions.flagSort 48 | coefficientRange = max(allCoefficients,[],1) - min(allCoefficients,[],1); 49 | [~, plotOrder] = sort(coefficientRange,'ascend'); 50 | end 51 | for plotCounter = 1 : nAxis 52 | subplot(nAxis, 1, plotCounter); 53 | yPos = (nAxis - plotCounter)/(nAxis+1) + 0.5/(nAxis+1); 54 | pos = get(gca, 'Position'); 55 | pos(1) = myPlotCoefficientsOptions.leftPosition; 56 | pos(3) = myPlotCoefficientsOptions.width; 57 | set(gca, 'Position', pos); 58 | [ksdens, u, bb]=ksdensity(allCoefficients(:,plotOrder(plotCounter))); 59 | ksdens=ksdens/max(ksdens)*0.3; 60 | median=nanmedian(allCoefficients(:,plotOrder(plotCounter))); 61 | scatter(allCoefficients(:,plotOrder(plotCounter)),jitterVals,10,randColors,'filled'); 62 | ylim([-0.3 0.3]); 63 | xlim(myPlotCoefficientsOptions.xLim); 64 | set(gca, 'YTick', [0]); 65 | set(gca, 'YTickLabel', {allAxisIDs{plotOrder(plotCounter)}},'TickLabelInterpreter','none'); 66 | set(gca,'box','on'); 67 | grid on; 68 | set(gca,'fontsize', myPlotCoefficientsOptions.fontSize); 69 | if plotCounter < nAxis 70 | set(gca,'XTickLabel', ''); 71 | end 72 | end 73 | if myPlotCoefficientsOptions.flagSave 74 | if length(myPlotCoefficientsOptions.fileName) > 0 75 | print([myPlotCoefficientsOptions.fileName,'.tif'],'-dtiff','-r300'); 76 | else 77 | theDate = date; 78 | formatOut = 'yymmdd'; 79 | theDate = datestr(theDate,formatOut); 80 | print(['worksheetAxisCoefficients_',theDate,'.tif'],'-dtiff','-r300'); 81 | end 82 | end 83 | end 84 | 85 | end -------------------------------------------------------------------------------- /QSPToolbox/population/classes/@VPop/assignCoeffs.m: -------------------------------------------------------------------------------- 1 | function obj = assignCoeffs(obj, myWorksheet) 2 | % Copy the VP coefficients from a worksheet to the `coeffsTable` property of the 3 | % VPop object. 4 | % 5 | % EXAMPLE 6 | % >> myVPop.assignCoeffs(myWorksheet) 7 | % 8 | % SEE ALSO 9 | % VPop.coeffsTable 10 | mycoeffsTable = getVPCoeffs(myWorksheet); 11 | obj.coeffsTable = mycoeffsTable; 12 | end 13 | -------------------------------------------------------------------------------- /QSPToolbox/population/classes/@VPop/assignIndices.m: -------------------------------------------------------------------------------- 1 | function obj = assignIndices(obj, myWorksheet, myMapelOptions) 2 | % This method takes a worksheet and mapelOptions structure and 3 | % creates a bin table and other poperties needed for the virtual 4 | % population and MAPEL algorithm. 5 | % 6 | % ARGUMENT 7 | % (self) 8 | % myWorksheet: a worksheet structure, with VPs, axes, and 9 | % coefficients 10 | % myMapelOptions: an instace of mapelOptions, with 11 | % properties 12 | % nBins 13 | % equalBinBreaks 14 | % 15 | % RETURNS 16 | % (self): properties of the virtual population are updated: 17 | % indexTable 18 | % binEdges 19 | % binMidPoints 20 | % 21 | % SEE ALSO 22 | % VPop.indexTable, VPop.binEdges, VPop.binMidPoints 23 | % mapelOptions 24 | 25 | myVPCoeffs = getVPCoeffs(myWorksheet); 26 | [nAxis, nVP] = size(myVPCoeffs); 27 | myIndexTable = ones(nAxis, nVP); 28 | nBins = myMapelOptions.nBins; 29 | myBinEdges = nan(nAxis, (nBins+1)); 30 | myBinMidPoints = nan(nAxis, nBins); 31 | equalBinBreaks = myMapelOptions.equalBinBreaks; 32 | for axisCounter = 1 : nAxis 33 | % We currently only implement continuous variables from 34 | % the paper/R MAPEL 35 | if equalBinBreaks 36 | % Rather than scaling based on the sampled min and 37 | % max as in the R MAPEL algorithm, we adjust according 38 | % to the allowed, 39 | % and this range is [0, 1] by the axis definition. 40 | myBinEdges(axisCounter,:) = (0:1/nBins:1); 41 | else 42 | myPercentiles = (0:1/nBins:1)'; 43 | myBinEdges(axisCounter,:) = (quantile(myVPCoeffs(axisCounter,:),myPercentiles)); 44 | end 45 | % We'll use the cdf convention that FX(x) = P(X <= x), so 46 | % check if a value is <= the bin upper cutoff in order to 47 | % assign it. 48 | % Note that effectively we want to ignore the first bin of 0 49 | % as a cutoff and lump this in with the first bin. 50 | for binCounter = 1 : nBins 51 | myBinMidPoints(axisCounter,binCounter) = (myBinEdges(axisCounter,binCounter) + myBinEdges(axisCounter,binCounter+1))/2; 52 | % First bins are assigned an index of 0 by this method. 53 | myIndexTable(axisCounter, :) = myIndexTable(axisCounter, :) + (myVPCoeffs(axisCounter, :) > myBinEdges(axisCounter,binCounter+1)); 54 | end 55 | end 56 | obj.indexTable = myIndexTable; 57 | obj.binEdges = myBinEdges; 58 | obj.binMidPoints = myBinMidPoints; 59 | end -------------------------------------------------------------------------------- /QSPToolbox/population/classes/@VPop/get.m: -------------------------------------------------------------------------------- 1 | function value = get(obj, propName) 2 | % value = get(vpop, propName) get the value of property `propName` from the virtual 3 | % population object. 4 | switch propName 5 | case 'coeffsTable' 6 | value = obj.coeffsTable; 7 | case 'coeffsDist' 8 | value = obj.coeffsDist; 9 | case 'pwStrategy' 10 | value = obj.pwStrategy; 11 | case 'indexTable' 12 | value = obj.indexTable; 13 | case 'binEdges' 14 | value = obj.binEdges; 15 | case 'binMidPoints' 16 | value = obj.binMidPoints; 17 | case 'binProbs' 18 | value = obj.binProbs; 19 | case 'pws' 20 | value = obj.pws; 21 | case 'mnSDTable' 22 | value = obj.mnSDTable; 23 | case 'binTable' 24 | value = obj.binTable; 25 | case 'distTable' 26 | value = obj.distTable; 27 | case 'distTable2D' 28 | value = obj.distTable2D; 29 | case 'corTable' 30 | value = obj.corTable; 31 | case 'subpopTable' 32 | value = obj.subpopTable; 33 | case 'expData' 34 | value = obj.expData; 35 | case 'simData' 36 | value = obj.simData; 37 | case 'gofMn' 38 | value = obj.gofMn; 39 | case 'gofSD' 40 | value = obj.gofSD; 41 | case 'gofBin' 42 | value = obj.gofBin; 43 | case 'gofDist' 44 | value = obj.gofDist; 45 | case 'gofDist2D' 46 | value = obj.gofDist2D; 47 | case 'gofCor' 48 | value = obj.gofCor; 49 | case 'gof' 50 | value = obj.gof; 51 | case 'spreadOut' 52 | value = obj.spreadOut; 53 | case 'minIndPVal' 54 | value = obj.minIndPVal; 55 | case 'useEffN' 56 | value = obj.useEffN; 57 | case 'exactFlag' 58 | value = obj.exactFlag; 59 | case 'optimizeTimeLimit' 60 | value = obj.optimizeTimeLimit; 61 | case 'optimizeType' 62 | value = obj.optimizeType; 63 | case 'optimizePopSize' 64 | value = obj.optimizePopSize; 65 | case 'objectiveLimit' 66 | value = obj.objectiveLimit; 67 | case 'poolRestart' 68 | value = obj.poolRestart; 69 | case 'poolClose' 70 | value = obj.poolClose; 71 | case 'intSeed' 72 | value = obj.intSeed; 73 | case 'tol' 74 | value = obj.tol; 75 | case 'nIters' 76 | value = obj.nIters; 77 | case 'minEffN' 78 | value = obj.minEffN; 79 | otherwise 80 | error(['Error: ',propName ,' is not a valid ',mfilename,' property.']) 81 | end 82 | end -------------------------------------------------------------------------------- /QSPToolbox/population/classes/@VPop/startPWs.m: -------------------------------------------------------------------------------- 1 | function obj = startPWs(obj, myWorksheet, myRandomStart) 2 | % This method initializes pws, and is used 3 | % prior to the optimization. 4 | % Only relevant for obj.pwStrategy = 'direct' 5 | % 6 | % ARGUMENTS 7 | % (self) 8 | % myRandomStart: A boolean variable (true/false), if true 9 | % prevalence weights will be set 10 | % randomly and if false they will be uniform 11 | % 12 | % SEE ALSO 13 | % VPop.pws, VPop.pwStrategy 14 | if nargin < 1 15 | myRandomStart = false; 16 | end 17 | mycoeffsTable = getVPCoeffs(myWorksheet); 18 | [nAxis, nVP] = size(mycoeffsTable); 19 | if ~myRandomStart 20 | myUniformStartProbs = ones(1,nVP) ./ nVP; 21 | else 22 | myUniformStartProbs = rand([1, nVP]); 23 | myUniformStartProbsSum=sum(myUniformStartProbs); 24 | for axisCounter = 1 : nVP 25 | myUniformStartProbs(1,axisCounter) = myUniformStartProbs(1,axisCounter)/myUniformStartProbsSum; 26 | end 27 | end 28 | obj.pws = myUniformStartProbs; 29 | end -------------------------------------------------------------------------------- /QSPToolbox/population/classes/@VPop/startProbs.m: -------------------------------------------------------------------------------- 1 | function obj = startProbs(obj, myRandomStart) 2 | % This method initializes bin probabilities, and is used 3 | % prior to the optization. 4 | % Only relevant for obj.pwStrategy = 'bin' 5 | % 6 | % ARGUMENTS 7 | % (self) 8 | % myRandomStart: A boolean variable (true/false), if true 9 | % the bin probabilities will be set 10 | % randomly and if false they will be uniform 11 | if nargin < 1 12 | myRandomStart = false; 13 | end 14 | myBinMidPoints = obj.binMidPoints; 15 | [nAxes, nBins] = size(myBinMidPoints); 16 | if ~myRandomStart 17 | myUniformStartProbs = ones(nAxes, nBins) ./ nBins; 18 | else 19 | myUniformStartProbs = rand([nAxes, nBins]); 20 | for axisCounter = 1 : nAxes 21 | myUniformStartProbs(axisCounter,:) = myUniformStartProbs(axisCounter,:)/sum(myUniformStartProbs(axisCounter,:)); 22 | end 23 | end 24 | obj.binProbs = myUniformStartProbs; 25 | end -------------------------------------------------------------------------------- /QSPToolbox/population/dataImport/convertExpDataToDistTable.m: -------------------------------------------------------------------------------- 1 | function myDistTable = convertExpDataToDistTable(myVPop) 2 | % This function takes experimental data and 3 | % converts it to a mean/sd table format for use in MAPEL 4 | % 5 | % ARGUMENTS: 6 | % myVPop: A VPop object with a populated expData field. A 7 | % mapelOptions structure is also OK. 8 | % 9 | % RETURNS 10 | % myDistTable 11 | % 12 | 13 | continueFlag = true; 14 | if nargin > 1 15 | continueFlag = false; 16 | warning(['Too many input arguments for ',mfilename,'. Should provide: myVPop.']) 17 | continueFlag = false; 18 | elseif nargin > 0 19 | continueFlag = true; 20 | else 21 | warning(['Insufficient input arguments for ',mfilename,'. Should provide: myVPop.']) 22 | continueFlag = false; 23 | end 24 | 25 | if continueFlag 26 | if sum(ismember({'VPop','VPopRECIST','VPopRECISTnoBin','mapelOptions','mapelOptionsRECIST','mapelOptionsRECISTnoBin'},class(myVPop))) < 1 27 | warning(['Wrong input arguments for ',mfilename,'. Should provide: myVPop (or mapelOptions).']) 28 | continueFlag = false; 29 | end 30 | end 31 | 32 | if continueFlag 33 | if sum(ismember({'table'},class(myVPop.expData))) < 1 34 | warning(['Wrong input arguments for ',mfilename,'. Should provide: myVPop (or mapelOptions) with a populated expData property.']) 35 | continueFlag = false; 36 | end 37 | end 38 | 39 | if continueFlag 40 | commonNames = loadCommonNames(); 41 | [nRows, ~] = size(myVPop.expData); 42 | if isa(myVPop,'VPop') || isa(myVPop,'mapelOptions') 43 | tableVariableNames = commonNames.VPOPTABLEVARNAMESFIXED; 44 | nDataHeaderCols = length(commonNames.VPOPTABLEVARNAMESFIXED); 45 | else 46 | tableVariableNames = commonNames.VPOPRECISTTABLEVARNAMESFIXED; 47 | nDataHeaderCols = length(commonNames.VPOPRECISTTABLEVARNAMESFIXED); 48 | end 49 | for rowCounter = 1 : nRows 50 | if rowCounter == 1 51 | tableVariableNames = [tableVariableNames,{'weight','expN', 'expSample', 'predN', 'predIndices','predSample', 'predProbs','expCombinedIndices','simCombinedIndices','combinedPoints'}]; 52 | myDistTable = cell2table(cell(0,length(tableVariableNames))); 53 | myDistTable.Properties.VariableNames = tableVariableNames; 54 | end 55 | curData = myVPop.expData{rowCounter,nDataHeaderCols+1:end}; 56 | curData = curData(~isnan(curData)); 57 | curRow = table2cell(myVPop.expData(rowCounter,1:nDataHeaderCols)); 58 | curRow = [curRow,{1, length(curData), {sort(curData,'ascend')}, nan, {nan}, {nan}, {nan},{nan},{nan},{nan}}]; 59 | curRow = cell2table(curRow); 60 | curRow.Properties.VariableNames = myDistTable.Properties.VariableNames; 61 | myDistTable = [myDistTable; curRow]; 62 | end 63 | else 64 | warning(['Unable to complete ',mfilename,', exiting.']) 65 | myDistTable = []; 66 | end 67 | 68 | end -------------------------------------------------------------------------------- /QSPToolbox/population/dataImport/convertExpDataToMnSDTable.m: -------------------------------------------------------------------------------- 1 | function myMnSDTable = convertExpDataToMnSDTable(myVPop) 2 | % This function takes experimental data and 3 | % converts it to a mean/sd table format for use in MAPEL 4 | % 5 | % ARGUMENTS: 6 | % myVPop: A VPop object with a populated expData field. A 7 | % mapelOptions structure is also OK. 8 | % 9 | % RETURNS 10 | % myMnSDTable 11 | % 12 | 13 | continueFlag = true; 14 | if nargin > 1 15 | continueFlag = false; 16 | warning(['Too many input arguments for ',mfilename,'. Should provide: myVPop.']) 17 | continueFlag = false; 18 | elseif nargin > 0 19 | continueFlag = true; 20 | else 21 | warning(['Insufficient input arguments for ',mfilename,'. Should provide: myVPop.']) 22 | continueFlag = false; 23 | end 24 | 25 | if continueFlag 26 | if sum(ismember({'VPop','VPopRECIST','VPopRECISTnoBin','mapelOptions','mapelOptionsRECIST','mapelOptionsRECISTnoBin'},class(myVPop))) < 1 27 | warning(['Wrong input arguments for ',mfilename,'. Should provide: myVPop (or mapelOptions).']) 28 | continueFlag = false; 29 | end 30 | end 31 | 32 | if continueFlag 33 | if sum(ismember({'table'},class(myVPop.expData))) < 1 34 | warning(['Wrong input arguments for ',mfilename,'. Should provide: myVPop (or mapelOptions) with a populated expData property.']) 35 | continueFlag = false; 36 | end 37 | end 38 | 39 | if continueFlag 40 | commonNames = loadCommonNames(); 41 | [nRows, ~] = size(myVPop.expData); 42 | if isa(myVPop,'VPop') || isa(myVPop,'mapelOptions') 43 | tableVariableNames = commonNames.VPOPTABLEVARNAMESFIXED; 44 | nDataHeaderCols = length(commonNames.VPOPTABLEVARNAMESFIXED); 45 | else 46 | tableVariableNames = commonNames.VPOPRECISTTABLEVARNAMESFIXED; 47 | nDataHeaderCols = length(commonNames.VPOPRECISTTABLEVARNAMESFIXED); 48 | end 49 | for rowCounter = 1 : nRows 50 | if rowCounter == 1 51 | tableVariableNames = [tableVariableNames,{'logN','weightMean', 'weightSD', 'expN', 'expMean', 'expSD', 'predN', 'predIndices', 'predMean', 'predSD'}]; 52 | myMnSDTable = cell2table(cell(0,length(tableVariableNames))); 53 | myMnSDTable.Properties.VariableNames = tableVariableNames; 54 | end 55 | curData = myVPop.expData{rowCounter,nDataHeaderCols+1:end}; 56 | curData = curData(~isnan(curData)); 57 | curRow = table2cell(myVPop.expData(rowCounter,1:nDataHeaderCols)); 58 | curRow = [curRow,{false, 1, 1, length(curData), mean(curData), std(curData), nan, {nan}, nan, nan}]; 59 | curRow = cell2table(curRow); 60 | curRow.Properties.VariableNames = myMnSDTable.Properties.VariableNames; 61 | myMnSDTable = [myMnSDTable; curRow]; 62 | end 63 | else 64 | warning(['Unable to complete ',mfilename,', exiting.']) 65 | myMnSDTable = []; 66 | end 67 | 68 | end -------------------------------------------------------------------------------- /QSPToolbox/population/evaluateMSE.m: -------------------------------------------------------------------------------- 1 | function myVPop = evaluateMSE(myVPop) 2 | % count the subpopulation and dropouts in: 3 | vpPrevalenceWeights=myVPop.pws'; 4 | if isempty(myVPop.LinearProblemMatrices) 5 | myOptimOptions = LinearCalibrationOptions(); 6 | myOptimOptions.cdfProbsToFit = 0.05:0.05:0.95; 7 | myOptimOptions.pdf2DProbsToFitN = 5; 8 | myOptimOptions.responseValTransformation='none'; 9 | myOptimOptions.optimizationAlgorithm = "quadprogEffN"; 10 | myOptimOptions.priorPrevalenceWeightAssumption = 'specified'; 11 | myOptimOptions.oldVPop = myVPop; 12 | % myOptimOptions = LinearCalibrationOptions(); 13 | % myOptimOptions.cdfProbsToFit = 0.05:0.05:0.95; 14 | % myOptimOptions.pdf2DProbsToFitN = 5; 15 | % myOptimOptions.responseValTransformation='none'; 16 | % myOptimOptions.optimizationAlgorithm = "fmincon"; 17 | % myOptimOptions.priorPrevalenceWeightAssumption = 'specified'; 18 | % myOptimOptions.targetEffNConstraint = 1; % just put any non-zero effN constraint to get the matrix 19 | % myOptimOptions.minSubWeightConstraint = 0; 20 | 21 | Objlinear = LinearCalibration(myVPop,myVPop,'optimOptions',myOptimOptions); 22 | Objlinear = Objlinear.constructLinearProblemMatrices(); 23 | myVPop.LinearProblemMatrices = Objlinear.LinearProblemMatrices; 24 | end 25 | C = myVPop.LinearProblemMatrices.independentVarValsWeighted; 26 | d = myVPop.LinearProblemMatrices.observationValsWeighted; 27 | SubgroupSumWeights = myVPop.LinearProblemMatrices.vpIsInSubgroup*vpPrevalenceWeights; 28 | % myVPop.LinearProblemMatricesSubgroupSumWeights = SubgroupSumWeights; % don't recalculate the subgroupweight from the rescaled weights. keep it the same as oldVPop 29 | Cactual = (1./SubgroupSumWeights).*(C.*myVPop.LinearProblemMatrices.vpIsInSubgroup); 30 | residuals = Cactual*vpPrevalenceWeights-d; 31 | residuals(isnan(residuals)) = 0; % added this in case there are one or less VPs in the row, mn and std will be NaNs 32 | N = length(d); % just fix it as the number of rows, so it is comparable between iterations 33 | myVPop.MSE = sum(residuals.^2)/N; 34 | end 35 | 36 | -------------------------------------------------------------------------------- /QSPToolbox/population/linearCalibration/increaseEffNWithLinearCalibrate.m: -------------------------------------------------------------------------------- 1 | function myVPop = increaseEffNWithLinearCalibrate(myVPop) 2 | % Uses least-squares optimization and bagging to increase EffN, likely 3 | % sacrificing goodness-of-fit p-value. 4 | 5 | tictoc = tic(); 6 | 7 | disp('Increasing EffN by using linear calibration with bagging...'); 8 | 9 | % Set up the optimization options, which will automatically spit back a set 10 | % of default values 11 | optimOptions = LinearCalibrationOptions(); 12 | 13 | % Define the probabilities of the cumulative 14 | % distribution functions (CDF) to fit. The default is to fit all points on 15 | % the CDF. We will only fit certain probabilities 16 | % along the CDF in order to make the fit faster. These probabilities are 17 | % defined here: 18 | optimOptions.cdfProbsToFit = 0.05:0.05:0.95; 19 | 20 | % Other options: 21 | optimOptions.optimizationAlgorithm = "nnls"; 22 | optimOptions.optimizationAlgorithmOptions.Accy = 0; 23 | optimOptions.method = "bagging"; 24 | optimOptions.fractionVPsPerBaggingIteration = 0.05; 25 | 26 | % Initialize a 'LinearCalibration' object: 27 | linearCalibrationObject = LinearCalibration(myVPop,'optimOptions',optimOptions); 28 | 29 | % Run the optimization: 30 | linearCalibrationObject = linearCalibrationObject.run(); 31 | 32 | % Update VPop: 33 | myVPop = linearCalibrationObject.OptimizedVPop; 34 | 35 | timeElapsedSec = toc(tictoc); 36 | disp(['Finished increasing EffN. Time elapsed [minutes]: ' num2str(timeElapsedSec/60)]); 37 | 38 | end -------------------------------------------------------------------------------- /QSPToolbox/population/statistics/alignCDFs.m: -------------------------------------------------------------------------------- 1 | function [CDF1, CDF2] = alignCDFs(sample1, sample2, W1, W2) 2 | % This function takes two samples and weights, and returns 3 | % adjusted sample and CDF vectors that can be compared element-wise 4 | % 5 | % ARGUMENTS 6 | % sample1 observed values for sample1. These are assumed to be sorted 7 | % in ascending order 8 | % sample2 observed values for sample2. These are assumed to be sorted 9 | % in ascending order 10 | % W1 a 1xlength(sample1) vector of weights for sample 1 11 | % W2 a 1xlength(sample2) vector of weights for sample 2 12 | % 13 | % RETURNS 14 | % CDF1 a 1xlength unique sample values of increasing cumulative 15 | % probabilities in sample 1 corresponding to the unique 16 | % combined sample values 17 | % CDF2 a 1xlength unique sample values of increasing cumulative 18 | % probabilities in sample 1 corresponding to the unique 19 | % combined sample values 20 | % First we need to interpolate the two samples so we can directly 21 | % take the supremum function. 22 | W1 = W1 / sum(W1); 23 | W2 = W2 / sum(W2); 24 | W1 = cumsum(W1); 25 | W2 = cumsum(W2); 26 | % We need to re-calculate the cdf for sample1 and sample2 27 | % at all x-values in either 28 | % sample 1 and sample2 so we can directly calculate 29 | % the differences in the cdf at each point 30 | [sample1ind, sample2ind, SC] = alignSamples(sample1, sample2); 31 | CDF1 = zeros(1, length(SC)); 32 | CDF2 = zeros(1, length(SC)); 33 | CDF1Indices = find(~isnan(sample1ind)); 34 | CDF2Indices = find(~isnan(sample2ind)); 35 | CDF1(CDF1Indices) = W1(sample1ind(CDF1Indices)); 36 | CDF2(CDF2Indices) = W2(sample2ind(CDF2Indices)); 37 | 38 | end -------------------------------------------------------------------------------- /QSPToolbox/population/statistics/alignCDFsPreGrid.m: -------------------------------------------------------------------------------- 1 | function [CDF1, CDF2] = alignCDFsPreGrid(SC, sample1ind, sample2ind, W1, W2) 2 | % This function returns 3 | % adjusted CDF vectors that can be compared element-wise 4 | % 5 | % ARGUMENTS 6 | % SC the combined unique, sorted sample values 7 | % sample1ind indices mapping values for sample1 to SC. 8 | % Indices are assumed to point to the each unique, last value 9 | % following sorting. 10 | % sample2ind indices mapping values for sample1 to SC. 11 | % Indices are assumed to point to the each unique, last value 12 | % following sorting. 13 | % W1 a 1xlength(sample1) vector of weights for sample 1 14 | % W2 a 1xlength(sample2) vector of weights for sample 2 15 | % 16 | % RETURNS 17 | % CDF1 a 1xlength unique sample values of increasing cumulative 18 | % probabilities in sample 1 corresponding to the unique 19 | % combined sample values 20 | % CDF2 a 1xlength unique sample values of increasing cumulative 21 | % probabilities in sample 1 corresponding to the unique 22 | % combined sample values 23 | % 24 | % First we need to interpolate the two samples so we can directly 25 | % take the supremum function. 26 | W1 = W1 / sum(W1); 27 | W2 = W2 / sum(W2); 28 | W1 = cumsum(W1); 29 | W2 = cumsum(W2); 30 | % We need to re-calculate the cdf for sample1 and sample2 31 | % at all x-values in either 32 | % sample 1 and sample2 so we can directly calculate 33 | % the differences in the cdf at each point 34 | CDF1 = zeros(1, length(SC)); 35 | CDF2 = zeros(1, length(SC)); 36 | CDF1Indices = find(~isnan(sample1ind)); 37 | CDF2Indices = find(~isnan(sample2ind)); 38 | CDF1(CDF1Indices) = W1(sample1ind(CDF1Indices)); 39 | CDF2(CDF2Indices) = W2(sample2ind(CDF2Indices)); 40 | 41 | end -------------------------------------------------------------------------------- /QSPToolbox/population/statistics/alignSamples.m: -------------------------------------------------------------------------------- 1 | function [sample1Ind, sample2Ind, SC] = alignSamples(sample1, sample2) 2 | % This function takes two samples, combines them, and returns 3 | % indices vectors that can be used to map the 4 | % original values in each sample onto the combined vector, prioritizing 5 | % the last observation to facilitate generating empirical CDFs. 6 | % 7 | % ARGUMENTS 8 | % sample1 observed values for sample1. These are assumed to be sorted 9 | % in ascending order 10 | % sample2 observed values for sample2. These are assumed to be sorted 11 | % in ascending order 12 | % 13 | % RETURNS 14 | % sample1Ind a 1xlength unique sample indices that map elements in sample 15 | % 1 to SC. 16 | % sample2Ind a 1xlength unique sample indices that map elements in sample 17 | % 2 to SC. 18 | % SC combined sample values 19 | % 20 | % We need to re-calculate the cdf for sample1 and sample2 21 | % at all x-values in either 22 | % sample 1 and sample2 so we can directly calculate 23 | % the differences in the cdf at each point 24 | [sample1,Inu1,~]=unique(sample1,'last'); 25 | [sample2,Inu2,~]=unique(sample2,'last'); 26 | SC = unique([sample1,sample2]); 27 | SC = sort(SC, 'ascend'); 28 | % Get the indices of length SC where every entry in SC is found to be 29 | % >= the indicated index in sample1 30 | if length(sample1) > 1 31 | sample1Ind = interp1(sample1,[1:length(sample1)],SC,'previous'); 32 | else 33 | % If there is just one unique value in sample1 34 | sample1Ind = ones(1,length(SC)); 35 | sample1Ind(sample1= the indicated index in sample2 39 | if length(sample2) > 1 40 | sample2Ind = interp1(sample2,[1:length(sample2)],SC,'previous'); 41 | else 42 | sample2Ind = ones(1,length(SC)); 43 | sample2Ind(sample2 0 47 | t = 1:numel(sample1Ind); 48 | sample1Ind = interp1(t(~isnan(sample1Ind)),sample1Ind(~isnan(sample1Ind)),t,'previous','extrap'); 49 | end 50 | if sum(isnan(sample2Ind)) > 0 && sum(~isnan(sample2Ind)) > 1 %need > 2 points for interpolating 51 | t = 1:numel(sample2Ind); 52 | sample2Ind = interp1(t(~isnan(sample2Ind)),sample2Ind(~isnan(sample2Ind)),t,'previous','extrap'); 53 | end 54 | % To update CDFs, we will need to map back to the non-unique but sorted 55 | % samples 56 | curInd = find(~isnan(sample1Ind)); 57 | sample1Ind(curInd) = Inu1(sample1Ind(curInd)); 58 | curInd = find(~isnan(sample2Ind)); 59 | sample2Ind(curInd) = Inu2(sample2Ind(curInd)); 60 | end -------------------------------------------------------------------------------- /QSPToolbox/population/statistics/contingency2N.m: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BMSQSP/QSPToolbox/42cb4425292c5ecdf4954b6251346503746671d0/QSPToolbox/population/statistics/contingency2N.m -------------------------------------------------------------------------------- /QSPToolbox/population/statistics/hbe.m: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BMSQSP/QSPToolbox/42cb4425292c5ecdf4954b6251346503746671d0/QSPToolbox/population/statistics/hbe.m -------------------------------------------------------------------------------- /QSPToolbox/population/statistics/predNPDTFLS.m: -------------------------------------------------------------------------------- 1 | function myVPop = predNPDTFLS(myVPop) 2 | % This function takes a VPop object and updates with 3 | % predictions for number of PD patients. 4 | % 5 | % ARGUMENTS 6 | % myVPop: (Required) a mapelOptionsRECIST or VPopRECIST 7 | % instance. 8 | % 9 | % Returns 10 | % myVPop: VPopRECIST with updated brTableRECIST. This 11 | % gives predNPD21LS values. 12 | % 13 | % 14 | 15 | 16 | continueFlag = true; 17 | if nargin > 1 18 | warning(['Too many input arguments provided to ',mfilename,'. Requires: VPopRECIST object.']) 19 | continueFlag = false; 20 | elseif nargin < 1 21 | continueFlag = false; 22 | warning(['Insufficient input arguments provided to ',mfilename,'. Requires: VPopRECIST object.']) 23 | end 24 | 25 | if continueFlag 26 | if ~ismember(class(myVPop),{'VPopRECIST'}) 27 | continueFlag = false; 28 | warning(['Input myVPop not recognized in call to ',mfilename,'. Requires: VPopRECIST object.']) 29 | end 30 | end 31 | 32 | 33 | if continueFlag 34 | lmResults = regressPD2ScaleFactor(myVPop); % updated: use PD, SD as dependent variable, intercept=0 35 | % Update the values for the 36 | % First find the blocks by the PD2 measures 37 | predRows = find(sum(isnan(myVPop.brTableRECIST{:,{'predN','predCR','predPR','predSD','predPD'}}),2)==0); 38 | predN = myVPop.brTableRECIST{predRows,{'predN'}}; 39 | predPD = myVPop.brTableRECIST{predRows,{'predPD'}}.*predN; 40 | predSD = myVPop.brTableRECIST{predRows,{'predSD'}}.*predN; 41 | 42 | res = predPD.*lmResults.Coefficients{1,'Estimate'} + predSD.*lmResults.Coefficients{2,'Estimate'}; 43 | myVPop.brTableRECIST{predRows,'predNPD21LS'}=res; 44 | else 45 | lmResults = {}; 46 | warning(['Unable to run ',mfilename,'.']) 47 | end 48 | end 49 | 50 | 51 | -------------------------------------------------------------------------------- /QSPToolbox/population/statistics/regressPD2ScaleFactor.m: -------------------------------------------------------------------------------- 1 | function lmResults = regressPD2ScaleFactor(myMapelOptions) 2 | % This function takes a mapelOptions or VPop object and returns 3 | % coefficients for a predicted PD2 scaling rate. 4 | % 5 | % ARGUMENTS 6 | % myMapelOptions: (Required) a mapelOptionsRECIST or VPopRECIST 7 | % instance. 8 | % 9 | % Returns 10 | % lmResults: Output of the regression. This gives the 11 | % a regression model for the observed PD normalized 12 | % to the number of patients recorded as nonPD2 13 | % (expN) at the first lesion scan. Multiply by 14 | % expN to get the predicted expNPD21LS. To 15 | % given an expNPD21LS, one could use the 16 | % predSD, predPD with the regression coefficients 17 | % and scale by the the predN. 18 | % 19 | % 20 | 21 | 22 | continueFlag = true; 23 | if nargin > 1 24 | warning(['Too many input arguments provided to ',mfilename,'. Requires: mapelOptionsRECIST or VPopRECIST object.']) 25 | continueFlag = false; 26 | elseif nargin < 1 27 | continueFlag = false; 28 | warning(['Insufficient input arguments provided to ',mfilename,'. Requires: mapelOptionsRECIST or VPopRECIST object.']) 29 | end 30 | 31 | if continueFlag 32 | if ~ismember(class(myMapelOptions),{'mapelOptionsRECIST','VPopRECIST'}) 33 | continueFlag = false; 34 | warning(['Input not recognized in call to ',mfilename,'. Requires: mapelOptionsRECIST or VPopRECIST object.']) 35 | end 36 | end 37 | 38 | 39 | if continueFlag 40 | % First find the blocks by the PD2 measures 41 | % Only keep the last time point from each inidividual intervention (BOR), then train the regression model 42 | testData = myMapelOptions.brTableRECIST(:,{'subpopNo','expDataID','interventionID'}); 43 | [C,IA,IC] = unique(testData,'rows','stable'); % unique(testData,'last','rows','stable'); 44 | LastRowindex=IA; 45 | for j=1:length(IA) 46 | indices=find(IC==j); 47 | LastRowindex(j)=indices(end); 48 | end 49 | testRows = find(~isnan(myMapelOptions.brTableRECIST{:,{'expNPD21LS'}})); 50 | regRows = intersect(testRows, LastRowindex); 51 | expN = table2array(myMapelOptions.brTableRECIST(regRows,'expN')); 52 | expPD=table2array(myMapelOptions.brTableRECIST(regRows,'expPD')).*expN; 53 | expSD=table2array(myMapelOptions.brTableRECIST(regRows,'expSD')).*expN; 54 | resp=table2array(myMapelOptions.brTableRECIST(regRows,'expNPD21LS')); 55 | fitTable = table(expPD,expSD,resp); 56 | lmResults = fitlm(fitTable,'resp ~ expPD + expSD','Intercept',false); 57 | else 58 | lmResults = {}; 59 | warning(['Unable to run ',mfilename,'. Returning an empty object.']) 60 | end 61 | end 62 | 63 | -------------------------------------------------------------------------------- /QSPToolbox/population/statistics/weightedKS.m: -------------------------------------------------------------------------------- 1 | function myPVal = weightedKS(sample1, sample2, W1, W2, N1, N2) 2 | % This function performs a KS test. Rather than assuming the 3 | % percentiles are computed from the rank-order it 4 | % adjusts the percentiles for observations according to the 5 | % provided weights. 6 | % 7 | % References: 8 | % Press et al, Numerical Recipes - The Art of Scientific Computing 9 | % (2007) P 736-740 10 | % Stevens MA. Use of the Kolmogorov-Smirnov, Cramer-Von Mises and 11 | % Related Statistics Without Extensive Tables. 12 | % Journal of the Royal Statistical Society Series B (Methodological). 13 | % 1970;32(1):115-122. 14 | % 15 | % 16 | % ARGUMENTS 17 | % sample1 observed values for sample1. These are assumed to be sorted 18 | % in ascending order 19 | % sample2 observed values for sample2. These are assumed to be sorted 20 | % in ascending order 21 | % W1 a 1xlength(sample1) vector of weights for sample 1 22 | % W2 a 1xlength(sample2) vector of weights for sample 2 23 | % N1 number of observations underlying sample1 24 | % N2 number of observations underlying sample2 25 | % 26 | % RETURNS 27 | % myPVal the p-value resulting from the two-tailed test 28 | 29 | % First calculate CDF along the sample sample axis 30 | [CDF1, CDF2, SC] = alignCDFs(sample1, sample2, W1, W2); 31 | % See Press et al, Numerical Recipes - The Art of Scientific Computing 32 | % (2007) P 736-740 33 | D = max(abs(CDF2-CDF1)); 34 | nPool = N1 * N2 /(N1 + N2); 35 | zVal = max((sqrt(nPool) + 0.12 + 0.11/sqrt(nPool)) * D , 0); 36 | % See page 334, special functions, in Numerical Recipes 37 | % This is an infinite series. Here we assume 100 terms is enough 38 | % TODO: may want to add a check to validate desired precision 39 | % for the series 40 | iVals = (1:100)'; 41 | myPVal = 2 * sum((-1).^(iVals-1).*exp(-2*zVal^2*iVals.^2)); 42 | myPVal = min(max(myPVal, 0), 1); 43 | end 44 | 45 | -------------------------------------------------------------------------------- /QSPToolbox/population/statistics/weightedKSPreGrid.m: -------------------------------------------------------------------------------- 1 | function myPVal = weightedKSPreGrid(SC, sample1Ind, sample2Ind, W1, W2, N1, N2) 2 | % This function performs a KS test. Rather than assuming the 3 | % percentiles are computed from the rank-order it 4 | % adjusts the percentiles for observations according to the 5 | % provided weights. 6 | % 7 | % This version assumes you will provide the 1-D mesh and indices to 8 | % map weights onto that mesh from combined, sorted, unique sample points. 9 | % 10 | % References: 11 | % Press et al, Numerical Recipes - The Art of Scientific Computing 12 | % (2007) P 736-740 13 | % Stevens MA. Use of the Kolmogorov-Smirnov, Cramer-Von Mises and 14 | % Related Statistics Without Extensive Tables. 15 | % Journal of the Royal Statistical Society Series B (Methodological). 16 | % 1970;32(1):115-122. 17 | % 18 | % ARGUMENTS 19 | % SC the vector of unique, sorted combined sample points 20 | % sample1Ind indices to map observations in sorted sample1 to SC 21 | % sample2Ind indices to map observations in sorted sample2 to SC 22 | % W1 a 1xlength(sample1) vector of weights for sample 1. 23 | % Is it assumed the W1s are based on sorted observations. 24 | % W2 a 1xlength(sample2) vector of weights for sample 2 25 | % Is it assumed the W2s are based on sorted observations. 26 | % N1 number of observations underlying sample1 27 | % N2 number of observations underlying sample2 28 | % 29 | % RETURNS 30 | % myPVal the p-value resulting from the two-tailed test 31 | % 32 | 33 | % First calculate CDF along the sample sample axis 34 | [CDF1, CDF2] = alignCDFsPreGrid(SC, sample1Ind, sample2Ind, W1, W2); 35 | % See Press et al, Numerical Recipes - The Art of Scientific Computing 36 | % (2007) P 736-740 37 | D = max(abs(CDF2-CDF1)); 38 | nPool = N1 * N2 /(N1 + N2); 39 | zVal = max((sqrt(nPool) + 0.12 + 0.11/sqrt(nPool)) * D , 0); 40 | % See page 334, special functions, in Numerical Recipes 41 | % This is an infinite series. Here we assume 100 terms is enough 42 | % TODO: may want to add a check to validate desired precision 43 | % for the series 44 | iVals = (1:100)'; 45 | myPVal = 2 * sum((-1).^(iVals-1).*exp(-2*zVal^2*iVals.^2)); 46 | myPVal = min(max(myPVal, 0), 1); 47 | end 48 | 49 | -------------------------------------------------------------------------------- /QSPToolbox/population/statistics/woodF.m: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BMSQSP/QSPToolbox/42cb4425292c5ecdf4954b6251346503746671d0/QSPToolbox/population/statistics/woodF.m -------------------------------------------------------------------------------- /QSPToolbox/population/statistics/wtdBinProb.m: -------------------------------------------------------------------------------- 1 | function wpp = wtdBinProb(measVals, pws, binEdgeValues) 2 | % This function calculates a discrete/binned pdf based on observations and 3 | % weights. Here, we strictly enforce the first dimension is 1 4 | % so there are no errors. 5 | % 6 | % ARGUMENTS 7 | % measVals: A 1 X nVP vector of measurement values 8 | % pws: A 1 X nVP vector of prevalence weights 9 | % binEdgeValues: A 1 X Nbin-1 vector of bin dividing edge values. Note 10 | % that values smaller than the first bin edge are counted 11 | % in the first bin and values >= than the upper bin edge 12 | % are counted in the last returned bin. 13 | % 14 | % RETURNS 15 | % wpp: A 1 X Nbin vector of weighted pdf in each bin 16 | % 17 | continueFlag = true; 18 | wpp = nan; 19 | numericTolerance = max(eps(1) * length(pws) * 10,1E-14); 20 | % We just check if matrix/vector dimensions are OK here. 21 | if nargin > 3 22 | continueFlag = false; 23 | warning(['A 1 x nVP vector of values and weights, and vector of inner bin edges, are all required for ',mfilename,'. Too many input arguments. Returning NaN.']) 24 | elseif nargin > 2 25 | continueFlag = true; 26 | else 27 | continueFlag = false; 28 | warning(['A 1 x nVP vector of values and weights, and vector of inner bin edges, are all required for ',mfilename,'. Insufficient input arguments. Returning NaN.']) 29 | end 30 | 31 | if continueFlag 32 | [size1r, size1c] = size(measVals); 33 | [size2r, size2c] = size(pws); 34 | [size3r, size3c] = size(binEdgeValues); 35 | if (size1c~= size2c) 36 | continueFlag = false; 37 | end 38 | if ((size1r ~= 1) || (size2r ~= 1) || (size3r ~= 1)) 39 | continueFlag = false; 40 | end 41 | if (size3c < 1) 42 | continueFlag = false; 43 | end 44 | if ~continueFlag 45 | warning(['A 1 x nVP vector of values and weights, and 1 X (nBin-1) vector of inner bin edges, are all required for ',mfilename,'. Returning NaN.']) 46 | end 47 | end 48 | 49 | if continueFlag 50 | if ((sum(pws) > (1 + numericTolerance)) || (sum(pws) < (1 - numericTolerance))) 51 | warning(['Supplied pws to ',mfilename,' should sum to 1. Returning NaN.']) 52 | continueFlag = false; 53 | end 54 | end 55 | 56 | if continueFlag 57 | catMat = cat(1, measVals, pws); 58 | [sortVal, Indices] = sort(measVals); 59 | catMat = catMat(:,Indices); 60 | nBins = length(binEdgeValues) + 1; 61 | wpp = zeros(1,length(nBins)); 62 | curIndices = catMat(1,:) < binEdgeValues(1); 63 | wpp(1,1) = sum(curIndices .* catMat(2,:)); 64 | for binCounter = 2 : (nBins-1) 65 | curIndices = catMat(1,:) < binEdgeValues(binCounter); 66 | wpp(1,binCounter) = sum(curIndices .* catMat(2,:)) - sum(wpp(1:(binCounter-1))); 67 | end 68 | curIndices = catMat(1,:) >= binEdgeValues(nBins-1); 69 | wpp(1,nBins) = sum(curIndices .* catMat(2,:)); 70 | end 71 | 72 | end -------------------------------------------------------------------------------- /QSPToolbox/population/statistics/wtdMean.m: -------------------------------------------------------------------------------- 1 | function wmn = wtdMean(measVals,pws) 2 | % Calculation of the weighted mean. 3 | % 4 | % ARGUMENTS 5 | % measVals: A 1 X nVP vector of measurement values 6 | % pws: A 1 X nVP vector of prevalence weights 7 | % 8 | % RETURNS 9 | % wmn: weighted mean 10 | % 11 | 12 | continueFlag = true; 13 | wmn = nan; 14 | % We just check if matrix/vector dimensions are OK here. 15 | if nargin > 2 16 | continueFlag = false; 17 | warning(['A 1 x nVP (or nVP X 1) vector of values and weights are both required for ',mfilename,'. Too many input arguments. Returning NaN.']) 18 | elseif nargin > 1 19 | continueFlag = true; 20 | else 21 | continueFlag = false; 22 | warning(['A 1 x nVP (or nVP X 1) vector of values and weights are both required for ',mfilename,'. Insufficient input arguments. Returning NaN.']) 23 | end 24 | 25 | if continueFlag 26 | [size1r, size1c] = size(measVals); 27 | [size2r, size2c] = size(pws); 28 | if ((size1r~= size2r) || (size1c~= size2c)) 29 | continueFlag = false; 30 | end 31 | if (min(size1r, size1c) ~= 1) || (min(size2r, size2c) ~= 1) 32 | continueFlag = false; 33 | end 34 | if ~continueFlag 35 | warning(['A 1 x nVP (or nVP X 1) vector of values and weights are both required for ',mfilename,'. Returning NaN.']) 36 | end 37 | end 38 | 39 | if continueFlag 40 | % We allow an error of eps * the number of VPs * 10 41 | % We could in strictly enforce eps * the number of VPs but 42 | % this criterion is relaxed a little. 43 | % 10^-14 was used as a minimum in the bin probabilities. The 44 | % bin probabilities should all be fixed and 45 | % PWs should all be corrected to sum to 1, but 46 | % here 10^-14 is set as a minimum allowed error in the check 47 | numericTolerance = max(eps(1) * length(pws) * 10,1E-14); 48 | if ((sum(pws) > (1 + numericTolerance)) || (sum(pws) < (1 - numericTolerance))) 49 | warning(['Supplied pws to ',mfilename,' should sum to 1. Returning NaN.']) 50 | continueFlag = false; 51 | end 52 | end 53 | 54 | if continueFlag 55 | wmn = sum(pws .* measVals); 56 | end 57 | 58 | end -------------------------------------------------------------------------------- /QSPToolbox/population/statistics/wtdStd.m: -------------------------------------------------------------------------------- 1 | function wsd = wtdStd(measVals,pws) 2 | % Calculates a weighted standard deviation. Note this is a quantity 3 | % without universal agreement on a definition from statisticians. 4 | % So here, we adopt the definition used in NIST software. See: 5 | % http://www.itl.nist.gov/div898/software/dataplot/refman2/ch2/weightsd.pdf 6 | % 7 | % ARGUMENTS 8 | % measVals: A 1 X nVP (or nVP X 1) vector of measurement values 9 | % pws: A 1 X nVP (or nVP X 1) vector of prevalence weights 10 | % 11 | % RETURNS 12 | % wsd: weighted standard deviation 13 | % 14 | 15 | continueFlag = true; 16 | wsd = nan; 17 | % We just check if matrix/vector dimensions are OK here. 18 | if nargin > 2 19 | continueFlag = false; 20 | warning(['A 1 x nVP (or nVP X 1) vector of values and weights are both required for ',mfilename,'. Too many input arguments. Returning NaN.']) 21 | elseif nargin > 1 22 | continueFlag = true; 23 | else 24 | continueFlag = false; 25 | warning(['A 1 x nVP (or nVP X 1) vector of values and weights are both required for ',mfilename,'. Insufficient input arguments. Returning NaN.']) 26 | end 27 | 28 | if continueFlag 29 | [size1r, size1c] = size(measVals); 30 | [size2r, size2c] = size(pws); 31 | if ((size1r~= size2r) || (size1c~= size2c)) 32 | continueFlag = false; 33 | end 34 | if (min(size1r, size1c) ~= 1) || (min(size2r, size2c) ~= 1) 35 | continueFlag = false; 36 | end 37 | if ~continueFlag 38 | warning(['A 1 x nVP (or nVP X 1) vector of values and weights are both required for ',mfilename,'. Returning NaN.']) 39 | end 40 | end 41 | 42 | if continueFlag 43 | % We allow an error of eps * the number of VPs * 10 44 | % We could in strictly enforce eps * the number of VPs but 45 | % this criterion is relaxed a little. 46 | % 10^-14 was used as a minimum in the bin probabilities. The 47 | % bin probabilities should all be fixed and 48 | % PWs should all be corrected to sum to 1, but 49 | % here 10^-14 is set as a minimum allowed error in the check 50 | numericTolerance = max(eps(1) * length(pws) * 10,1E-14); 51 | if ((sum(pws) > (1 + numericTolerance)) || (sum(pws) < (1 - numericTolerance))) 52 | warning(['Supplied pws to ',mfilename,' should sum to 1. Returning NaN.']) 53 | continueFlag = false; 54 | end 55 | end 56 | 57 | if continueFlag 58 | wMean = wtdMean(measVals,pws); 59 | wVar = sum(pws.*((measVals - wMean).^2)); 60 | % Note that for n in the wsd, we use the number of pws above a numeric 61 | % threshold (here, 1 E -16 as was done in the MAPEL paper). 62 | % If an effective N is used for statistical comparisons, the effective 63 | % N is implemented at the time of the statistical testing (e.g. F-test, 64 | % t-test, ...) 65 | n = sum(pws > numericTolerance); 66 | % Use the unbiased correction so it gives the 67 | % same answer as R's SD function 68 | wVar = wVar*n/(n-1); 69 | wsd = sqrt(wVar); 70 | % infinity can be returned 71 | % with a PW of ~1 coupled with 72 | % very small PWs. The std 73 | % of 1 value should be 0. 74 | if isinf(wsd) 75 | wsd = 0; 76 | end 77 | end 78 | end -------------------------------------------------------------------------------- /QSPToolbox/population/utility/align2DPDFs.m: -------------------------------------------------------------------------------- 1 | function [data1pdf, data2pdf, combinedPoints] = align2DPDFs(data1, data2, data2PWs) 2 | % This function takes two samples and weights, and returns 3 | % adjusted sample and CDF vectors that can be compared element-wise 4 | % 5 | % ARGUMENTS 6 | % data1 observed values for sample1. These need not be sorted, 7 | % but should be provided as a 2xN1 matrix 8 | % data2 observed values for sample2. These need not be sorted, 9 | % but should be provided as a 2xN2 matrix. 10 | % data2PWs a 1xN2 vector of weights for sample 2. It is assumed 11 | % all observations in sample1 are weighted equally. 12 | % 13 | % RETURNS 14 | % data1pdf: a pdf for data in sample1 mapped onto the combinedPoints 15 | % data2pdf: a pdf for data in sample2 mapped onto the combinedPoints 16 | % combinedPoints: a set of points that the pdfs in data1 and data2 are mapped onto. 17 | 18 | % First combine points, to get ranges 19 | combinedPoints = [(unique(data1','rows'))',(unique(data2','rows'))']; 20 | 21 | % We will apply smoothing to the PDFs. Calculate a bandwidth to use 22 | % base on the range in the data 23 | bw1 = (max(combinedPoints(1,:),[],2)-min(combinedPoints(1,:),[],2))/10; 24 | bw2 = (max(combinedPoints(2,:),[],2)-min(combinedPoints(2,:),[],2))/10; 25 | 26 | % Get the experimental density onto the model sampled points, with 27 | % smoothing 28 | data1pdf = ksdensity(data1',combinedPoints','Bandwidth',[bw1;bw2]); 29 | f = scatteredInterpolant(combinedPoints(1,:)', combinedPoints(2,:)', data1pdf, 'nearest'); 30 | 31 | % Unfortunately, we have to integrate over discontinuous surfaces (see 32 | % below) 33 | % and it's very likely there will be some residual error. We may want 34 | % to revisit this in future MATLAB releases. 35 | warning('off','MATLAB:integral2:maxFunEvalsPass'); 36 | % We may want to turn this back on with improved performance of 37 | % the 2D integration 38 | warning('off','MATLAB:integral2:maxFunEvalsFail'); 39 | % We use large tolerances. int does not have to be very precise, 40 | % and MATLAB's integral2 function can use much overhead if 41 | % we require a small tolerance. 42 | int = integral2(@(x,y) f(x,y), min(combinedPoints(1,:)), max(combinedPoints(1,:)), min(combinedPoints(2,:)), max(combinedPoints(2,:)),'method','tiled','AbsTol',1e-2,'RelTol',1e-1); 43 | 44 | % Normalize the 2D PDF 45 | data1pdf = data1pdf/int; 46 | 47 | % We will resample from data2 before smoothing. We can't apply 48 | % PWs in the smoothing function directly 49 | % Note: we may want to adjust the rng seed as an additional 50 | % input to make this reproducible 51 | % rng(0); 52 | data2pdf = datasample(data2', 1E3, 'Weights',data2PWs'); 53 | data2pdf = ksdensity(data2pdf,combinedPoints','Bandwidth',[bw1;bw2]); 54 | % We have to use 'nearest', which is discontinuous but 55 | % the only practical option. Otherwise, MATLAB may calculate a 56 | % negative interpolant with the available options, which does not 57 | % make sense for a pdf surface 58 | f = scatteredInterpolant(combinedPoints(1,:)', combinedPoints(2,:)', data2pdf, 'nearest'); 59 | int = integral2(@(x,y) f(x,y), min(combinedPoints(1,:)), max(combinedPoints(1,:)), min(combinedPoints(2,:)), max(combinedPoints(2,:)),'method','tiled','AbsTol',1e-2,'RelTol',1e-1); 60 | data2pdf = data2pdf/int; 61 | warning('on','MATLAB:integral2:maxFunEvalsPass'); 62 | warning('on','MATLAB:integral2:maxFunEvalsFail'); 63 | 64 | end -------------------------------------------------------------------------------- /QSPToolbox/population/utility/calculateExpWeight.m: -------------------------------------------------------------------------------- 1 | function w = calculateExpWeight(expN, expSTD, dataGroupDescription, simN) 2 | % This is a utility function to find calculation of 3 | % different weights for the different data group types 4 | % in linear calibrate. 5 | % 6 | % ARGUMENTS 7 | % expN: An experimental N 8 | % expSTD: An experimental standard deviation 9 | % dataGroupDescription: Data group description. Should be one of: 10 | % binTable 11 | % distTable 12 | % brTableRECIST 13 | % rTableRECIST 14 | % mnSDTablemean 15 | % mnSDTablevariance 16 | % simN: Assumed N for weighting for the simulation results 17 | % RETURNS 18 | % w: A weighting factor. 19 | % 20 | 21 | if strcmp(dataGroupDescription(1:length('binTable')), 'binTable') 22 | w = sqrt((expN*simN)/(expN+simN)); 23 | 24 | elseif strcmp(dataGroupDescription(1:length('distTable')), 'distTable') 25 | w = sqrt((expN*simN)/(expN+simN)); 26 | 27 | elseif strcmp(dataGroupDescription(1:length('distTable2D')), 'distTable2D') 28 | w = sqrt((expN*simN)/(expN+simN)); 29 | 30 | elseif strcmp(dataGroupDescription(1:length('brTableRECIST')), 'brTableRECIST') 31 | w = sqrt((expN*simN)/(expN+simN)); 32 | 33 | elseif strcmp(dataGroupDescription(1:length('rTableRECIST')), 'rTableRECIST') 34 | w = sqrt((expN*simN)/(expN+simN)); 35 | 36 | elseif strcmp(dataGroupDescription(1:length('mnSDTable')), 'mnSDTable') && strcmp(dataGroupDescription(end-length('mean')+1:end), 'mean') 37 | w = 1/(expSTD*sqrt(1/expN+1/simN)); 38 | 39 | elseif strcmp(dataGroupDescription(1:length('mnSDTable')), 'mnSDTable') && strcmp(dataGroupDescription(end-length('variance')+1:end), 'variance') 40 | w = 1/(expSTD*sqrt(1/expN+1/simN)); 41 | elseif strcmp(dataGroupDescription(1:length('corTable')), 'corTable') 42 | if expN>3 && simN>3 43 | w = 1/sqrt(1/(expN-3)+1/(simN-3)); 44 | else 45 | warning(['Either expN or simN is less than or equal to 3, modify weight calculation in ' mfilename ' to avoid NaN']) 46 | w = 1/sqrt(1/(expN)+1/(simN)); 47 | end 48 | else 49 | error('data group not supported'); 50 | end 51 | 52 | end -------------------------------------------------------------------------------- /QSPToolbox/population/utility/calculateExpWeightFix.m: -------------------------------------------------------------------------------- 1 | function w = calculateExpWeightFix(expN, expSTD, dataGroupDescription, simN) 2 | % This is a utility function to fix the experimental 3 | % weight to 1 for the different data group types 4 | % in linear calibrate. 5 | % 6 | % ARGUMENTS 7 | % expN: An experimental N, these are ignored here 8 | % expSTD: An experimental standard deviation 9 | % dataGroupDescription: Data group description. Should be one of: 10 | % binTable 11 | % distTable 12 | % brTableRECIST 13 | % rTableRECIST 14 | % mnSDTablemean 15 | % mnSDTablevariance 16 | % corTable 17 | % simN: Assumed N for weighting for the simulation results 18 | % RETURNS 19 | % w: A weighting factor. 20 | % 21 | 22 | % We will also try supplementing the VP scores scaled into PWs. This 23 | % likely won't be very effective at finding optimal solutions but will add 24 | % points where VPs in sparser regions of the distributions relative to the data 25 | % are more highly weighted which could help to weight to where it is needed 26 | % without overly focusing on a few VPs 27 | if strcmp(dataGroupDescription(1:length('binTable')), 'binTable') 28 | w = 1; 29 | 30 | elseif strcmp(dataGroupDescription(1:length('distTable')), 'distTable') 31 | w = 1; 32 | 33 | elseif strcmp(dataGroupDescription(1:length('distTable2D')), 'distTable2D') 34 | w = 1; 35 | 36 | elseif strcmp(dataGroupDescription(1:length('brTableRECIST')), 'brTableRECIST') 37 | w = 1; 38 | 39 | elseif strcmp(dataGroupDescription(1:length('rTableRECIST')), 'rTableRECIST') 40 | w = 1; 41 | 42 | elseif strcmp(dataGroupDescription(1:length('mnSDTable')), 'mnSDTable') && strcmp(dataGroupDescription(end-length('mean')+1:end), 'mean') 43 | w = 1; 44 | 45 | elseif strcmp(dataGroupDescription(1:length('mnSDTable')), 'mnSDTable') && strcmp(dataGroupDescription(end-length('variance')+1:end), 'variance') 46 | w = 1; 47 | elseif strcmp(dataGroupDescription(1:length('corTable')), 'corTable') 48 | w = 1; 49 | else 50 | error('data group not supported'); 51 | end 52 | 53 | end -------------------------------------------------------------------------------- /QSPToolbox/population/utility/calculateExpWeightFixSingle.m: -------------------------------------------------------------------------------- 1 | function w = calculateExpWeightFixSingle(expN, expSTD, dataGroupDescription, simN, keepType) 2 | % This is a utility function to fix the experimental 3 | % weight to 1 for a single data group type 4 | % in linear calibrate. 5 | % 6 | % ARGUMENTS 7 | % expN: An experimental N, these are ignored here 8 | % expSTD: An experimental standard deviation 9 | % dataGroupDescription: Data group description. Should be one of: 10 | % binTable 11 | % distTable 12 | % brTableRECIST 13 | % rTableRECIST 14 | % mnSDTablemean 15 | % mnSDTablevariance 16 | % corTable 17 | % simN: Assumed N for weighting for the simulation results 18 | % keepType: data group description to keep 19 | % nonzero. Note: use mnSDTable rather than 20 | % mnSDTablemean, mnSDTablevariance 21 | % RETURNS 22 | % w: A weighting factor. 23 | % 24 | 25 | if strcmp(dataGroupDescription(1:length('binTable')), 'binTable') 26 | if strcmp(keepType,'binTable') 27 | w = 1; 28 | else 29 | w = 0; 30 | end 31 | 32 | elseif strcmp(dataGroupDescription(1:length('distTable')), 'distTable') 33 | if strcmp(keepType,'distTable') 34 | w = 1; 35 | else 36 | w = 0; 37 | end 38 | 39 | elseif strcmp(dataGroupDescription(1:length('distTable2D')), 'distTable2D') 40 | if strcmp(keepType,'distTable') 41 | w = 1; 42 | else 43 | w = 0; 44 | end 45 | 46 | elseif strcmp(dataGroupDescription(1:length('brTableRECIST')), 'brTableRECIST') 47 | if strcmp(keepType,'distTable') 48 | w = 1; 49 | else 50 | w = 0; 51 | end 52 | 53 | elseif strcmp(dataGroupDescription(1:length('rTableRECIST')), 'rTableRECIST') 54 | if strcmp(keepType,'rTableRECIST') 55 | w = 1; 56 | else 57 | w = 0; 58 | end 59 | 60 | elseif strcmp(dataGroupDescription(1:length('mnSDTable')), 'mnSDTable') && strcmp(dataGroupDescription(end-length('mean')+1:end), 'mean') 61 | if strcmp(keepType,'mnSDTable') 62 | w = 1; 63 | else 64 | w = 0; 65 | end 66 | 67 | 68 | elseif strcmp(dataGroupDescription(1:length('mnSDTable')), 'mnSDTable') && strcmp(dataGroupDescription(end-length('variance')+1:end), 'variance') 69 | if strcmp(keepType,'mnSDTable') 70 | w = 1; 71 | else 72 | w = 0; 73 | end 74 | elseif strcmp(dataGroupDescription(1:length('corTable')), 'corTable') 75 | if strcmp(keepType,'corTable') 76 | w = 1; 77 | else 78 | w = 0; 79 | end 80 | else 81 | error('data group not supported'); 82 | end 83 | 84 | end -------------------------------------------------------------------------------- /QSPToolbox/population/utility/combineBins.m: -------------------------------------------------------------------------------- 1 | function myVPop = combineBins(myVPop) 2 | % Take an existing population and combine the axis bins, such that N bins 3 | % becomes N/2 bins. This is an auxiliary function that may be helpful 4 | % if testing using different numbers of axis bins for the VPop. 5 | % Note that you need to start with an even number of bins per axis 6 | % for this function. 7 | % 8 | % ARGUMENTS 9 | % myVPop: An instance of a VPop object. Properties should be 10 | % populated: 11 | % binEdges 12 | % indexTable 13 | % mnSDTable 14 | % binTable 15 | % simData 16 | % 17 | % RETURNS 18 | % myVpop: VPop with updated properties: 19 | % binEdges 20 | % binMidPoints 21 | % binProbs 22 | % gofMn 23 | % gofSD 24 | % gofBin 25 | % gof 26 | % 27 | 28 | continueFlag = false; 29 | if nargin > 1 30 | warning([mfilename,' requires input argument: myVPop. Too many arguments provided.']); 31 | elseif nargin >0 32 | continueFlag = true; 33 | else 34 | warning([mfilename,' requires input argument: myVPop. Insufficient arguments provided.']) 35 | end 36 | 37 | if continueFlag 38 | if class(myVPop) ~= 'VPop' 39 | warning(['An argument of class VPop is required in ',mfilename,'. Exiting.']) 40 | continueFlag = false; 41 | end 42 | end 43 | 44 | if continueFlag 45 | [myNAxis, myNBins] = size(myVPop.binMidPoints); 46 | if mod(myNBins,2) > 0 47 | warning(['Unable to combine bins in ',mfilename,'. An even number of bins is required. Exiting']) 48 | continueFlag = false; 49 | end 50 | end 51 | 52 | if continueFlag 53 | for axisCounter = 1 : myNAxis 54 | for binCounter = 1 : (myNBins/2) 55 | downAdjustBin = 2 * binCounter; 56 | myIndices = find(myVPop.indexTable(axisCounter,:) == downAdjustBin); 57 | indexTable(axisCounter,myIndices) = binCounter; 58 | end 59 | end 60 | myVPop.binEdges = myVPop.binEdges(:,[1:2:length(myVPop.binEdges(axisCounter,:))]); 61 | newMidPoints = nan(myNAxis,myNBins/2); 62 | newBinProbs = nan(myNAxis,myNBins/2); 63 | for binCounter = 1 : (myNBins/2) 64 | newMidPoints(:,binCounter) = 0.5*myVPop.binEdges(:,binCounter)+0.5*myVPop.binEdges(:,binCounter+1); 65 | newBinProbs(:,binCounter) = myVPop.binProbs(:,2*(binCounter-1)+1)+myVPop.binProbs(:,2*(binCounter)); 66 | end 67 | myVPop.binMidPoints = newMidPoints; 68 | myVPop.binProbs = newBinProbs; 69 | myVPop = evaluateGOF(myVPop); 70 | end -------------------------------------------------------------------------------- /QSPToolbox/population/utility/hyperTransform.m: -------------------------------------------------------------------------------- 1 | function probVectTrans = hyperTransform(probVect) 2 | % Hyperspherical coordinate transform 3 | % 4 | % ARGUMENTS 5 | % probVect: a vector of probabilities (0-1, sum to 1) 6 | % 7 | % RETURNS 8 | % probVectTrans: the transformed probability vector 9 | % 10 | 11 | % We need to do this because for hyperspherical 12 | % coords sum(x**2) = 1, for us sum(x) = 1 (probability) 13 | probVect = (probVect).^.5; 14 | nProbs = length(probVect); 15 | % We likely want a row vector out of the function 16 | probVectTrans = nan(1, nProbs-1); 17 | 18 | for pCounter = 1 : (nProbs-2) 19 | probVectTrans(pCounter) = atan2( sqrt(sum((probVect((pCounter+1):nProbs)).^2)),probVect(pCounter) ); 20 | end 21 | 22 | 23 | probVectTrans(nProbs-1) = atan2(probVect(nProbs),probVect(nProbs-1)); 24 | end -------------------------------------------------------------------------------- /QSPToolbox/population/utility/initializeOptionPropertiesToVPop.m: -------------------------------------------------------------------------------- 1 | function myVPop = initializeOptionPropertiesToVPop(myMapelOptions) 2 | % This is a simple utility function to copy all of the properties from 3 | % an options object to a VPop. Note Copying over myMapelOptions.initialPWs 4 | % is not done here. It is assumed appropriate treatment of these 5 | % is done in a calling script. 6 | % Also can't be set up here: 7 | % indexTable 8 | % binEdges 9 | % binMidPoints 10 | % binProbs 11 | % simData 12 | % recistSimFilter 13 | % 14 | % ARGUMENTS 15 | % myMapelOptions: (Required) an instance of a mapelOptions object. 16 | % 17 | % RETURNS 18 | % VPop: an instance of a VPop 19 | % 20 | 21 | if isa(myMapelOptions, 'mapelOptions') 22 | myVPop = VPop; 23 | elseif isa(myMapelOptions, 'mapelOptionsRECIST') 24 | myVPop = VPopRECIST; 25 | end 26 | % First, get the properties from myMapelOptions 27 | 28 | 29 | myVPop.pwStrategy = myMapelOptions.pwStrategy; 30 | myVPop.mnSDTable = myMapelOptions.mnSDTable; 31 | myVPop.binTable = myMapelOptions.binTable; 32 | myVPop.distTable = myMapelOptions.distTable; 33 | myVPop.distTable2D = myMapelOptions.distTable2D; 34 | myVPop.corTable = myMapelOptions.corTable; 35 | myVPop.subpopTable = myMapelOptions.subpopTable; 36 | myVPop.expData = myMapelOptions.expData; 37 | myVPop.spreadOut = myMapelOptions.spreadOut; 38 | myVPop.minIndPVal = myMapelOptions.minIndPVal; 39 | myVPop.useEffN = myMapelOptions.useEffN; 40 | myVPop.exactFlag = myMapelOptions.exactFlag; 41 | myVPop.optimizeTimeLimit = myMapelOptions.optimizeTimeLimit; 42 | myVPop.optimizeType = myMapelOptions.optimizeType; 43 | myVPop.optimizePopSize = myMapelOptions.optimizePopSize; 44 | myVPop.objectiveLimit = myMapelOptions.objectiveLimit; 45 | myVPop.poolClose = myMapelOptions.poolClose; 46 | myVPop.poolRestart = myMapelOptions.poolRestart; 47 | myVPop.intSeed = myMapelOptions.intSeed; 48 | myVPop.tol = myMapelOptions.tol; 49 | myVPop.nIters = myMapelOptions.nIters; 50 | myVPop.minEffN = myMapelOptions.minEffN; 51 | 52 | if isa(myVPop,'VPopRECIST') 53 | myVPop.brTableRECIST = myMapelOptions.brTableRECIST; 54 | myVPop.rTableRECIST = myMapelOptions.rTableRECIST; 55 | myVPop.relSLDvar = myMapelOptions.relSLDvar; 56 | myVPop.absALDVar = myMapelOptions.absALDVar; 57 | myVPop.crCutoff = myMapelOptions.crCutoff; 58 | end 59 | 60 | end -------------------------------------------------------------------------------- /QSPToolbox/population/utility/initializeVPopPropertiesToOption.m: -------------------------------------------------------------------------------- 1 | function myMapelOptions = initializeVPopPropertiesToOption(myVPop) 2 | % This is a simple utility function to copy all of the properties from 3 | % a VPop back to a MapelOptions. 4 | % 5 | % ARGUMENTS 6 | % myVPop: (Required) an instance of a VPop 7 | % 8 | % RETURNS 9 | % myMapelOptions: an instance of a mapelOptions object 10 | % 11 | 12 | if isa(myVPop, 'VPop') 13 | myMapelOptions = mapelOptions; 14 | elseif isa(myVPop, 'VPopRECIST') 15 | myMapelOptions = mapelOptionsRECIST; 16 | end 17 | % First, get the properties from myVPop 18 | % Also, note these are lost here: 19 | % indexTable 20 | % binEdges 21 | % binMidPoints 22 | % binProbs 23 | % simData 24 | % recistSimFilter 25 | 26 | myMapelOptions.pwStrategy = myVPop.pwStrategy; 27 | myMapelOptions.mnSDTable = myVPop.mnSDTable; 28 | myMapelOptions.binTable = myVPop.binTable; 29 | myMapelOptions.distTable = myVPop.distTable; 30 | myMapelOptions.distTable2D = myVPop.distTable2D; 31 | myMapelOptions.corTable = myVPop.corTable; 32 | myMapelOptions.subpopTable = myVPop.subpopTable; 33 | myMapelOptions.expData = myVPop.expData; 34 | myMapelOptions.spreadOut = myVPop.spreadOut; 35 | myMapelOptions.minIndPVal = myVPop.minIndPVal; 36 | myMapelOptions.useEffN = myVPop.useEffN; 37 | myMapelOptions.exactFlag = myVPop.exactFlag; 38 | myMapelOptions.optimizeTimeLimit = myVPop.optimizeTimeLimit; 39 | myMapelOptions.optimizeType = myVPop.optimizeType; 40 | myMapelOptions.optimizePopSize = myVPop.optimizePopSize; 41 | myMapelOptions.objectiveLimit = myVPop.objectiveLimit; 42 | myMapelOptions.poolClose = myVPop.poolClose; 43 | myMapelOptions.poolRestart = myVPop.poolRestart; 44 | myMapelOptions.intSeed = myVPop.intSeed; 45 | myMapelOptions.tol = myVPop.tol; 46 | myMapelOptions.nIters = myVPop.nIters; 47 | myMapelOptions.minEffN = myVPop.minEffN; 48 | 49 | if ~isempty(myVPop.binMidPoints) 50 | [~,myMapelOptions.nBins] = size(myVPop.binMidPoints); 51 | else 52 | myMapelOptions.nBins = 2; 53 | end 54 | myMapelOptions.initialProbs = myVPop.binProbs; 55 | myMapelOptions.initialPWs = myVPop.pws; 56 | % randomStart not on VPop 57 | 58 | if isa(myVPop,'VPopRECIST') 59 | myMapelOptions.brTableRECIST = myVPop.brTableRECIST; 60 | myMapelOptions.rTableRECIST = myVPop.rTableRECIST; 61 | myMapelOptions.relSLDvar = myVPop.relSLDvar; 62 | myMapelOptions.absALDVar = myVPop.absALDVar; 63 | myMapelOptions.crCutoff = myVPop.crCutoff; 64 | end 65 | 66 | end -------------------------------------------------------------------------------- /QSPToolbox/population/utility/invHyperTransform.m: -------------------------------------------------------------------------------- 1 | function probVect = invHyperTransform(probVectTrans) 2 | % Recover probabilities from hyperspherical coordinate transform 3 | % 4 | % ARGUMENTS 5 | % probVectTrans: the transformed probability vector 6 | % 7 | % RETURNS 8 | % probVect: a vector of probabilities (0-1, sum to 1) 9 | % 10 | 11 | probVect = [cos(probVectTrans) 1] .* [1 cumprod(sin(probVectTrans))]; 12 | probVect = probVect.^2; 13 | end -------------------------------------------------------------------------------- /QSPToolbox/population/utility/loadCommonNames.m: -------------------------------------------------------------------------------- 1 | function commonNames = loadCommonNames() 2 | % This is a simple function that returns a struct with useful 3 | % information for names for items such as table headers. 4 | % This is intended to ensure consistency in table 5 | % formatting and references. 6 | % 7 | % ARGUMENTS: 8 | % none 9 | % 10 | % RETURNS 11 | % commonNames: A structure with useful names 12 | % 13 | 14 | commonNames = struct; 15 | % Add table header variables. 16 | commonNames.RESPONSETABLEVARNAMESFIXED = {'subpopNo','time', 'expVarID', 'interventionID','elementID','elementType', 'expDataID', 'expTimeVarID','PatientIDVar','TRTVar','BRSCOREVar','RSCOREVar'}; 17 | commonNames.VPOPRECISTTABLEVARNAMESFIXED = {'subpopNo','time', 'interventionID', 'elementID', 'elementType', 'expDataID', 'expTimeVarID', 'expVarID','PatientIDVar','TRTVar','BRSCOREVar','RSCOREVar'}; 18 | commonNames.VPOPTABLEVARNAMESFIXED = {'subpopNo','time', 'interventionID', 'elementID', 'elementType', 'expDataID', 'expTimeVarID', 'expVarID','PatientIDVar'}; 19 | commonNames.VPOPEXPTABLEVARNAMESFIXED = commonNames.VPOPTABLEVARNAMESFIXED; 20 | commonNames.VPOPRECISTEXPTABLEVARNAMESFIXED = commonNames.VPOPRECISTTABLEVARNAMESFIXED; 21 | commonNames.VPOPRECISTRESPONSETABLEVARNAMESFIXED = {'subpopNo','time', 'expVarID', 'interventionID', 'elementID', 'elementType', 'expDataID', 'expTimeVarID', 'PatientIDVar','TRTVar','BRSCOREVar','RSCOREVar'}; 22 | commonNames.VPOP2DTABLEVARNAMESFIXED = {'subpopNo','time1','time2','interventionID1','interventionID2','elementID1','elementID2','elementType1','elementType2','expDataID1','expDataID2','expTimeVarID1','expTimeVarID2','expVarID1','expVarID2','PatientIDVar1','PatientIDVar2'}; % Lu edited: added 'PatientIDVar1','PatientIDVar2' 23 | commonNames.VPOPRECIST2DTABLEVARNAMESFIXED = {'subpopNo','time1','time2','interventionID1','interventionID2','elementID1','elementID2','elementType1','elementType2','expDataID1','expDataID2','expTimeVarID1','expTimeVarID2','expVarID1','expVarID2','PatientIDVar1','PatientIDVar2','TRTVar1','TRTVar2','BRSCOREVar1','BRSCOREVar2','RSCOREVar1','RSCOREVar2'}; 24 | commonNames.SUBPOPTABLEVARNAMESFIXED = {'subpopID','time','interventionID', 'elementID', 'elementType','comparator','value'}; 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /QSPToolbox/population/utility/probsToProbVect.m: -------------------------------------------------------------------------------- 1 | function myProbVect = probsToProbVect(myProbs) 2 | % Reshape a mxn table of axis probilities (m axis, n bins in each axis) 3 | % to a 1 X m*n vector. 4 | % This is needed in order to feed the vector to the optimization 5 | % algorithms 6 | % 7 | % ARGUMENTS 8 | % myProbs: an array of axis probabilities, preferentially already 9 | % transformed. 10 | % 11 | myProbVect = reshape(transpose(myProbs),[],1); 12 | myProbVect = transpose(myProbVect); 13 | end -------------------------------------------------------------------------------- /QSPToolbox/population/utility/spreadPWsToNeighbors.m: -------------------------------------------------------------------------------- 1 | function myNewPWs = spreadPWsToNeighbors(myPWs,myCoefficients,nNew) 2 | % This is a "utility function" that should be called directly. 3 | % This function will generate new PW guesses spread 4 | % around an initial guess, with weights given 5 | % preferentially to nearer neighbors. 6 | % 7 | % ARGUMENTS 8 | % myPWs: a 1 x nVPs vector of prevalence weights 9 | % myCoefficients an nAxis x nVP matrix of coefficients 10 | % nNew number of new PW solutions to add 11 | % 12 | % RETURNS 13 | % myNewPWs: original PWs appended with additional 14 | % (nNew + 1) x nVP matrix 15 | % 16 | 17 | [nDim,nVPs] = size(myCoefficients); 18 | % To speed up, we will focus on shifting weight 19 | % for up to the top 200 PWs 20 | nParents = min(nVPs,200); 21 | [~,parentIndices] = sort(myPWs,'descend'); 22 | parentIndices = parentIndices(1:nParents); 23 | vpDistance = pdist2(myCoefficients',myCoefficients'); 24 | % Maximim allowed my. i.e. mu of 4 25 | % will leave 25% of weight on the parent 26 | spreadMuMax = min(4,nParents/2); 27 | 28 | % We will generate new guesses that follow exponential 29 | % distributions around the initial point 30 | myNewPWs = myPWs; 31 | myNewPWs(parentIndices) = 0; 32 | myNewPWs = repmat(myNewPWs,nNew,1); 33 | % mu is the mu parameter from the exponential distribution 34 | mu = rand([nNew,1,nParents])*spreadMuMax; 35 | % Each parent VP from the original solution (outer loop) 36 | % will have some of his mass shifted onto neighbors according 37 | % to the exponential spread. 38 | spreadVals = exppdf(repmat([0:1:(nVPs-1)],nNew,1,nParents),mu); 39 | % loop over VPs in the outer loop so we only have to sort distances 40 | % for each VP once 41 | for parentCounter = 1 : nParents 42 | parentIndex = parentIndices(parentCounter); 43 | [~, sortIndex] = sort(vpDistance(parentIndex,:),'ascend'); 44 | % Normalize the spreadvals to make sure each row sums to 1 45 | spreadValsCur = spreadVals(:,:,parentCounter)./sum(spreadVals(:,:,parentCounter),2); 46 | %for distCounter = 1 : nNew 47 | %myNewPWs(distCounter, sortIndex) = myPWs(parentCounter)*spreadVals(distCounter,:)+myNewPWs(distCounter, sortIndex); 48 | myNewPWs(:, sortIndex) = myPWs(parentIndex)*spreadValsCur+myNewPWs(:, sortIndex); 49 | %end 50 | end 51 | myNewPWs = [myPWs;myNewPWs]; 52 | end -------------------------------------------------------------------------------- /QSPToolbox/population/utility/subsetWorksheetVPop.m: -------------------------------------------------------------------------------- 1 | function [myWorksheet, myVPop] = subsetWorksheetVPop(myWorksheet, myVPop, myVPIDs, equalizePWflag) 2 | % This function will take an input paired worksheet and VPop 3 | % and return a subsetted worksheet/VPop combination 4 | % 5 | % ARGUMENTS 6 | % myWorksheet: A worksheet structure 7 | % myVPop: A VPop object 8 | % myVPIDs: A 1xN set of VPIDs to selected 9 | % equalizePWflag: (optional, default FALSE) A boolean indicating 10 | % whether to reset all of the PWs to 1/N. 11 | % Default behavior is to re-normalize to 1 12 | % but not reset to be equal. If pwStrategy is 13 | % 'bin', the same bin probabilities are kept 14 | % and equalize will set the bin probabilities 15 | % to be the same. 16 | % RETURNS 17 | % myWorksheet 18 | % myVPop 19 | 20 | % Perform initial checks on the provided arguments 21 | flagContinue = true; 22 | 23 | if nargin > 4 24 | warning([mfilename,' requires input argument: myWorksheet, myVPop, myVPIDs, and optionally equalizePWflag. Too many arguments provided.']) 25 | flagContinue = false; 26 | elseif nargin > 3 27 | flagContinue = true; 28 | elseif nargin > 2 29 | equalizePWflag = false; 30 | flagContinue = true; 31 | elseif nargin < 1 32 | warning([mfilename,' requires input argument: myWorksheet, myVPop, myVPIDs, and optionally equalizePWflag. Insufficient arguments provided.']) 33 | flagContinue = true; 34 | end 35 | 36 | 37 | 38 | if flagContinue 39 | vpIDsAll = getVPIDs(myWorksheet); 40 | iMaskVPIDsKeep = ismember(vpIDsAll,myVPIDs); 41 | if (~isempty(myVPop.LinearProblemMatrices)) 42 | myVPop.LinearProblemMatrices.vpIsInSubgroup = myVPop.LinearProblemMatrices.vpIsInSubgroup(:,iMaskVPIDsKeep); 43 | myVPop.LinearProblemMatrices.independentVarValsWeighted = myVPop.LinearProblemMatrices.independentVarValsWeighted(:,iMaskVPIDsKeep); 44 | myVPop.LinearProblemMatrices.independentVarVals = myVPop.LinearProblemMatrices.independentVarVals(:,iMaskVPIDsKeep); 45 | end 46 | vpIDsKeep = vpIDsAll(iMaskVPIDsKeep); 47 | myWorksheet = copyWorksheet(myWorksheet,vpIDsKeep); 48 | if isa(myVPop,'VPopRECIST') 49 | myVPop.recistSimFilter = createRECISTSimFilter(myWorksheet, myVPop, false); 50 | end 51 | myVPop = myVPop.getSimData(myWorksheet); 52 | 53 | if isequal(myVPop.pwStrategy,'direct') 54 | if ~equalizePWflag 55 | prevalenceWeightsRenormalized = myVPop.pws(iMaskVPIDsKeep); 56 | prevalenceWeightsRenormalized = prevalenceWeightsRenormalized/sum(prevalenceWeightsRenormalized); 57 | else 58 | prevalenceWeightsRenormalized = 1/sum(iMaskVPIDsKeep) * ones(1,sum(iMaskVPIDsKeep)); 59 | end 60 | myVPop.pws = prevalenceWeightsRenormalized; 61 | else 62 | myVPop.indexTable = myVPop.indexTable(:,iMaskVPIDsKeep); 63 | if equalizePWflag 64 | myVPop = myVPop.startProbs(false); 65 | end 66 | myVPop = myVPop.assignPWs(); 67 | end 68 | 69 | myVPop = myVPop.assignCoeffs(myWorksheet); 70 | myVPop.subpopTable = updateSubpopTableVPs(myVPop.subpopTable, myWorksheet); 71 | myVPop = myVPop.addTableSimVals(); 72 | myVPop = myVPop.addPredTableVals(); 73 | myVPop = evaluateGOF(myVPop); 74 | myVPop = evaluateMSE(myVPop); 75 | else 76 | warning(['Could not complete ',mfilename,'. Returning original worksheet, VPop.']) 77 | end 78 | end -------------------------------------------------------------------------------- /QSPToolbox/visp/createViSPInput.m: -------------------------------------------------------------------------------- 1 | function createViSPInput(myWorksheet, myFileName) 2 | % Transform a worksheet into an input file for ViSP. 3 | % Note this should be run on the target simulation 4 | % architecture. 5 | % 6 | % ARGUMENTS 7 | % myWorksheet: A worksheet. 8 | % myFileName: The file to save to. ".mat" will be appended. 9 | % 10 | % RETURNS 11 | % nothing 12 | % 13 | 14 | flagContinue = false; 15 | if nargin > 2 16 | warning([mfilename,' requires input arguments: myWorksheet, myFileName. Too many arguments provided.']) 17 | elseif nargin < 2 18 | warning([mfilename,' requires input argument: myWorksheet, myFileName. Insufficient arguments provided.']) 19 | else 20 | flagContinue = true; 21 | end 22 | 23 | if flagContinue 24 | 25 | simBioModel = copyobj(myWorksheet.model); 26 | 27 | [modelValues,modelIndices, dosesArray,~,modelNames,~]... 28 | = getSimulateValuesDosesSep(myWorksheet); 29 | indices = GetIndices(modelValues,modelIndices); 30 | [paramValues,paramNames] = GetParamNamesAndValuesToStoreInDB(modelValues,modelNames,indices); 31 | 32 | simBioModel = UpdateSimBioModel(myWorksheet.compiled.elements, simBioModel, modelValues,indices); 33 | exportedModel = CreateExportedModel(simBioModel); 34 | exportedModel = SetSimulationOptionsInExportedModel(exportedModel,'myWorksheet',myWorksheet); 35 | 36 | vispSimBioInput.paramValues = paramValues; 37 | vispSimBioInput.paramNames = paramNames; 38 | vispSimBioInput.dosesArray = dosesArray; 39 | vispSimBioInput.exportedModel = exportedModel; 40 | vispSimBioInput.mySaveElementResultIDs = myWorksheet.simProps.saveElementResultIDs; 41 | save(myFileName,'-struct','vispSimBioInput'); 42 | disp('Saved Visp SimBio Input') 43 | end 44 | end 45 | 46 | function config = GetConfigForInput(fname) 47 | config_data = readtable(fname, 'Delimiter', '|'); 48 | config = containers.Map(config_data{:,1}, config_data{:,2}); 49 | end 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /QSPToolbox/visp/utility/CreateExportedModel.m: -------------------------------------------------------------------------------- 1 | function exportedModel = CreateExportedModel(simBioModel) 2 | 3 | %simBioModel = copyobj(myWorksheet.model); 4 | allModelParameters = get(simBioModel, 'Parameters'); 5 | allModelSpecies = get(simBioModel, 'Species'); 6 | allModelCompartments = get(simBioModel, 'Compartments'); 7 | exportElements = [allModelParameters;allModelSpecies;allModelCompartments]; 8 | allModelDoses = get(simBioModel, 'Doses'); 9 | 10 | simBioModel.ConfigSet.CompileOptions.UnitConversion = false; 11 | simBioModel.ConfigSet.CompileOptions.DimensionalAnalysis = false; 12 | 13 | exportedModel = export(simBioModel, exportElements, allModelDoses); 14 | 15 | end -------------------------------------------------------------------------------- /QSPToolbox/visp/utility/GetDoseNames.m: -------------------------------------------------------------------------------- 1 | function doseNames = GetDoseNames(doseArray) 2 | doseNames = cell(1,length(doseArray)); 3 | for theIndex = 1: length(doseArray) 4 | doseNames{counter} = get(doseArray{theIndex},'Name'); 5 | end 6 | for theIndex = 1: length(theDoseIndices) 7 | counter = counter + 1; 8 | theDoseArray = [theDoseArray, myModelDoseObjects(theDoseIndices(theIndex))]; 9 | intervention(counter) = interventionCounter; 10 | names{counter} = get(myModelDoseObjects(theDoseIndices(theIndex)),'Name'); 11 | end 12 | end -------------------------------------------------------------------------------- /QSPToolbox/visp/utility/GetIndices.m: -------------------------------------------------------------------------------- 1 | function indices = GetIndices(modelValues,modelIndices) 2 | 3 | numSim = size(modelValues,1)*size(modelValues,2); 4 | numParam = size(modelValues,3); 5 | reshapedModelValues = reshape(modelValues,numSim,numParam); 6 | 7 | filter = max(reshapedModelValues,[],1)- min(reshapedModelValues,[],1)==0; 8 | indices.constantParam = find(filter)'; 9 | indices.modelElemToSet = modelIndices(indices.constantParam); 10 | 11 | filter = max(reshapedModelValues,[],1)- min(reshapedModelValues,[],1)~=0; 12 | indices.varyingParam = find(filter)'; 13 | 14 | 15 | end 16 | -------------------------------------------------------------------------------- /QSPToolbox/visp/utility/GetParamNamesAndValuesToStoreInDB.m: -------------------------------------------------------------------------------- 1 | function [paramValues,paramNames] = GetParamNamesAndValuesToStoreInDB(modelValues,modelNames,indices) 2 | 3 | paramValues = modelValues(:,:,indices.varyingParam); 4 | paramNames = modelNames(indices.varyingParam); 5 | 6 | end 7 | 8 | 9 | -------------------------------------------------------------------------------- /QSPToolbox/visp/utility/UpdateSimBioModel.m: -------------------------------------------------------------------------------- 1 | function simBioModel = UpdateSimBioModel(modelElements,simBioModel,modelValues,indices) 2 | for counter = 1:length(indices.modelElemToSet) 3 | paramName = modelElements{indices.modelElemToSet(counter),1}; 4 | paramType = modelElements{indices.modelElemToSet(counter),2}; 5 | paramValue = modelValues(1,1,indices.constantParam(counter)); 6 | myObject = sbioselect(simBioModel,'Type',paramType,'Name',paramName); 7 | set(myObject,'Value',paramValue); 8 | end 9 | end 10 | 11 | -------------------------------------------------------------------------------- /QSPToolbox/worksheet/axis/getAxisDef.m: -------------------------------------------------------------------------------- 1 | function myAxisDef = getAxisDef(myWorksheet, myAxisDefID) 2 | % Get axisDef from a worksheet 3 | % ARGUMENTS 4 | % myWorksheet: a worksheet, required 5 | % myAxisDefID: String identifier for the axis 6 | % 7 | % RETURNS 8 | % myAxisDef: the desired axis definition 9 | 10 | axisDefIDs = getAxisDefIDs(myWorksheet); 11 | theMemberTrue = ismember(axisDefIDs, myAxisDefID); 12 | if sum(theMemberTrue) < 1 13 | error('Specified axis ID not in model') 14 | elseif sum(theMemberTrue) > 1 15 | error('Specified axis ID degenerate in model') 16 | else 17 | axisIndex = find(theMemberTrue); 18 | myAxisDef = myWorksheet.axisProps.axisDef{axisIndex}; 19 | end -------------------------------------------------------------------------------- /QSPToolbox/worksheet/axis/getAxisDefBounds.m: -------------------------------------------------------------------------------- 1 | function axisDefElementBounds = getAxisDefBounds(myWorksheet, myAxisID) 2 | % Get mechanistic axes bounds from a worksheet 3 | % ARGUMENTS 4 | % myWorksheet: a worksheet, required 5 | % myAxisID: axis to get the bounds for 6 | % 7 | % RETURNS 8 | % axisDefElementBounds: a nAxisElements X 2 matrix with axis bounds 9 | % 10 | 11 | previousAxesDef = getAxisDef(myWorksheet,myAxisID); 12 | axisDefElementBounds = zeros(0,2); 13 | for axesCounter = 1 : length(previousAxesDef) 14 | curAxisDefElementBounds = previousAxesDef.bounds{axesCounter}; 15 | axisDefElementBounds = cat(1, axisDefElementBounds, curAxisDefElementBounds); 16 | end -------------------------------------------------------------------------------- /QSPToolbox/worksheet/axis/getAxisDefIDs.m: -------------------------------------------------------------------------------- 1 | function axisDefIDs = getAxisDefIDs(myWorksheet) 2 | % Get mechanistic axes IDs from a worksheet 3 | % ARGUMENTS 4 | % myWorksheet: a worksheet, required 5 | % 6 | % RETURNS 7 | % axisDefIDs: a 1 X nAxes cell array with axes IDs 8 | % 9 | previousAxisDef = myWorksheet.axisProps.axisDef; 10 | axisDefIDs = cell(1,0); 11 | for axesCounter = 1 : length(previousAxisDef) 12 | testAxesDef = previousAxisDef{axesCounter}; 13 | axisDefIDs = [axisDefIDs, testAxesDef.id]; 14 | end -------------------------------------------------------------------------------- /QSPToolbox/worksheet/axis/getVPCoeffs.m: -------------------------------------------------------------------------------- 1 | function myVPCoeffs = getVPCoeffs(myWorksheet) 2 | % Get VP axes coefficient values from a worksheet 3 | % ARGUMENTS 4 | % myWorksheet: a worksheet, required 5 | % 6 | % RETURNS 7 | % myVPCoefs: an nCoeffs x nVP numeric matrix of coefficient values 8 | % 9 | myVPCoeffs = myWorksheet.axisProps.axisVP.coefficients; -------------------------------------------------------------------------------- /QSPToolbox/worksheet/axis/getVPValues.m: -------------------------------------------------------------------------------- 1 | function myVPValues = getVPValues(myWorksheet) 2 | % Get VP element values that are defined by axes in a worksheet 3 | % ARGUMENTS 4 | % myWorksheet: a worksheet, required 5 | % 6 | % RETURNS 7 | % myVPValues: a cell array, each element is a matrix of element (parameter) values 8 | % 9 | myCoeffs = getVPCoeffs(myWorksheet); 10 | [nAxes, nVPs] = size(myCoeffs); 11 | myVPValues = cell(nAxes, nVPs); 12 | axesVP = myWorksheet.axisProps.axisVP; 13 | for vpCounter = 1 : nVPs 14 | for axesCounter = 1: nAxes 15 | myVPValues{axesCounter, vpCounter} = axesVP.calculateElementValues([axesCounter, vpCounter], myWorksheet); 16 | end 17 | end -------------------------------------------------------------------------------- /QSPToolbox/worksheet/axis/utility/setAxisDefBounds.m: -------------------------------------------------------------------------------- 1 | function myWorksheet = setAxisDefBounds(myWorksheet, myAxisID, myBoundsMatrix) 2 | % Set mechanistic axes bounds from a worksheet 3 | % This is just added so we can work with axes bounds as matrices 4 | % rather than a cell array of 1X2 matrices 5 | % 6 | % NOTE: THIS FUNCTION DOES NOT RESET VP COEFFICIENTS! CALL RESETAXISBOUNDS 7 | % TO INCLUDE A VP COEFFICIENT UPDATE! 8 | % 9 | % ARGUMENTS 10 | % myWorksheet: a worksheet, required 11 | % myAxisID: axis to set the bounds for 12 | % myBoundsMatrix 13 | % 14 | % RETURNS 15 | % myWorksheet: worksheet with updated bounds for the indicates axes 16 | % 17 | allAxisIDs = getAxisDefIDs(myWorksheet); 18 | axisIndex = find(ismember(allAxisIDs, myAxisID)); 19 | [nElements, dummy] = size(myBoundsMatrix); 20 | myBoundsAsCellArray = cell(1,0); 21 | 22 | for elementCounter = 1 : nElements 23 | myBoundsAsCellArray = [myBoundsAsCellArray, myBoundsMatrix(elementCounter, :)]; 24 | end 25 | myWorksheet.axisProps.axisDef{axisIndex}.bounds = myBoundsAsCellArray; -------------------------------------------------------------------------------- /QSPToolbox/worksheet/convertVPCoefficientsToVariants.m: -------------------------------------------------------------------------------- 1 | function myVariants = convertVPCoefficientsToVariants(myWorksheet, myVPIDs) 2 | % Here, we convert VP Coefficients defined from the axes to a variant. 3 | % This can potentially help in developing virtual populations. 4 | % 5 | % ARGUMENTS: 6 | % myWorksheet A worksheet data structure with VPs and coefficients 7 | % myVPIDs An optional 1xnVP cell array of virtual patient IDs to gather. 8 | % If none are given, all worksheet VP IDs will be used. 9 | % 10 | % RETURNS: 11 | % myVariants A 1xnVP cell array of variants 12 | % 13 | 14 | continueFlag = true; 15 | if nargin > 2 16 | warning(['Too many input arguments provided to ',mfilename,'. Expecting myWorksheet, myVPIDs. Exiting.']) 17 | continueFlag = false; 18 | elseif nargin > 1 19 | continueFlag = true; 20 | elseif nargin > 0 21 | continueFlag = true; 22 | myVPIDs = getVPIDs(myWorksheet); 23 | else 24 | warning(['Too few input arguments provided to ',mfilename,'. Expecting myWorksheet, myVPIDs. Exiting.']) 25 | continueFlag = false; 26 | end 27 | 28 | if continueFlag 29 | allVPIDs = getVPIDs(myWorksheet); 30 | if sum(ismember(myVPIDs,allVPIDs)) < length(myVPIDs) 31 | warning(['Worksheet is missing desired VPIDs in ',mfilename,'. Exiting']) 32 | continueFlag = false; 33 | end 34 | end 35 | 36 | if continueFlag 37 | nVPs = length(myVPIDs); 38 | myVariants = cell(1,nVPs); 39 | myAxisIDs = getAxisDefIDs(myWorksheet); 40 | nAxis = length(myAxisIDs) 41 | myTemplate = cell(1,0); 42 | templateCounter = 0; 43 | for axisCounter = 1:nAxis 44 | myAxisDef = myWorksheet.axisProps.axisDef{axisCounter}; 45 | for elementCounter = 1:length(myAxisDef.elementNames) 46 | %curTemplate = cell(1,4); 47 | elementType = myAxisDef.elementTypes{elementCounter}; 48 | elementName = myAxisDef.elementNames{elementCounter}; 49 | elementValue = NaN; 50 | if strcmp('parameter',elementType) 51 | elementValueType = 'Value'; 52 | elseif strcmp('species',elementType) 53 | elementValueType = 'InitialAmount'; 54 | else 55 | elementValueType = 'Capacity'; 56 | end 57 | myTemplate = [myTemplate,{{elementType,elementName,elementValueType,elementValue}}]; 58 | end 59 | end 60 | for vpCounter = 1 : nVPs 61 | curVPValues = myTemplate; 62 | vpIndex = find(ismember(allVPIDs,myVPIDs{vpCounter})); 63 | elementIndex = 0; 64 | for axisCounter = 1 :nAxis 65 | myValues = myWorksheet.axisProps.axisVP.calculateElementValues([axisCounter,vpIndex],myWorksheet); 66 | for memberCounter = 1 : length(myValues) 67 | elementIndex = elementIndex +1; 68 | curVPValues{elementIndex}{4} = myValues(memberCounter); 69 | end 70 | end 71 | myVariants{vpCounter}=sbiovariant(myVPIDs{vpCounter}); 72 | myVariants{vpCounter}.Content = curVPValues; 73 | end 74 | else 75 | warning(['Exiting ',mfilename,'.']) 76 | end 77 | 78 | 79 | -------------------------------------------------------------------------------- /QSPToolbox/worksheet/createWorksheet.m: -------------------------------------------------------------------------------- 1 | function myWorksheet = createWorksheet() 2 | % A simple function to initialize a new blank worksheet. 3 | % This function 4 | % ARGUMENTS 5 | % none 6 | % 7 | % RETURNS 8 | % myWorksheet 9 | 10 | % Worksheets are structures. At some point in the future, we may want to 11 | % re-code them as objects. 12 | myWorksheet = struct(); 13 | 14 | % No null value in MATLAB, just use an empty string 15 | myWorksheet.model = ''; 16 | 17 | myWorksheet.project = struct(); 18 | myWorksheet.project.filePath = ''; 19 | myWorksheet.project.fileName = ''; 20 | 21 | myWorksheet.compiled = struct(); 22 | myWorksheet.compiled.elements = ''; 23 | myWorksheet.compiled.doses = ''; 24 | myWorksheet.compiled.model = ''; 25 | 26 | 27 | % VP definitions will be an 1XnVP array of cells, each cell consiting of 28 | % and appropriate VP 29 | myWorksheet.vpDef = cell(1,0); 30 | 31 | myWorksheet.axisProps = struct(); 32 | % axesDef will be an LX1 array of axisDef objects, 33 | myWorksheet.axisProps.axisDef = cell(0,1); 34 | % VP axes will be an 1 vpAxis object, 35 | myWorksheet.axisProps.axisVP = axisVP(); 36 | % interventions will be an MX1 array of 37 | % cells, then within each cell we will 38 | % have an intervention structure 39 | myWorksheet.interventions = cell(0,1); 40 | % expData will contain misc. datasets for plotting and optimization 41 | myWorksheet.expData = cell(0,1); 42 | % Response types will include groups of response type elements 43 | % which will be mappings from the responses to intervention 44 | % for certain variables to datasets or specified bounds. 45 | myWorksheet.responseTypes = cell(0,1); 46 | 47 | % simProps will include specifications for the simulation run 48 | myWorksheet.simProps = struct(); 49 | myWorksheet.simProps.sampleTimes = [0:0.25:100]'; 50 | myWorksheet.simProps.absoluteTolerance = 1e-8; 51 | myWorksheet.simProps.absoluteToleranceStepSize = [];%myWorksheet.simProps.absoluteTolerance * myWorksheet.simProps.simTime * 0.1; 52 | myWorksheet.simProps.relativeTolerance = 1e-3; 53 | myWorksheet.simProps.absoluteToleranceScaling = true; 54 | myWorksheet.simProps.maximumWallClock = 5*60; 55 | myWorksheet.simProps.maxStep = []; 56 | myWorksheet.simProps.solverType = 'sundials'; 57 | myWorksheet.simProps.saveElementResultIDs = {}; 58 | 59 | % We will initialize results to an empty cell 60 | myWorksheet.results = cell(0,0); 61 | 62 | % Variantprops will keep track of the variants to apply to define the 63 | % base VP's, before axes or the effects of interventions are applied. 64 | myWorksheet.variantProps = struct(); 65 | % Variant types define the grouping of parameters 66 | myWorksheet.variantProps.variantTypes = cell(0,1); 67 | % Variant type value sets are the types plus specific parameter values 68 | myWorksheet.variantProps.typeValueSets = cell(0,1); 69 | 70 | % Reserved string for splitting variant type and variant description 71 | % in variant names 72 | myWorksheet.variantProps.delimiter = '___'; 73 | 74 | end -------------------------------------------------------------------------------- /QSPToolbox/worksheet/data/getExpData.m: -------------------------------------------------------------------------------- 1 | function myExpData = getExpData(expDataID, myWorksheet) 2 | % Get experimental data from a worksheet 3 | % ARGUMENTS 4 | % expDataID: String identifier for the expData 5 | % myWorksheet: a worksheet, required 6 | % 7 | % RETURNS 8 | % myExpData: the experimental data 9 | 10 | expDataIDs = getExpDataIDs(myWorksheet); 11 | if sum(ismember(expDataIDs, expDataID)) < 1 12 | warning(['Specified data set ID, ',expDataID,', not loaded into worksheet.']) 13 | myExpData = table(); 14 | elseif sum(ismember(expDataIDs, expDataID)) > 1 15 | warning(['Specified data set ID, ',expDataID,', degenerate in worksheet.']) 16 | myExpData = table(); 17 | else 18 | dataIndex = find(ismember(expDataIDs, expDataID)); 19 | myExpData = myWorksheet.expData{dataIndex,1}.('data'); 20 | end -------------------------------------------------------------------------------- /QSPToolbox/worksheet/data/getExpDataIDs.m: -------------------------------------------------------------------------------- 1 | function expDataIDs = getExpDataIDs(myWorksheet) 2 | % Get experiment data IDs from a model 3 | % ARGUMENTS 4 | % worksheet: a worksheet object, required 5 | % 6 | % RETURNS 7 | % expDataIDs: an array of cells with the variant names 8 | % 9 | expDataSets = myWorksheet.expData; 10 | [nDataSets, dummy] = size(expDataSets); 11 | expDataIDs = cell(1, nDataSets); 12 | for dataCounter = 1 : nDataSets 13 | curDataSet = expDataSets{dataCounter}; 14 | expDataIDs{dataCounter} = curDataSet.('ID'); 15 | end 16 | 17 | 18 | end -------------------------------------------------------------------------------- /QSPToolbox/worksheet/intervention/createIntervention.m: -------------------------------------------------------------------------------- 1 | function myWorksheet = createIntervention(myWorksheet, interventionID, arrangedIntervention) 2 | % Create an intervention and add it to the worksheet 3 | % ARGUMENTS 4 | % myWorksheet: a worksheet structure, required 5 | % interventionID: a simple text identifier for the intervention 6 | % arrangedIntervention: an (N+M)x2 cell of N Variants and M doses 7 | % 8 | % RETURNS 9 | % worksheet: an updated worksheet with the intervention. 10 | % 11 | % TODO: 1st iteration, might want to add checks on 12 | % the VP variants. This is done before calling createVP() now. 13 | % Also might want to update this to add a set of VPs at once. 14 | newIntervention = struct(); 15 | newIntervention.ID = interventionID; 16 | newIntervention.definition = arrangedIntervention; 17 | 18 | % Don't duplicate intervention ID's 19 | % But we will allow multiple base interventions with identical 20 | % variants/doses, since we may alter these 21 | % later 22 | existingInterventionIDs = getInterventionIDs(myWorksheet); 23 | if length(find(ismember(existingInterventionIDs, newIntervention.ID))) == 0 24 | [dummyVar, nExistingInterventions] = size(existingInterventionIDs); 25 | myWorksheet.interventions{nExistingInterventions + 1, 1} = newIntervention; 26 | else 27 | warning(['Input argument interventionID in ',mfilename,' should not already be present in worksheet. Returning input worksheet.']) 28 | end 29 | 30 | end -------------------------------------------------------------------------------- /QSPToolbox/worksheet/intervention/extractInterventionTypeElements.m: -------------------------------------------------------------------------------- 1 | function interventionSubElements = extractInterventionTypeElements(intervention, type) 2 | % Get the identities of model VARIANTs or DOSEs used by an intervention. 3 | % 4 | % ARGUMENTS 5 | % intervention: an intervention structure 6 | % type: a string indicating the type of model components 7 | % to return from the intervention definition: 8 | % i.e. 'VARIANT' or 'DOSE' 9 | % 10 | % RETURNS 11 | % interventionSubElements: a cell array of strings containing the names 12 | % of the indicated model components. 13 | % Order is maintained. 14 | % 15 | interventionSubElements = cell(0,1); 16 | [nModifiers, nCols] = size(intervention.('definition')); 17 | for modifierCounter = 1 : nModifiers 18 | specType = intervention.('definition'){modifierCounter,1}; 19 | specName = intervention.('definition'){modifierCounter,2}; 20 | if strcmp(specType, type) 21 | interventionSubElements{length(interventionSubElements) + 1} = specName; 22 | end 23 | end 24 | end -------------------------------------------------------------------------------- /QSPToolbox/worksheet/intervention/getDoseNames.m: -------------------------------------------------------------------------------- 1 | function doseNames = getDoseNames(worksheet) 2 | % Get dose names from a model 3 | % ARGUMENTS 4 | % worksheet: a worksheet object, required 5 | % 6 | % RETURNS 7 | % doseNames: an array of cells with the dose names 8 | % 9 | 10 | allDoses = getdose(worksheet.model); 11 | nDoses = length(allDoses); 12 | doseNames = cell(nDoses,1); 13 | 14 | for doseCounter = 1 : length(doseNames) 15 | doseNames{doseCounter} = allDoses(doseCounter).('Name'); 16 | end 17 | 18 | 19 | end -------------------------------------------------------------------------------- /QSPToolbox/worksheet/intervention/getInterventionIDs.m: -------------------------------------------------------------------------------- 1 | function interventionIDs = getInterventionIDs(myWorksheet) 2 | % Get VP IDs from a model 3 | % ARGUMENTS 4 | % myWorksheet: a worksheet 5 | % 6 | % RETURNS 7 | % interventionIDs: an array of cells with the intervention names 8 | 9 | interventions = myWorksheet.interventions; 10 | [nInterventions, dummy] = size(interventions); 11 | interventionIDs = cell(1,nInterventions); 12 | for theInterventionCounter = 1 : nInterventions 13 | curIntervention = interventions{theInterventionCounter}; 14 | interventionIDs{theInterventionCounter} = curIntervention.('ID'); 15 | end 16 | 17 | 18 | end -------------------------------------------------------------------------------- /QSPToolbox/worksheet/intervention/removeInterventions.m: -------------------------------------------------------------------------------- 1 | function myWorksheet = removeInterventions(myWorksheet, myInterventionIDs) 2 | % Remove Interventions from a worksheet based on ID. Also remove any 3 | % results for that intervention and responseType elements that reference 4 | % it. 5 | % 6 | % ARGUMENTS 7 | % myWorksheet: a worksheet 8 | % interventionIDs: IDs of interventions to remove from worksheet 9 | % 10 | % RETURNS 11 | % myWorksheet: an updated worksheet without the interventions 12 | % 13 | continueFlag = true; 14 | allInterventionIDs = getInterventionIDs(myWorksheet); 15 | nInterventionsToRemove = length(unique(myInterventionIDs)); 16 | if sum(ismember(myInterventionIDs,allInterventionIDs)) < nInterventionsToRemove 17 | warning(['Require a list of unique intervention IDs all contained in worksheet in call to ',mfilesname,'. Returning input worksheet'.']) 18 | continueFlag = false; 19 | end 20 | 21 | if continueFlag 22 | interventionIndicestoRemove = nan(nInterventionsToRemove,1); 23 | responseTypeIDs = getResponseTypeIDs(myWorksheet); 24 | nResponseTypes = length(responseTypeIDs); 25 | responseTypeElementIndicesToRemove = cell(nResponseTypes,1); 26 | 27 | resultIndicestoRemove = find(ismember(allInterventionIDs,myInterventionIDs)); 28 | nWorksheetInterventions = length(allInterventionIDs); 29 | myWorksheet.interventions(resultIndicestoRemove) = []; 30 | [size1, ~] = size(myWorksheet.results); 31 | if size1 == nWorksheetInterventions 32 | myWorksheet.results(resultIndicestoRemove,:) = []; 33 | end 34 | responseTypeIndicesToRemove = []; 35 | for responseTypeCounter = 1 : nResponseTypes 36 | responseTypeElementIndicesToRemove = []; 37 | responseTypeID = responseTypeIDs{responseTypeCounter}; 38 | curResponseType = getResponseType(myWorksheet, responseTypeID); 39 | responseTypeElementIDs = getResponseTypeElementIDs(myWorksheet, responseTypeID); 40 | nResponseTypeElements = length(responseTypeElementIDs); 41 | for responseTypeElementCounter = 1: nResponseTypeElements 42 | curResponseTypeElement = curResponseType.elements{responseTypeElementCounter}; 43 | if sum(ismember(properties(curResponseTypeElement),'interventionID')) > 0 44 | if sum(ismember(myInterventionIDs,curResponseTypeElement.interventionID)) > 0 45 | responseTypeElementIndicesToRemove = [responseTypeElementIndicesToRemove,responseTypeElementCounter]; 46 | end 47 | end 48 | end 49 | if length(responseTypeElementIndicesToRemove) == nResponseTypeElements 50 | responseTypeIndicesToRemove = [responseTypeIndicesToRemove,responseTypeCounter]; 51 | elseif length(responseTypeElementIndicesToRemove) > 0 52 | myWorksheet.responseTypes{responseTypeCounter}.elements(responseTypeElementIndicesToRemove) = []; 53 | end 54 | end 55 | if length(responseTypeIndicesToRemove) > 0 56 | if length(responseTypeIndicesToRemove) < nResponseTypes 57 | myWorksheet.responseTypes(responseTypeIndicesToRemove) = []; 58 | else 59 | myWorksheet.responseTypes = cell(0,1); 60 | end 61 | end 62 | [size1, ~] = size(myWorksheet.results); 63 | if size1 == 0 64 | myWorksheet.results = {}; 65 | end 66 | end 67 | -------------------------------------------------------------------------------- /QSPToolbox/worksheet/model/getModelCompartmentIDs.m: -------------------------------------------------------------------------------- 1 | function compartmentNames = getModelCompartmentIDs(myWorksheet) 2 | % A simple function to get the compartments IDs from a model included in a 3 | % worksheet. 4 | % 5 | % ARGUMENTS 6 | % myWorksheet 7 | % 8 | % RETURNS 9 | % compartmentNames 10 | % 11 | 12 | myCompartments = get(myWorksheet.model, 'Compartments'); 13 | [nCompartments, ~] = size(myCompartments); 14 | compartmentNames = cell(1,nCompartments); 15 | for cCounter = 1 : nCompartments 16 | compartmentNames{1,cCounter} = myCompartments(cCounter).Name; 17 | end 18 | 19 | end -------------------------------------------------------------------------------- /QSPToolbox/worksheet/model/getModelObservableIDs.m: -------------------------------------------------------------------------------- 1 | function observableNames = getModelObservableIDs(myWorksheet) 2 | % A simple function to get the parameter ID's from a model included in a 3 | % worksheet. 4 | % ARGUMENTS 5 | % myWorksheet 6 | % 7 | % RETURNS 8 | % parameterNames 9 | 10 | myObservables = get(myWorksheet.model, 'Observables'); 11 | [nObservables, ~] = size(myObservables); 12 | observableNames = cell(1,nObservables); 13 | for pCounter = 1 : nObservables 14 | observableNames{1,pCounter} = myObservables(pCounter).Name; 15 | end 16 | 17 | end -------------------------------------------------------------------------------- /QSPToolbox/worksheet/model/getModelParameterIDs.m: -------------------------------------------------------------------------------- 1 | function parameterNames = getModelParameterIDs(myWorksheet) 2 | % A simple function to get the parameter ID's from a model included in a 3 | % worksheet. 4 | % ARGUMENTS 5 | % myWorksheet 6 | % 7 | % RETURNS 8 | % parameterNames 9 | 10 | myParameters = get(myWorksheet.model, 'Parameters'); 11 | [nParameters, ~] = size(myParameters); 12 | parameterNames = cell(1,nParameters); 13 | for pCounter = 1 : nParameters 14 | parameterNames{1,pCounter} = myParameters(pCounter).Name; 15 | end 16 | 17 | end -------------------------------------------------------------------------------- /QSPToolbox/worksheet/model/getModelSpeciesIDs.m: -------------------------------------------------------------------------------- 1 | function speciesNames = getModelSpeciesIDs(myWorksheet) 2 | % A simple function to get the species ID's from a model included in a 3 | % worksheet. 4 | % 5 | % ARGUMENTS 6 | % myWorksheet 7 | % 8 | % RETURNS 9 | % speciesNames 10 | % 11 | mySpecies = get(myWorksheet.model, 'Species'); 12 | [nSpecies, ~] = size(mySpecies); 13 | speciesNames = cell(1,nSpecies); 14 | for sCounter = 1 : nSpecies 15 | speciesNames{1,sCounter} = mySpecies(sCounter).Name; 16 | end 17 | 18 | end -------------------------------------------------------------------------------- /QSPToolbox/worksheet/removeDuplicateVPs.m: -------------------------------------------------------------------------------- 1 | function myWorksheet = removeDuplicateVPs(myWorksheet) 2 | % Remove VPs with duplicate base definitions and axis values. 3 | % 4 | % ARGUMENTS 5 | % myWorksheet: a worksheet 6 | % 7 | % RETURNS 8 | % copiedWorksheet 9 | % 10 | 11 | % Perform initial checks on the provided arguments 12 | flagContinue = false; 13 | 14 | if nargin > 1 15 | warning([mfilename,' requires input argument: myWorksheet. Too many arguments provided.']) 16 | elseif nargin == 0 17 | warning([mfilename,' requires input argument: myWorksheet. Insufficient arguments provided.']) 18 | else 19 | flagContinue = true; 20 | end 21 | 22 | if flagContinue 23 | allVPIDs = getVPIDs(myWorksheet); 24 | nVPs = length(allVPIDs); 25 | if length(unique(allVPIDs)) < nVPs 26 | warning(['Degenerate VP IDs in worksheet provided to ',mfilename,'.']); 27 | flagContinue = false; 28 | end 29 | end 30 | 31 | if flagContinue 32 | pointBaseVPIndices = nan(2, nVPs); 33 | baseVPVariantSets = cell(1,0); 34 | baseVPVariantSetIndices = nan(1,0); 35 | iseqarray = @(x,y) isequal(x,y); 36 | nUniqueVarSets = 0; 37 | for vpCounter = 1 : nVPs 38 | curVariants = myWorksheet.vpDef{vpCounter}.('variants'); 39 | if nUniqueVarSets > 0 40 | baseVariantsCheck = cell2mat(arrayfun(@(i) iseqarray(baseVPVariantSets{i},curVariants), 1:nUniqueVarSets,'UniformOutput',false)'); 41 | if sum(baseVariantsCheck) > 0 42 | baseVariantIndex = find(baseVariantsCheck); 43 | baseVariantIndex = baseVPVariantSetIndices(baseVariantIndex); 44 | pointBaseVPIndices(:, vpCounter) = [baseVariantIndex;vpCounter]; 45 | else 46 | pointBaseVPIndices(:, vpCounter) = [vpCounter;vpCounter]; 47 | nUniqueVarSets = nUniqueVarSets + 1; 48 | baseVPVariantSets = cat(2,baseVPVariantSets,{curVariants}); 49 | baseVPVariantSetIndices = cat(2,baseVPVariantSetIndices,vpCounter); 50 | end 51 | else 52 | pointBaseVPIndices(:, vpCounter) = [vpCounter;vpCounter]; 53 | baseVPVariantSets = cat(2,baseVPVariantSets,{curVariants}); 54 | baseVPVariantSetIndices = cat(2,baseVPVariantSetIndices,vpCounter); 55 | nUniqueVarSets = nUniqueVarSets + 1; 56 | end 57 | end 58 | allVPCoefficients = getVPCoeffs(myWorksheet); 59 | keepVPIndices = nan(1,0); 60 | for baseVPCounter = 1 : nUniqueVarSets 61 | curOriginalIndices = find(pointBaseVPIndices(1,:) == baseVPCounter); 62 | curOriginalIndices = pointBaseVPIndices(2,curOriginalIndices); 63 | vpCoeffsToTest = allVPCoefficients(:,curOriginalIndices); 64 | vpCoeffsToTest = transpose(vpCoeffsToTest); 65 | [C,IA,IC] = unique(vpCoeffsToTest,'rows'); 66 | keepVPIndices = [keepVPIndices, curOriginalIndices(IA)]; 67 | end 68 | keepVPIndices = sort(keepVPIndices,'ascend'); 69 | vpsToCopy = allVPIDs(keepVPIndices); 70 | myWorksheet = copyWorksheet(myWorksheet,vpsToCopy,true); 71 | else 72 | warning(['Could not complete ',mfilename,'. Returning original worksheet.']) 73 | copiedWorksheet = myWorksheet; 74 | end 75 | 76 | end -------------------------------------------------------------------------------- /QSPToolbox/worksheet/responseType/createResponseType.m: -------------------------------------------------------------------------------- 1 | function myWorksheet = createResponseType(myWorksheet, responseTypeID) 2 | % Create a response type and add it to the worksheet 3 | % ARGUMENTS 4 | % myWorksheet: a worksheet structure, required 5 | % responseTypeID: a simple text identifier for the response type 6 | % 7 | % RETURNS 8 | % myWorksheet: an updated worksheet with the empty response type. 9 | % 10 | newResponseType = struct(); 11 | newResponseType.ID = responseTypeID; 12 | newResponseType.elements = cell(0,1); 13 | 14 | % Don't duplicate RT ID's 15 | existingResponseTypeIDs = getResponseTypeIDs(myWorksheet); 16 | if length(find(ismember(existingResponseTypeIDs, newResponseType.ID))) == 0 17 | [dummyVar, nExistingResponseTypes] = size(existingResponseTypeIDs); 18 | myWorksheet.responseTypes{nExistingResponseTypes + 1, 1} = newResponseType; 19 | else 20 | warning('Response type with specified ID already exists, not creating a new one') 21 | end 22 | 23 | end -------------------------------------------------------------------------------- /QSPToolbox/worksheet/responseType/getResponseType.m: -------------------------------------------------------------------------------- 1 | function myResponseType = getResponseType(myWorksheet, responseTypeID) 2 | % Get response types from a model 3 | % ARGUMENTS 4 | % myWorksheet: a worksheet, required 5 | % responseTypeID 6 | % 7 | % RETURNS 8 | % responseType: the requested response type 9 | % note this is a memory copy and not an actual object 10 | 11 | responseTypes = myWorksheet.responseTypes; 12 | responseTypeIDs = getResponseTypeIDs(myWorksheet); 13 | if sum(ismember(responseTypeIDs, responseTypeID)) > 1 14 | error('Requested response type ID is degenerate') 15 | elseif sum(ismember(responseTypeIDs, responseTypeID)) < 1 16 | error('Requested response type ID is not present') 17 | else 18 | myIndex = find(ismember(responseTypeIDs, responseTypeID)); 19 | myResponseType = responseTypes{myIndex}; 20 | end 21 | 22 | end -------------------------------------------------------------------------------- /QSPToolbox/worksheet/responseType/getResponseTypeElementIDs.m: -------------------------------------------------------------------------------- 1 | function responseTypeElementIDs = getResponseTypeElementIDs(myWorksheet, responseTypeID) 2 | % Get Response Type Element IDs from a model 3 | % ARGUMENTS 4 | % myWorksheet: a worksheet object, required 5 | % responseTypeID 6 | % 7 | % RETURNS 8 | % responseTypeElementIDs: an array of cells with the response type element 9 | % names for the specified response type 10 | continueFlag = true; 11 | responseTypeElementIDs = cell(1,0); 12 | 13 | if nargin > 2 14 | warning(['Too many input arguments to ',mfilename,'. Require: myWorksheet, responseTypeID.']) 15 | continueFlag = false; 16 | elseif nargin < 2 17 | warning(['Insufficient input arguments to ',mfilename,'. myWorksheet, responseTypeID.']) 18 | continueFlag = false; 19 | end 20 | 21 | if continueFlag 22 | responseTypeIDs = getResponseTypeIDs(myWorksheet); 23 | if sum(ismember(responseTypeIDs, responseTypeID)) < 1 24 | warning('Cannot identify specified response type ID, ',responseTypeID,', in the worksheet') 25 | elseif sum(ismember(responseTypeIDs, responseTypeID)) > 1 26 | warning('Specified response type ID, ',responseTypeID,', is degenerate in the worksheet') 27 | else 28 | responseTypeIndex = find(ismember(responseTypeIDs, responseTypeID)); 29 | responseType = myWorksheet.responseTypes{responseTypeIndex}; 30 | [nResponseTypeElements, dummyVar] = size(responseType.elements); 31 | responseTypeElementIDs = cell(1,nResponseTypeElements); 32 | for rteCounter = 1 : nResponseTypeElements 33 | currte = responseType.elements{rteCounter}; 34 | responseTypeElementIDs{1,rteCounter} = currte.id; 35 | end 36 | end 37 | end 38 | 39 | end -------------------------------------------------------------------------------- /QSPToolbox/worksheet/responseType/getResponseTypeIDs.m: -------------------------------------------------------------------------------- 1 | function responseTypeIDs = getResponseTypeIDs(myWorksheet) 2 | % Get response type IDs from a model 3 | % ARGUMENTS 4 | % worksheet: a worksheet object, required 5 | % 6 | % RETURNS 7 | % responseTypeIDs: an array of cells with the response type names 8 | 9 | responseTypes = myWorksheet.responseTypes; 10 | [nResponseTypes, dummyVar] = size(responseTypes); 11 | responseTypeIDs = cell(1, nResponseTypes); 12 | for theRTcounter = 1 : length(responseTypes) 13 | curRT = responseTypes{theRTcounter,1}; 14 | responseTypeIDs{1,theRTcounter} = curRT.('ID'); 15 | end 16 | 17 | 18 | end -------------------------------------------------------------------------------- /QSPToolbox/worksheet/responseType/utility/evaluateAxisObjective.m: -------------------------------------------------------------------------------- 1 | function objectiveValue = evaluateAxisObjective(myCoefficient, targetValue) 2 | % Objective function type of evaluation for axis coefficients 3 | % 4 | % ARGUMENTS 5 | % myCoefficient: coefficient for the mechanistic axis 6 | % targetValue: target value for the axis coefficient 7 | % 8 | % RETURNS 9 | % objectiveValue: 10 | % 11 | 12 | % A small local gradient might be preferable, but then we run into 13 | % issues such as with how to best shape the well. So it's just 14 | % absolute value for now. The axes are already inherently scaled. 15 | objectiveValue = abs(myCoefficient-targetValue); 16 | end -------------------------------------------------------------------------------- /QSPToolbox/worksheet/responseType/utility/evaluateBoundsObjectiveWtIntRangeCE.m: -------------------------------------------------------------------------------- 1 | function objectiveValue = evaluateBoundsObjectiveWtIntRangeCE(myTimeVals, myYVals, myBounds) 2 | % Objective function for bounds response type elements 3 | % WtIntRange - values being included in the objective are weighted by how 4 | % far they fall outside the allowed range and 5 | % also take into consideration the interval over which they 6 | % are out-of-bounds. 7 | % CE - the penalty for out-of-bounds terms is normalized by an error term 8 | % that is constant across time points 9 | % 10 | % ARGUMENTS 11 | % myTimeVals: a vector of time values from the simulation 12 | % myYVals: a vector of simulation output values 13 | % 14 | % RETURNS 15 | % objectiveValue: a single value 16 | % 17 | 18 | epsilon = 1E-4; 19 | if isequal(isinf(myBounds),[1, 1]) 20 | % If our bounds are just infinite then there won't be a penalty, 21 | % this just passes through the VP without penalizing 22 | % them on this RTE 23 | objectiveValue = 0; 24 | else 25 | % We assume these have already been ordered 26 | lowerBound = myBounds(1); 27 | upperBound = myBounds(2); 28 | lowerBound2 = lowerBound; 29 | upperBound2 = upperBound; 30 | if isequal(isinf(myBounds),[1, 0]) 31 | % If this is one-sided, we will normalize by the larger of epsilon 32 | % or magnitude of the non-infinite bound 33 | rangeNorm = min(myBounds(1), epsilon); 34 | lowerBound2 = 0; 35 | elseif isequal(isinf(myBounds),[0, 1]) 36 | rangeNorm = min(myBounds(2), epsilon); 37 | upperBound2 = 0; 38 | else 39 | % Otherwise, we assume the upper/lower bounds are finite and 40 | % nonequal, which should be true based on the definition of the 41 | % RTE 42 | rangeNorm = max(myBounds) - min(myBounds); 43 | end 44 | % We also normalize by the time interval 45 | myTimeInterval = max(myTimeVals) - min(myTimeVals); 46 | myPenaltyValues = (myYVals > upperBound) .* (myYVals-upperBound2) + (myYVals < lowerBound) .* (lowerBound2-myYVals); 47 | if myTimeInterval > 0 48 | objectiveValue = trapz(myTimeVals,myPenaltyValues)/myTimeInterval/rangeNorm; 49 | else 50 | objectiveValue = myPenaltyValues/rangeNorm; 51 | end 52 | end -------------------------------------------------------------------------------- /QSPToolbox/worksheet/responseType/utility/evaluatePointObjectiveCV.m: -------------------------------------------------------------------------------- 1 | function objectiveValue = evaluatePointObjectiveCV(uniqueSimTime, simY, expTime, expY) 2 | % Objective function for point response type elements 3 | % CV - A "coefficeint of variation" type of objective is implemented. 4 | % We evaluate the variation in the data about the simulation at each 5 | % time point, normalized by the magnitude of the mean of the data at 6 | % the current time point 7 | % 8 | % 9 | % ARGUMENTS 10 | % uniqueSimTime: filtered to match unique values in expTime 11 | % simY: interpolated simulation values at each uniqueSimTime 12 | % expTime: experiment times for samples 13 | % expY: experimental Y values 14 | % 15 | % RETURNS 16 | % objectiveValue: a single value 17 | % 18 | nExpPoints = length(expY); 19 | objectiveValue = 0; 20 | for timeCounter = 1 : length(uniqueSimTime) 21 | curTime = uniqueSimTime(timeCounter); 22 | curY = simY(timeCounter); 23 | expIndices = find(expTime == curTime); 24 | nCurPoints = length(expIndices); 25 | % Could try different objectives, but start with the sample size 26 | % weighted coefficient of variation 27 | curVal = sqrt((sum((expY(expIndices) - curY).^2))/nCurPoints) / abs(mean(expY(expIndices))); 28 | objectiveValue = objectiveValue + curVal*nCurPoints/nExpPoints; 29 | end 30 | end -------------------------------------------------------------------------------- /QSPToolbox/worksheet/responseType/utility/evaluatePointObjectiveRange.m: -------------------------------------------------------------------------------- 1 | function objectiveValue = evaluatePointObjectiveRange(uniqueSimTime, simY, expTime, expY) 2 | % Objective function for point response type elements 3 | % Range - Whether the simulation falls within the experimental data range 4 | % at each data point is evaluated. The objective value is also 5 | % normalized by the number of time points for which we have data 6 | % 7 | % 8 | % ARGUMENTS 9 | % uniqueSimTime: filtered to match unique values in expTime 10 | % simY: interpolated simulation values at each uniqueSimTime 11 | % expTime: experiment times for samples 12 | % expY: experimental Y values 13 | % 14 | % RETURNS 15 | % objectiveValue: a single value 16 | % 17 | nExpPoints = length(expY); 18 | objectiveValue = 0; 19 | nTpoints = length(uniqueSimTime); 20 | for timeCounter = 1 : nTpoints 21 | curTime = uniqueSimTime(timeCounter); 22 | curY = simY(timeCounter); 23 | expIndices = find(expTime == curTime); 24 | nCurPoints = length(expIndices); 25 | maxval = max(expY(expIndices)); 26 | minval = min(expY(expIndices)); 27 | curVal = ((curY>maxval)+(curY 1 31 | if timeCounter < nTimePoints 32 | deltaT = (uniqueSimTime(timeCounter+1) - uniqueSimTime(timeCounter-1))/2; 33 | else 34 | deltaT = (uniqueSimTime(timeCounter) - uniqueSimTime(timeCounter-1))/2; 35 | end 36 | elseif nTimePoints > 1 37 | deltaT = (uniqueSimTime(timeCounter+1) - uniqueSimTime(timeCounter))/2; 38 | else 39 | deltaT = 1; 40 | totalTimeInterval = 1; 41 | end 42 | curTime = uniqueSimTime(timeCounter); 43 | curY = simY(timeCounter); 44 | expIndices = find(expTime == curTime); 45 | nCurPoints = length(expIndices); 46 | medVal = median(expY(expIndices)); 47 | curVal = abs(curY-medVal); 48 | objectiveValue = objectiveValue + curVal*deltaT/totalTimeInterval; 49 | rangeNorm = rangeNorm + std(expY(expIndices)); 50 | end 51 | rangeNorm = rangeNorm / nTimePoints; 52 | objectiveValue = objectiveValue / rangeNorm; 53 | end -------------------------------------------------------------------------------- /QSPToolbox/worksheet/responseType/utility/evaluatePointObjectiveWtIntRangeCE.m: -------------------------------------------------------------------------------- 1 | function objectiveValue = evaluatePointObjectiveWtIntRangeCE(uniqueSimTime, simY, expTime, expY) 2 | % Objective function for point response type elements 3 | % WtIntRange - values being included in the objective are weighted by how 4 | % far they fall outside the observed range in the data and 5 | % also take into consideration the interval between the 6 | % data time points. So data from periods of time 7 | % that are more sparsely sampled can receive more weight 8 | % CE - The penalty for simulated values falling outside the observed range 9 | % is normalized by an error term that is constant across time points, 10 | % the average standard deviation in the data 11 | % 12 | % 13 | % ARGUMENTS 14 | % uniqueSimTime: filtered to match unique values in expTime 15 | % simY: interpolated simulation values at each uniqueSimTime 16 | % expTime: experiment times for samples 17 | % expY: experimental Y values 18 | % 19 | % RETURNS 20 | % objectiveValue: a single value 21 | % 22 | nExpPoints = length(expY); 23 | objectiveValue = 0; 24 | nTimePoints = length(uniqueSimTime); 25 | rangeNorm = 0; 26 | totalTimeInterval = max(uniqueSimTime) - min(uniqueSimTime); 27 | for timeCounter = 1 : nTimePoints 28 | % It would be computationally slightly more efficient to use 29 | % convolution, but then we would also have to write up the matrix to 30 | % Take the edges into consideration. Implement this this way for now. 31 | if timeCounter > 1 32 | if timeCounter < nTimePoints 33 | deltaT = (uniqueSimTime(timeCounter+1) - uniqueSimTime(timeCounter-1))/2; 34 | else 35 | deltaT = (uniqueSimTime(timeCounter) - uniqueSimTime(timeCounter-1))/2; 36 | end 37 | elseif nTimePoints > 1 38 | deltaT = (uniqueSimTime(timeCounter+1) - uniqueSimTime(timeCounter))/2; 39 | else 40 | deltaT = 1; 41 | totalTimeInterval = 1; 42 | end 43 | curTime = uniqueSimTime(timeCounter); 44 | curY = simY(timeCounter); 45 | expIndices = find(expTime == curTime); 46 | nCurPoints = length(expIndices); 47 | maxval = max(expY(expIndices)); 48 | minval = min(expY(expIndices)); 49 | % We could normalize out of bounds 50 | % simulation points by stdev, range, etc... 51 | % just to provide a gentle push to bring these in 52 | % spec 53 | rangeNorm = rangeNorm + std(expY(expIndices)); 54 | flagTop = curY > maxval; 55 | flagBottom = curY < minval; 56 | % This was set to 0.99 prior to 12/26/15, then tried adjusting 57 | % to see if I could get more agreeable results from the optimizers. 58 | % inRangeWeight = 0.0 seems to give better results for many 59 | % scenarios 60 | inRangeWeight = 0.0; 61 | curVal = inRangeWeight*((flagTop)+(flagBottom))+(1-inRangeWeight)*(flagBottom*(minval-curY)+flagTop*(curY-maxval)); 62 | objectiveValue = objectiveValue + curVal*deltaT/totalTimeInterval; 63 | end 64 | rangeNorm = rangeNorm / nTimePoints; 65 | objectiveValue = objectiveValue / rangeNorm; 66 | end -------------------------------------------------------------------------------- /QSPToolbox/worksheet/responseType/utility/evaluatePointObjectiveWtRange.m: -------------------------------------------------------------------------------- 1 | function objectiveValue = evaluatePointObjectiveWtRange(uniqueSimTime, simY, expTime, expY) 2 | % Objective function for point response type elements 3 | % WtRange - values being included in the objective are weighted by how far 4 | % they fall outside the observed range in the data 5 | % Note "CE" is not specified. Objective values are also 6 | % normalized by an error term that is varied across time 7 | % points, the current standard deviation in the data 8 | % 9 | % ARGUMENTS 10 | % uniqueSimTime: filtered to match unique values in expTime 11 | % simY: interpolated simulation values at each uniqueSimTime 12 | % expTime: experiment times for samples 13 | % expY: experimental Y values 14 | % 15 | % RETURNS 16 | % objectiveValue: a single value 17 | % 18 | nExpPoints = length(expY); 19 | objectiveValue = 0; 20 | nTpoints = length(uniqueSimTime); 21 | for timeCounter = 1 : nTpoints 22 | curTime = uniqueSimTime(timeCounter); 23 | curY = simY(timeCounter); 24 | expIndices = find(expTime == curTime); 25 | nCurPoints = length(expIndices); 26 | maxval = max(expY(expIndices)); 27 | minval = min(expY(expIndices)); 28 | % We could normalize out of bounds 29 | % simulation points by stdev, range, etc... 30 | % just to provide a gentle push to bring these in 31 | % spec 32 | % rangeNorm = (maxval - minval); 33 | rangeNorm = std(expY(expIndices)); 34 | flagTop = curY > maxval; 35 | flagBottom = curY < minval; 36 | % This was set to 0.99 prior to 12/26, then tried adjusting 37 | % to see if I could get more agreeable results from the optimizers. 38 | inRangeWeight = 0.0; 39 | curVal = inRangeWeight*((flagTop)+(flagBottom))+(1-inRangeWeight)*(flagBottom*(minval-curY)+flagTop*(curY-maxval))/rangeNorm; 40 | %curVal = sqrt((sum((expY(expIndices) - curY).^2))/nCurPoints) / abs(mean(expY(expIndices))); 41 | objectiveValue = objectiveValue + curVal*1/nTpoints; 42 | end 43 | end -------------------------------------------------------------------------------- /QSPToolbox/worksheet/responseType/utility/evaluatePointObjectiveWtRangeCE.m: -------------------------------------------------------------------------------- 1 | function objectiveValue = evaluatePointObjectiveWtRangeCE(uniqueSimTime, simY, expTime, expY) 2 | % Objective function for point response type elements 3 | % WtRange - values being included in the objective are weighted by how far 4 | % they fall outside the observed range in the data 5 | % CE - Objective values are also normalized by an error term that is 6 | % constant across time points, the average standard deviation in the 7 | % data 8 | % 9 | % ARGUMENTS 10 | % uniqueSimTime: filtered to match unique values in expTime 11 | % simY: interpolated simulation values at each uniqueSimTime 12 | % expTime: experiment times for samples 13 | % expY: experimental Y values 14 | % 15 | % RETURNS 16 | % objectiveValue: a single value 17 | % 18 | nExpPoints = length(expY); 19 | objectiveValue = 0; 20 | nTpoints = length(uniqueSimTime); 21 | rangeNorm = 0; 22 | for timeCounter = 1 : nTpoints 23 | curTime = uniqueSimTime(timeCounter); 24 | curY = simY(timeCounter); 25 | expIndices = find(expTime == curTime); 26 | nCurPoints = length(expIndices); 27 | maxval = max(expY(expIndices)); 28 | minval = min(expY(expIndices)); 29 | % We could normalize out of bounds 30 | % simulation points by stdev, range, etc... 31 | % just to provide a gentle push to bring these in 32 | % spec 33 | % rangeNorm = (maxval - minval); 34 | rangeNorm = rangeNorm + std(expY(expIndices)); 35 | flagTop = curY > maxval; 36 | flagBottom = curY < minval; 37 | % This was set to 0.99 prior to 12/26/15, then tried adjusting 38 | % to see if I could get more agreeable results from the optimizers. 39 | % inRangeWeight = 0.0 seems to give better results for many 40 | % scenarios 41 | inRangeWeight = 0.0; 42 | curVal = inRangeWeight*((flagTop)+(flagBottom))+(1-inRangeWeight)*(flagBottom*(minval-curY)+flagTop*(curY-maxval)); 43 | %curVal = sqrt((sum((expY(expIndices) - curY).^2))/nCurPoints) / abs(mean(expY(expIndices))); 44 | objectiveValue = objectiveValue + curVal*1/nTpoints; 45 | end 46 | rangeNorm = rangeNorm / nTpoints; 47 | objectiveValue = objectiveValue / rangeNorm; 48 | end -------------------------------------------------------------------------------- /QSPToolbox/worksheet/responseType/utility/evaluateResponseType.m: -------------------------------------------------------------------------------- 1 | function myRTresult = evaluateResponseType(myWorksheet, responseTypeID, verifyFlag) 2 | % This function evaluates a response type, returning a responseTypeResult 3 | % object. 4 | % 5 | % ARGUMENTS 6 | % myWorksheet: a worksheet 7 | % responseTypeID: ID of the response type to evaluate 8 | % verifyFlag: (optional) Whether to verify the responseType: boolean 9 | % (true/false, default is false). This is an optional 10 | % step as re-verification during iterative processes 11 | % like optimization should not be necessary and could slow 12 | % optimization. 13 | % 14 | % RETURNS 15 | % myRTresult: a response type result object 16 | % 17 | 18 | flagContinue = true; 19 | if nargin > 3 20 | warning(['Too many input arguments to ',mfilename,'. Require: myWorksheet, responseTypeID.']) 21 | flagContinue = false; 22 | elseif nargin > 2 23 | flagContinue = true; 24 | elseif nargin > 1 25 | verifyFlag = false; 26 | flagContinue = true; 27 | else 28 | warning(['Insufficient input arguments to ',mfilename,'. myWorksheet, responseTypeID.']) 29 | flagContinue = false; 30 | end 31 | 32 | if flagContinue 33 | if ~islogical(verifyFlag) 34 | warning(['Invalid verifyFlag specified for ',mfilename,', a boolean (true/false) should be specified.']) 35 | end 36 | end 37 | 38 | if flagContinue 39 | if verifyFlag 40 | flagContinue = verifyResponseType(myWorksheet, responseTypeID); 41 | if ~flagContinue 42 | warning(['Verification failed for ',responseTypeID,' in ',mfilename,'.']) 43 | end 44 | end 45 | end 46 | 47 | if flagContinue 48 | myRTresult = responseTypeResult({[responseTypeID,'_result'], responseTypeID}); 49 | myRTresult = myRTresult.evaluateResponseTypeResults(myWorksheet); 50 | % myWorksheet, 51 | else 52 | warning(['Unable to run ',mfilename,'.']) 53 | myRTresult = responseTypeResult({}); 54 | end 55 | 56 | end -------------------------------------------------------------------------------- /QSPToolbox/worksheet/responseType/verifyResponseType.m: -------------------------------------------------------------------------------- 1 | function passCheck = verifyResponseType(myWorksheet, responseTypeID) 2 | % Perform a series of checks on a response type and the constituent 3 | % response type elements to make sure it is valid. 4 | % 5 | % ARGUMENTS 6 | % myWorksheet: a worksheet, required 7 | % responseTypeID 8 | % 9 | % RETURNS 10 | % passCheck: a boolean 11 | passCheck = true; 12 | 13 | if nargin > 2 14 | warning(['Too many input arguments to ',mfilename,'. Require: myWorksheet, responseTypeID.']) 15 | passCheck = false; 16 | elseif nargin < 2 17 | warning(['Insufficient input arguments to ',mfilename,'. myWorksheet, responseTypeID.']) 18 | passCheck = false; 19 | end 20 | 21 | if passCheck 22 | responseTypeIDs = getResponseTypeIDs(myWorksheet); 23 | if sum(ismember(responseTypeIDs, responseTypeID)) > 1 24 | warning(['Requested response type ID ',responseTypeID,' is degenerate. Check failed.']) 25 | passCheck = false; 26 | elseif sum(ismember(responseTypeIDs, responseTypeID)) < 1 27 | warning(['Requested response type ID ',responseTypeID,' is not present. Check failed.']) 28 | passCheck = false; 29 | end 30 | end 31 | 32 | if passCheck 33 | failedRTEs = cell(1,0); 34 | responseTypes = myWorksheet.responseTypes; 35 | myIndex = find(ismember(responseTypeIDs, responseTypeID)); 36 | myResponseType = responseTypes{myIndex}; 37 | myResponseTypeElementIDs = getResponseTypeElementIDs(myWorksheet, responseTypeID); 38 | nResponseTypeElementIDs = length(myResponseTypeElementIDs); 39 | for rteCounter = 1 : length(myResponseTypeElementIDs) 40 | myRTE = myResponseType.elements{rteCounter}; 41 | curPassCheck = myRTE.verify(myWorksheet); 42 | if ~curPassCheck 43 | passCheck = false; 44 | failedRTEs = [failedRTEs, myRTE.id]; 45 | end 46 | end 47 | if ~passCheck 48 | warning(['Verification failed for RTEs: ',strjoin(failedRTEs,', '),'.']) 49 | end 50 | end 51 | 52 | 53 | end -------------------------------------------------------------------------------- /QSPToolbox/worksheet/results/convertSimData.m: -------------------------------------------------------------------------------- 1 | function simStruct = convertSimData(simData) 2 | % Take a simResult and convert it to a format just with 2 fields: 3 | % Name and Data. Originally, I was going to use tables but ran into 4 | % maximum name length issue. 5 | % 6 | % ARGUMENTS 7 | % simData 8 | % 9 | % RETURNS 10 | % simStruct 11 | % 12 | colnames = ['time';simData.DataNames]; 13 | datavalues = [simData.Time,simData.Data]; 14 | simStruct.Data = datavalues; 15 | simStruct.Names = transpose(colnames); 16 | end -------------------------------------------------------------------------------- /QSPToolbox/worksheet/utility/calculateIndividualElementValues.m: -------------------------------------------------------------------------------- 1 | function elementValues = calculateIndividualElementValues(axisVPCoeffs,curBounds,myScale) 2 | % This function calculates values for individual elements 3 | % (parameter/initial species/compartment) values within an axis. 4 | % It is vectorized to work across all VPs in a worksheet to run 5 | % large worksheets more quickly. 6 | % Note there is no input argument proofing, this is essentially a 7 | % utility function we anticipate will be called often. 8 | % 9 | % ARGUMENTS 10 | % axisVPCoeffs: a 1xnVP vector of axis coefficients 11 | % curBounds: a 1x2 vector of lower, upper bound for the current axis 12 | % scale: axis string to indicate type of scale. Currently 13 | % anticipated are 'linear' and 'log'. Will default to 14 | % log calculation if specification is not recognized. 15 | % 16 | % RETURNS 17 | % elementValues: an 1xnVP vector of each element 18 | % (parameter/initial species/compartment) value 19 | % 20 | if strcmp(myScale,'linear') 21 | elementValues = axisVPCoeffs*(curBounds(2) - curBounds(1)) + curBounds(1); 22 | else 23 | elementValues = 10.^(axisVPCoeffs*(curBounds(2) - curBounds(1)) + curBounds(1)); 24 | end 25 | end -------------------------------------------------------------------------------- /QSPToolbox/worksheet/utility/checkNWorkers.m: -------------------------------------------------------------------------------- 1 | function mySimulateOptions = checkNWorkers(mySimulateOptions) 2 | % This is a "utility function" that should not be called directly. 3 | % This is used to check the number of workers specified 4 | % and if not, check how many are available. 5 | % 6 | % ARGUMENTS 7 | % mySimulateOptions: a simulateOptions object 8 | % 9 | % RETURNS 10 | % mySimulateOptions: a simulateOptions object with the 11 | % number of workers checked 12 | % 13 | 14 | mySettings = parallel.Settings; 15 | clusterCheck = parcluster(mySimulateOptions.clusterID); 16 | if isnan(mySimulateOptions.nWorkers) 17 | if isnumeric(mySettings.Pool.PreferredNumWorkers) 18 | % First try getting the value from parallel.settings, but cap in 19 | % case a silly value was entered. 20 | if isa(clusterCheck, 'parallel.cluster.Local') 21 | mySimulateOptions.nWorkers = min(clusterCheck.NumWorkers, ... 22 | mySettings.Pool.PreferredNumWorkers); 23 | else 24 | mySimulateOptions.nWorkers = min(clusterCheck.MaxNumWorkers, ... 25 | mySettings.Pool.PreferredNumWorkers); 26 | end 27 | else 28 | mySimulateOptions.nWorkers = clusterCheck.NumWorkers; 29 | end 30 | % The local scheduler tends to be listed this way, but this is not 31 | % guaranteed. This code is no longer needed but is 32 | % kept for reference. 33 | % mySchedulerComponent = [mySimulateOptions.clusterID,'SchedulerComponent']; 34 | 35 | else 36 | % Otherwise, check that the number of workers specified 37 | % doesn't exceed any pre-set maximums. 38 | if isnumeric(mySettings.Pool.PreferredNumWorkers) 39 | % First try getting the value from parallel.settings, but cap in 40 | % case a silly value was entered. 41 | if isa(clusterCheck, 'parallel.cluster.Local') 42 | mySimulateOptions.nWorkers = min(mySimulateOptions.nWorkers, min(clusterCheck.NumWorkers, mySettings.Pool.PreferredNumWorkers)); 43 | else 44 | mySimulateOptions.nWorkers = min(mySimulateOptions.nWorkers, min(clusterCheck.MaxNumWorkers, mySettings.Pool.PreferredNumWorkers)); 45 | end 46 | else 47 | if isa(clusterCheck, 'parallel.cluster.Local') 48 | mySimulateOptions.nWorkers = min(mySimulateOptions.nWorkers, clusterCheck.NumWorkers); 49 | else 50 | mySimulateOptions.nWorkers = min(mySimulateOptions.nWorkers, clusterCheck.MaxNumWorkers); 51 | end 52 | end 53 | end 54 | -------------------------------------------------------------------------------- /QSPToolbox/worksheet/utility/getOptimizationAxes.m: -------------------------------------------------------------------------------- 1 | function [indicesForVaried, boundsForVaried, axisScale] = getOptimizationAxes(myWorksheet, mySimulateOptions) 2 | 3 | optimizeAxisIDs = mySimulateOptions.optimizeAxisIDs; 4 | allInterventionIDs = getInterventionIDs(myWorksheet); 5 | nInterventions = length(allInterventionIDs); 6 | allAxisIDs = getAxisDefIDs(myWorksheet); 7 | nOptimizeAxes = length(optimizeAxisIDs); 8 | % indicesForVaried will be N axes X M interventions 9 | % as interventions may 10 | % may overwrite some of the parameters included in the axes, which 11 | % we will need to account for in the optimization process 12 | indicesForVaried = cell(nOptimizeAxes, nInterventions); 13 | % We make an additional cell for bounds 14 | boundsForVaried = cell(nOptimizeAxes, nInterventions); 15 | axisScale = cell(nOptimizeAxes, 1); 16 | for axisCounter = 1 : nOptimizeAxes 17 | myAxisDefID = optimizeAxisIDs{axisCounter}; 18 | curAxisDef = getAxisDef(myWorksheet, myAxisDefID); 19 | axisIndices = nan(1,0); 20 | axisBounds = cell(1,0); 21 | axisScale{axisCounter} = curAxisDef.scale; 22 | for eCounter = 1 : length(curAxisDef.elementNames) 23 | curElementName = curAxisDef.elementNames{eCounter}; 24 | curElementType = curAxisDef.elementTypes{eCounter}; 25 | axisBounds = [axisBounds,curAxisDef.bounds{eCounter}]; 26 | theIndices = find(ismember(myWorksheet.compiled.elements(:,1), curElementName) & ismember(myWorksheet.compiled.elements(:,2), curElementType)); 27 | if length(theIndices) > 0 28 | axisIndices = cat(2,axisIndices,theIndices); 29 | % It should not be possible not to find the axis index 30 | end 31 | end 32 | for interventionCounter = 1 : nInterventions 33 | curIntervention = myWorksheet.interventions{interventionCounter}; 34 | [nrows, ncols] = size(curIntervention); 35 | interventionVariants = extractInterventionTypeElements(curIntervention, 'VARIANT'); 36 | interventionElementValues = flattenVariantstoElements(myWorksheet, interventionVariants); 37 | checkedAxisIndices = nan(1,0); 38 | checkedAxisBounds = cell(1,0); 39 | for eCounter = 1 : length(axisIndices) 40 | indexToCheck = axisIndices(eCounter); 41 | nameToCheck = myWorksheet.compiled.elements{indexToCheck, 1}; 42 | typeToCheck = myWorksheet.compiled.elements{indexToCheck, 2}; 43 | nOverwriteIndices = sum(ismember(interventionElementValues(:,1),nameToCheck) & ismember(interventionElementValues(:,2),typeToCheck)); 44 | if nOverwriteIndices < 1 45 | checkedAxisIndices = cat(2, checkedAxisIndices, indexToCheck); 46 | checkedAxisBounds = [checkedAxisBounds, axisBounds{eCounter}]; 47 | % else 48 | % If we don't pass the check, the intervention will 49 | % overwrite the axis element, so we don't add this 50 | % element as a variable 51 | % 1; 52 | end 53 | end 54 | indicesForVaried{axisCounter,interventionCounter} = checkedAxisIndices; 55 | boundsForVaried{axisCounter,interventionCounter} = checkedAxisBounds; 56 | end 57 | end 58 | end -------------------------------------------------------------------------------- /QSPToolbox/worksheet/utility/getUniqueBaseVPVariantSets.m: -------------------------------------------------------------------------------- 1 | function [pointBaseVPIndices, baseVPVariantSets] = getUniqueBaseVPVariantSets(myWorksheet, flagKeepVP) 2 | % This utility function is helpful for collapsing down a set of VP 3 | % variant sets which may be repeated in the VP definitions. 4 | % 5 | % NOTE THIS IS A UTILITY FUNCTION AND NOT INTENDED TO BE CALLED DIRECTLY 6 | % BY TOOLBOX USERS 7 | % 8 | % ARGUMENTS 9 | % myWorksheet: a worksheet 10 | % flagKeepVP: a 1xnVP matrix of 1/0 indicating whether to keep a VP. 11 | % 12 | % RETURNS 13 | % pointBaseVPIndices: a 2xnVP matrix pointing to the each first unique 14 | % base VP and subsequent VPs with identical variants 15 | % sets 16 | % row 1: base VP index 17 | % row 2: VP index 18 | % baseVPVariantSets: base VP variant sets; that is, variant sets for 19 | % those unique VP indices on row 1 20 | % 21 | % 22 | 23 | vpIDs = getVPIDs(myWorksheet); 24 | nVPs = length(vpIDs); 25 | 26 | pointBaseVPIndices = nan(2, nVPs); 27 | baseVPVariantSets = cell(1,0); 28 | baseVPVariantSetIndices = nan(1,0); 29 | iseqarray = @(x,y) isequal(x,y); 30 | nUniqueVarSets = 0; 31 | for vpCounter = 1 : nVPs 32 | % If we are just running a subset of a large worksheet we 33 | % don't want to spend time here. 34 | if flagKeepVP(vpCounter) 35 | curVariants = myWorksheet.vpDef{vpCounter}.('variants'); 36 | if nUniqueVarSets > 0 37 | baseVariantsCheck = cell2mat(arrayfun(@(i) iseqarray(baseVPVariantSets{i},curVariants), 1:nUniqueVarSets,'UniformOutput',false)'); 38 | if sum(baseVariantsCheck) > 0 39 | baseVariantIndex = find(baseVariantsCheck); 40 | baseVariantIndex = baseVPVariantSetIndices(baseVariantIndex); 41 | pointBaseVPIndices(:, vpCounter) = [baseVariantIndex;vpCounter]; 42 | else 43 | pointBaseVPIndices(:, vpCounter) = [vpCounter;vpCounter]; 44 | nUniqueVarSets = nUniqueVarSets + 1; 45 | baseVPVariantSets = cat(2,baseVPVariantSets,{curVariants}); 46 | baseVPVariantSetIndices = cat(2,baseVPVariantSetIndices,vpCounter); 47 | end 48 | else 49 | pointBaseVPIndices(:, vpCounter) = [vpCounter;vpCounter]; 50 | baseVPVariantSets = cat(2,baseVPVariantSets,{curVariants}); 51 | baseVPVariantSetIndices = cat(2,baseVPVariantSetIndices,vpCounter); 52 | nUniqueVarSets = nUniqueVarSets + 1; 53 | end 54 | end 55 | end 56 | % We could still have nan's, for example if we didn't want to keep/simulate 57 | % a VP. 58 | keepCols = find((~isnan(pointBaseVPIndices(1,:)) & ~isnan(pointBaseVPIndices(2,:)))); 59 | pointBaseVPIndices = pointBaseVPIndices(:,keepCols); 60 | 61 | end -------------------------------------------------------------------------------- /QSPToolbox/worksheet/utility/particleSwarmCohortWrapper.m: -------------------------------------------------------------------------------- 1 | function [x,fval,exitFlag,swarm] = particleSwarmCohortWrapper(fun, nvars, lb, ub, userOptions) 2 | % This is a wrapper to call particle swarm and keep the last returned 3 | % swarm, which isn't available in the userOptions. 4 | 5 | swarm = []; 6 | userOptions.OutputFcn = @outputFunction; 7 | [x,fval,exitFlag,output] = particleswarm(fun, nvars, lb, ub, userOptions); 8 | 9 | function stop = outputFunction(optimValues, state) 10 | stop = false; 11 | swarm = optimValues.swarm; 12 | end 13 | end -------------------------------------------------------------------------------- /QSPToolbox/worksheet/utility/runSingleSimulation.m: -------------------------------------------------------------------------------- 1 | function simResult = runSingleSimulation(exportedModel, currentModelValues, curDoses, mySaveElementResultIDs) 2 | % This is a "utility function" that should be called directly. 3 | % This is called following preprocessing to run a single simulation 4 | % 5 | % ARGUMENTS 6 | % exportedModel: an exported (accelerated) simbiology model object 7 | % currentModelValues: a nModelElements matrix of values 8 | % curDoses: a dose array 9 | % mySaveElementResultIDs a cell array of variable names 10 | % 11 | % 12 | % RETURNS 13 | % simResult: a simulation result structure 14 | % 15 | 16 | try 17 | simData = simulate(exportedModel, currentModelValues, curDoses); 18 | simData = convertSimData(simData); 19 | % Reformat results into the desired data format 20 | if ~isempty(mySaveElementResultIDs) 21 | [~, keepIndices] = ismember(['time',mySaveElementResultIDs], simData.Names); 22 | simData.Names = simData.Names(keepIndices); 23 | simData.Data = simData.Data(:,keepIndices); 24 | end 25 | flagSimData = verifySimData(simData, exportedModel.SimulationOptions.StopTime); 26 | % If the simulation doesn't complete the entire 27 | % specified length of simulated time, then we need to 28 | % flag this. For now, we only keep results 29 | % for simulations that can complete. 30 | if ~flagSimData 31 | simResult = []; 32 | else 33 | simResult = simData; 34 | end 35 | catch 36 | % If the simulation fails, we need to move on 37 | simResult = []; 38 | end 39 | end 40 | -------------------------------------------------------------------------------- /QSPToolbox/worksheet/utility/verifyFullResults.m: -------------------------------------------------------------------------------- 1 | function fullResultsFlag = verifyFullResults(myWorksheet) 2 | % Check whether a worksheet has a fully populated results field. 3 | % 4 | % ARGUMENTS 5 | % myWorksheet: a worksheet 6 | % 7 | % RETURNS 8 | % fullResultsFlag: a (true/false) value indicating whether the results 9 | % are fully populated. 10 | % 11 | 12 | fullResultsFlag = false; 13 | vpIDs = getVPIDs(myWorksheet); 14 | interventionDefinitions = myWorksheet.interventions; 15 | nVPs = length(vpIDs); 16 | nInterventions = length(interventionDefinitions); 17 | %[nInterventionResults, nVPResults] = size(myWorksheet.results); 18 | myResultClasses = cellfun(@class,myWorksheet.results, 'UniformOutput', false); 19 | flagVPcheck = sum(strcmp(myResultClasses,'struct'),1); 20 | flagVPcheck = (flagVPcheck == nInterventions); 21 | if sum(flagVPcheck) == nVPs 22 | fullResultsFlag = true; 23 | end 24 | end -------------------------------------------------------------------------------- /QSPToolbox/worksheet/utility/verifySimData.m: -------------------------------------------------------------------------------- 1 | function flagPass = verifySimData(simData, stopTime) 2 | % A simple function to verify simData, indicates complete simulation 3 | % results are available. 4 | 5 | timeIndex = find(ismember(simData.Names,'time')); 6 | 7 | if max(simData.Data(:,timeIndex)) < stopTime 8 | flagPass = false; 9 | elseif length(simData.Data(:,timeIndex)) < 1 10 | flagPass = false; 11 | else 12 | flagPass = true; 13 | end 14 | 15 | end -------------------------------------------------------------------------------- /QSPToolbox/worksheet/variant/getVariantNames.m: -------------------------------------------------------------------------------- 1 | function variantNames = getVariantNames(worksheet, variantType) 2 | % Get variant names from a model, subject to the constraint 3 | % to select variants that start with "prefix" 4 | % ARGUMENTS 5 | % worksheet: a worksheet object, required 6 | % variantType: optional string. If provided, variants with that prefix 7 | % will be returned. Otherwise, if the prefix does not 8 | % match available prefixes or if prefix is not provided 9 | % all model variants will be matched 10 | % 11 | % RETURNS 12 | % variantNames: an array of cells with the variant names; aka typeValueSets 13 | 14 | variant_delimiter = worksheet.variantProps.delimiter; 15 | % 16 | if nargin < 2 17 | variantType = ''; 18 | end 19 | 20 | variantNames = cell(0,1); 21 | 22 | variants = worksheet.model.variants; 23 | [n_variants, dummy] = size(variants); 24 | allvariantNames = cell(n_variants,1); 25 | 26 | variantTypes = worksheet.variantProps.variantTypes; 27 | 28 | for i = 1 : n_variants 29 | current_variant_name = variants(i).Name; 30 | allvariantNames{i} = current_variant_name; 31 | end 32 | 33 | if length(variantType) > 0; 34 | if length(find(ismember(variantTypes, variantType))) > 0 35 | the_prefixes = cell(n_variants, 1); 36 | for i = 1 : n_variants 37 | split_values = strsplit(allvariantNames{i}, variant_delimiter); 38 | the_prefixes(i) = split_values(1); 39 | end 40 | the_indices = find(ismember(the_prefixes, variantType)); 41 | variantNames = allvariantNames(the_indices); 42 | else 43 | variantNames = allvariantNames; 44 | end 45 | 46 | else 47 | variantNames = allvariantNames; 48 | end 49 | 50 | 51 | end -------------------------------------------------------------------------------- /QSPToolbox/worksheet/variant/getVariantTypeElements.m: -------------------------------------------------------------------------------- 1 | function variantTypeElements = getVariantTypeElements(myWorksheet, variantTypeName) 2 | % This function is developed to look up a variant type and get all of the 3 | % associated parameters, species, compartments, generally referred to as 4 | % elements. We also check that the included 5 | % elements are consistent across the value sets of a variant type. 6 | % 7 | % ARGUMENTS 8 | % myWorksheet: a worksheet 9 | % variantTypeName: a variant type 10 | % 11 | % RETURNS 12 | % variantTypeElements: a cell array of strings with the components of the 13 | % variant type. 14 | % 15 | 16 | 17 | flagContinue = false; 18 | 19 | % First check input arguments 20 | if nargin > 2 21 | warning(['Too many input arguments to',mfilename,'. Require: myWorksheet, variantTypeName.']) 22 | elseif nargin > 1 23 | flagContinue = true; 24 | else 25 | warning(['Insufficient input arguments to',mfilename,'. Require: myWorksheet, variantTypeName.']) 26 | end 27 | 28 | variantTypeElements = cell(0,2); 29 | 30 | if flagContinue 31 | variantDelimiter = myWorksheet.variantProps.delimiter; 32 | variantNames = myWorksheet.variantProps.typeValueSets; 33 | variantTypes = cell(length(variantNames),1); 34 | for variantCounter = 1 : length(variantNames) 35 | % Scan through all of the model variants 36 | curVariantName = variantNames{variantCounter}; 37 | curVariantSplit = strsplit(curVariantName, variantDelimiter); 38 | curVariantType = curVariantSplit{1}; 39 | variantTypes{variantCounter} = curVariantType; 40 | % Check is the variant is of the right type 41 | if strcmp(curVariantType, variantTypeName) 42 | curVariantCell = myWorksheet.model.variants(variantCounter).('Content'); 43 | curVariantElements = cell(length(curVariantCell),2); 44 | % Scan through all of the current variant's parameters 45 | for curVariantElementNumber = 1 : length(curVariantCell) 46 | curVariantRow = curVariantCell{curVariantElementNumber}; 47 | % Get the name 48 | curVariantElements{curVariantElementNumber,1} = curVariantRow{2}; 49 | % Get the type: parameter, species, compartment 50 | curVariantElements{curVariantElementNumber,1} = curVariantRow{2}; 51 | curVariantElements{curVariantElementNumber,2} = curVariantRow{1}; 52 | end 53 | [nrow, ncol] = size(variantTypeElements); 54 | if nrow == 0 55 | variantTypeElements = curVariantElements; 56 | % If the names match we are OK 57 | elseif length(intersect(variantTypeElements(:,1), curVariantElements(:,1))) ~= length(variantTypeElements(:,1)) 58 | warning(['Inconsistency in variant elements noted for model variant: ',curVariantName,'.']); 59 | variantTypeElements = union(variantTypeElements, curVariantElements); 60 | end 61 | end 62 | end 63 | else 64 | warning([mfilename,' could not complete. Returning empty cell array.']) 65 | end 66 | end 67 | 68 | 69 | 70 | 71 | 72 | 73 | -------------------------------------------------------------------------------- /QSPToolbox/worksheet/variant/getVariantTypes.m: -------------------------------------------------------------------------------- 1 | function variantTypes = getVariantTypes(myWorksheet) 2 | % Scan a worksheet and return all of the variant types. 3 | % ARGUMENTS 4 | % myWorksheet 5 | % 6 | % RETURNS 7 | % variantTypes 8 | variant_delimiter = myWorksheet.variantProps.delimiter; 9 | 10 | variants = myWorksheet.model.variants; 11 | [n_variants, dummy] = size(variants); 12 | variant_names = cell(n_variants,1); 13 | variantTypes = cell(0,1); 14 | for i = 1 : n_variants 15 | current_variant_name = variants(i).Name; 16 | variant_names{i} = current_variant_name; 17 | variant_name_split = strsplit(current_variant_name, variant_delimiter); 18 | current_variant_prefix = variant_name_split{1}; 19 | if length(find(ismember(variantTypes,current_variant_prefix))) < 1 20 | n_variant_types = length(variantTypes); 21 | variantTypes{n_variant_types + 1,1} = current_variant_prefix; 22 | end 23 | end 24 | 25 | 26 | end -------------------------------------------------------------------------------- /QSPToolbox/worksheet/vp/getVP.m: -------------------------------------------------------------------------------- 1 | function myVP = getVP(myWorksheet, vpID) 2 | % Get VP from a model 3 | % ARGUMENTS 4 | % myWorksheet: a worksheet, required 5 | % vpID: String identifier for the VP 6 | % 7 | % RETURNS 8 | % myVP: the indicated VP 9 | 10 | vpIDs = getVPIDs(myWorksheet); 11 | if sum(ismember(vpIDs, vpID)) < 1 12 | error('Specified VP ID not in model') 13 | elseif sum(ismember(vpIDs, vpID)) > 1 14 | error('Specified VP ID degenerate in model') 15 | else 16 | vpIndex = find(ismember(vpIDs, vpID)); 17 | myVP = myWorksheet.vpDef{vpIndex}; 18 | end -------------------------------------------------------------------------------- /QSPToolbox/worksheet/vp/getVPIDs.m: -------------------------------------------------------------------------------- 1 | function vpIDs = getVPIDs(myWorksheet) 2 | % Get VP IDs from a model 3 | % ARGUMENTS 4 | % myWorksheet: a worksheet 5 | % 6 | % RETURNS 7 | % vpIDs: an array of cells with the vp names 8 | 9 | VPs = myWorksheet.vpDef; 10 | vpIDs = cell(1, length(VPs)); 11 | for theVPcounter = 1 : length(VPs) 12 | curVP = VPs{theVPcounter}; 13 | vpIDs{theVPcounter} = curVP.('ID'); 14 | end 15 | 16 | 17 | end -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | QSP Toolbox 2 | ============= 3 | Quantitative Systems Pharmacology Toolbox 4 | ------------- 5 | 6 | This toolbox was developed to support Quantitative Systems Pharmacology work. 7 | 8 | ## Current system requirements: 9 | -MATLAB 2022a (other releases not fully supported, good compatibility back to 2018b) 10 | Required MATLAB toolboxes: 11 | -SimBiology 12 | -Optimization 13 | -Global Optimization 14 | -Parallel Computing 15 | -Statistics and Machine Learning 16 | 17 | ## Tutorials and documentation: 18 | -There are several tutorials located in the examples folder. 19 | -Currently, functions are primarily documented in-line in MATLAB (i.e. type "help myFunction" following initialization). 20 | -The below AAPs J publication is a helpful reference to get started. Note the repository code is updated since the paper. 21 | 22 | ## How to cite: 23 | If this is useful for you, and you publish resulting work, please cite your usage of this tool. 24 | The most relevant paper is currently: 25 | 26 | Cheng Y, et al. (2017) QSP Toolbox: Computational Implementation of Integrated 27 | Workflow Components for Deploying Multi-Scale Mechanistic Models. AAPS J 19(4), 1002-1016. 28 | 29 | ## How to contribute: 30 | -We are evaluating allowing others to contribute to the development on a case-by-case basis. 31 | -We will likely require a Contributor License Agreement with the intent all resulting work will be equally available for others. 32 | -Please contact us to contribute, or with related inquiries. The current contact is brian(dot)schmidt{at}bms{dot}com. 33 | 34 | ## Other notes for our development efforts: 35 | -The current fully public version corresponds to rev1368 from the in-house development repository. 36 | 37 | ## To install: 38 | -Once you download, add the root directory (QSPToolbox folder) to your MATLAB path. 39 | -Type "initQSPToolbox" in MATLAB to initialize the QSP Toolbox for use. 40 | --------------------------------------------------------------------------------