1 //
2 //  metrosichel.cpp
3 //  Mothur
4 //
5 //  Created by Sarah Westcott on 5/3/19.
6 //  Copyright © 2019 Schloss Lab. All rights reserved.
7 //
8 
9 #include "metrosichel.hpp"
10 
11 /***********************************************************************/
MetroSichel(int af,double siga,double sigb,double sigg,double sigS,int n,string st)12 MetroSichel::MetroSichel(int af, double siga, double sigb, double sigg, double sigS, int n, string st) : sigmaA(siga), sigmaB(sigb), sigmaG(sigg), sigmaS(sigS), nIters(n), outFileStub(st), fitIters(af), DiversityCalculator(false) {}
13 /***********************************************************************/
14 
15 
16 
17 #ifdef USE_GSL
18 /***********************************************************************/
nLogLikelihood3(const gsl_vector * x,void * params)19 double nLogLikelihood3(const gsl_vector * x, void * params)
20 {
21     double dAlpha  = gsl_vector_get(x,0), dBeta = gsl_vector_get(x,1);
22     double dGamma  = gsl_vector_get(x,2);
23     int    nS = (int) floor(gsl_vector_get(x, 3));
24     t_Data *ptData = (t_Data *) params;
25     int    i       = 0;
26     double dLogL   = 0.0;
27     double dLog0 = 0.0, dLog1 = 0.0, dLog2 = 0.0, dLog3 = 0.0;
28 
29     if(dAlpha <= 0.0 || dBeta <= 0.0){
30         return PENALTY;
31     }
32 
33     DiversityUtils dutils("metrosichel");
34 
35     for(i = 0; i < ptData->nNA; i++){
36 
37         if (dutils.m->getControl_pressed()) { break; }
38 
39         double dLogP = 0.0;
40         int    nA    = ptData->aanAbund[i][0];
41 
42         dLogP = dutils.logLikelihood(nA, dAlpha, dBeta, dGamma);
43 
44         dLogL += ((double) ptData->aanAbund[i][1])*dLogP;
45 
46         dLogL -= gsl_sf_lnfact(ptData->aanAbund[i][1]);
47 
48     }
49 
50     dLog0 = dutils.logLikelihood(0, dAlpha, dBeta, dGamma);
51 
52     dLog1 = (nS - ptData->nL)*dLog0;
53 
54     dLog2 = - gsl_sf_lnfact(nS - ptData->nL);
55 
56     dLog3 = gsl_sf_lnfact(nS);
57 
58     dLogL += dLog1 + dLog2 + dLog3;
59 
60     /*return*/
61     return -dLogL;
62 }
63 /***********************************************************************/
negLogLikelihood3(double dAlpha,double dBeta,double dGamma,int nS,void * params)64 double negLogLikelihood3(double dAlpha, double dBeta, double dGamma, int nS, void * params)
65 {
66     t_Data *ptData = (t_Data *) params;
67     int    i       = 0;
68     double dLogL   = 0.0;
69     double dLog0 = 0.0, dLog1 = 0.0, dLog2 = 0.0, dLog3 = 0.0;
70 
71     if(dAlpha <= 0.0 || dBeta <= 0.0){
72         return PENALTY;
73     }
74 
75     DiversityUtils dutils("metrosichel");
76 
77     for(i = 0; i < ptData->nNA; i++){
78 
79         if (dutils.m->getControl_pressed()) { break; }
80 
81         double dLogP = 0.0;
82         int    nA    = ptData->aanAbund[i][0];
83 
84         dLogP = dutils.logLikelihood(nA, dAlpha, dBeta, dGamma);
85 
86         dLogL += ((double) ptData->aanAbund[i][1])*dLogP;
87 
88         dLogL -= gsl_sf_lnfact(ptData->aanAbund[i][1]);
89 
90     }
91 
92     dLog0 = dutils.logLikelihood(0, dAlpha, dBeta, dGamma);
93 
94     dLog1 = (nS - ptData->nL)*dLog0;
95 
96     dLog2 = - gsl_sf_lnfact(nS - ptData->nL);
97 
98     dLog3 = gsl_sf_lnfact(nS);
99 
100     dLogL += dLog1 + dLog2 + dLog3;
101 
102     /*return*/
103     return -dLogL;
104 }
105 /***********************************************************************/
metropolis3(void * pvInitMetro)106 void* metropolis3 (void * pvInitMetro)
107 {
108     t_MetroInit *ptMetroInit  = (t_MetroInit *) pvInitMetro;
109     gsl_vector  *ptX          = ptMetroInit->ptX;
110     t_Data      *ptData       = ptMetroInit->ptData;
111     t_Params    *ptParams     = ptMetroInit->ptParams;
112     gsl_vector  *ptXDash      = gsl_vector_alloc(4); /*proposal*/
113     char *szSampleFile = (char *) malloc(1024*sizeof(char));
114     const gsl_rng_type *T;
115     gsl_rng            *ptGSLRNG;
116     int nS = 0, nSDash = 0, nIter = 0;
117     double dRand = 0.0, dNLL = 0.0;
118     void   *pvRet = NULL;
119 
120     /*set up random number generator*/
121     T        = gsl_rng_default;
122     ptGSLRNG = gsl_rng_alloc (T);
123 
124     nS = (int) floor(gsl_vector_get(ptX,3));
125 
126     dNLL = negLogLikelihood3(gsl_vector_get(ptX,0), gsl_vector_get(ptX,1), gsl_vector_get(ptX,2), nS,(void*) ptData);
127 
128     string filename = ptParams->szOutFileStub + "_" + toString(ptMetroInit->nThread) + ".sample";
129 
130     ofstream out; Utils util; util.openOutputFile(filename, out);
131     out.setf(ios::fixed, ios::floatfield); out.setf(ios::showpoint);
132 
133     /*seed random number generator*/
134     gsl_rng_set(ptGSLRNG, ptMetroInit->lSeed);
135 
136     DiversityUtils dutils("metrosichel");
137 
138     /*now perform simple Metropolis algorithm*/
139     while(nIter < ptParams->nIter){
140         double dA = 0.0, dNLLDash = 0.0;
141 
142         if (dutils.m->getControl_pressed()) { break; }
143 
144         dutils.getProposal(ptGSLRNG, ptXDash, ptX, &nSDash, nS, ptParams);
145 
146         dNLLDash = negLogLikelihood3(gsl_vector_get(ptXDash,0), gsl_vector_get(ptXDash,1), gsl_vector_get(ptXDash,2), nSDash, (void*) ptData);
147 
148         dA = exp(dNLL - dNLLDash);
149         if(dA > 1.0){
150             dA = 1.0;
151         }
152 
153         dRand = gsl_rng_uniform(ptGSLRNG);
154 
155         if(dRand < dA){
156             gsl_vector_memcpy(ptX, ptXDash);
157             nS = nSDash;
158             dNLL = dNLLDash;
159             ptMetroInit->nAccepted++;
160         }
161 
162         if(nIter % 10 == 0){
163             out << nIter << "," << gsl_vector_get(ptX, 0) << "," << gsl_vector_get(ptX, 1) << "," << gsl_vector_get(ptX, 2) << "," << nS << "," << dNLL << endl;
164         }
165 
166         nIter++;
167     }
168 
169     out.close();
170 
171     /*free up allocated memory*/
172     gsl_vector_free(ptXDash);
173     free(szSampleFile);
174     gsl_rng_free(ptGSLRNG);
175 
176     return pvRet;
177 }
178 #endif
179 /***********************************************************************/
getValues(SAbundVector * rank)180 vector<string> MetroSichel::getValues(SAbundVector* rank){
181     try {
182 
183         t_Params tParams; tParams.nIter = nIters; tParams.dSigmaX = sigmaA; tParams.dSigmaY = sigmaB; tParams.dSigmaN = sigmaG; tParams.dSigmaS = sigmaS; tParams.szOutFileStub = outFileStub; tParams.lSeed = m->getRandomSeed();
184         t_Data   tData;
185 
186         int bestSample = 0;
187 
188 #ifdef USE_GSL
189 
190         DiversityUtils dutils("metrosichel");
191 
192         dutils.loadAbundance(&tData, rank);
193 
194         int sampled = rank->getNumSeqs(); //nj
195         int numOTUs = rank->getNumBins(); //nl
196 
197         gsl_vector* ptX = gsl_vector_alloc(4); /*parameter estimates*/
198 
199         gsl_rng_env_setup();
200         gsl_set_error_handler_off();
201 
202         /*set initial estimates for parameters*/
203         gsl_vector_set(ptX, 0, 0.1); //INIT_A
204         gsl_vector_set(ptX, 1, 1.0); //INIT_B
205         gsl_vector_set(ptX, 2, -0.5); //INIT_G
206         gsl_vector_set(ptX, 3, numOTUs*2);
207 
208         double chaoResult = dutils.chao(&tData);
209         m->mothurOut("\nMetroSichel - D = " + toString(numOTUs) + " L = " + toString(sampled) +  " Chao = " + toString(chaoResult) +  "\n");
210 
211         dutils.minimiseSimplex(ptX, 4, (void*) &tData, &nLogLikelihood3, 0.1, 1.0e-5, 100000);
212         vector<double> parameterResults  = dutils.outputResults(ptX, &tData, &nLogLikelihood3);
213 
214 
215         if(tParams.nIter > 0){
216 
217             vector<double> acceptanceRates = dutils.mcmc(&tParams, &tData, ptX, &metropolis3);
218 
219             if (fitIters != 0) { bestSample = dutils.fitSigma(acceptanceRates, parameterResults, fitIters, &tParams, &tData, ptX, &metropolis3); }
220         }
221 
222 
223         /*free up allocated memory*/
224         gsl_vector_free(ptX);
225 
226         dutils.freeAbundance(&tData);
227 
228 #endif
229 
230         outputs.push_back(outFileStub + "_" + toString(bestSample) + ".sample");
231         if (bestSample == 0) {  outputs.push_back(outFileStub + "_1.sample"); outputs.push_back(outFileStub + "_2.sample");  }
232         else if (bestSample == 1) {  outputs.push_back(outFileStub + "_0.sample"); outputs.push_back(outFileStub + "_2.sample");  }
233         else if (bestSample == 2) {  outputs.push_back(outFileStub + "_0.sample"); outputs.push_back(outFileStub + "_1.sample");  }
234 
235         return outputs;
236     }
237     catch(exception& e) {
238         m->errorOut(e, "MetroSichel", "getValues");
239         exit(1);
240     }
241 }
242 /***********************************************************************/
243