Skip to content

Commit 4de229b

Browse files
committed
Full reimplementation of H2MM, in C, with wrappers for Python and use from command line.
This code is substantially faster.
1 parent a5d9d79 commit 4de229b

21 files changed

Lines changed: 56182 additions & 5553 deletions

.ipynb_checkpoints/Example-H2MM-Analysis-ImportH2MMcode-checkpoint.ipynb

Lines changed: 1267 additions & 0 deletions
Large diffs are not rendered by default.

.ipynb_checkpoints/H2MM-DecayFitting-FRETBurstsModules-checkpoint.ipynb

Lines changed: 4896 additions & 0 deletions
Large diffs are not rendered by default.

.ipynb_checkpoints/H2MM-DecayFitting-MultiChannel-checkpoint.ipynb

Lines changed: 10766 additions & 0 deletions
Large diffs are not rendered by default.

.ipynb_checkpoints/H2MM-DecayFitting-checkpoint.ipynb

Lines changed: 723 additions & 0 deletions
Large diffs are not rendered by default.

C_H2MM.c

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
// File: C_H2MM.c
2+
// Author: Paul David Harris
3+
// Purpose: main wrapping functions to take burst data and submit to central H2MM algorithm
4+
// Date: 13 Feb 2021
5+
6+
#ifdef linux
7+
#include <unistd.h>
8+
#elif _WIN32
9+
#include <windows.h>
10+
#endif
11+
12+
#include <stdio.h>
13+
#include <stdlib.h>
14+
#include "C_H2MM.h"
15+
16+
#define TRUE 1
17+
#define FALSE 0
18+
19+
// data pre-processor, takes the raw photon times and turns them into deltas
20+
// allocating new memory for the deltas, and attaching the delta to the appropriate phstream
21+
pwrs* get_deltas(unsigned long num_burst, unsigned long *burst_sizes, unsigned long long **burst_times, unsigned long **burst_det, phstream *b)
22+
{
23+
size_t i, j;
24+
size_t max_delta = 1;
25+
size_t *deltas_temp;
26+
size_t *inds_temp;
27+
if ((burst_sizes == NULL) || (burst_times == NULL) || (burst_det == NULL) || (b == NULL))
28+
{
29+
printf("get_deltas(): One or more of the pointer arguments is NULL\n");
30+
return NULL;
31+
}
32+
pwrs *powers = (pwrs*) calloc(1,sizeof(pwrs));
33+
for ( i = 0; i < num_burst; i++)
34+
{
35+
deltas_temp = (size_t*) calloc(burst_sizes[i],sizeof(size_t));
36+
inds_temp = (size_t*) calloc(burst_sizes[i],sizeof(size_t));
37+
deltas_temp[0] = 0;
38+
inds_temp[0] = burst_det[i][0];
39+
for ( j = 1; j < burst_sizes[i]; j++)
40+
{
41+
if (burst_times[i][j] < burst_times[i][j-1])
42+
{
43+
printf("Photon %ld in burst %ld arrives out of order, please sanitize your data\n",j,i);
44+
free(powers);
45+
return NULL;
46+
}
47+
else if ( burst_times[i][j] == burst_times[i][j-1] ) deltas_temp[j] = 0;
48+
else
49+
{
50+
deltas_temp[j] = (size_t) (burst_times[i][j] - burst_times[i][j-1]) - 1;
51+
if ( deltas_temp[j] > max_delta) max_delta = deltas_temp[j];
52+
}
53+
inds_temp[j] = burst_det[i][j];
54+
}
55+
b[i].delta = deltas_temp;
56+
b[i].det = inds_temp;
57+
b[i].nphot = burst_sizes[i];
58+
//~ printf("burst_sizes[%d]: %d\n",i,burst_sizes[i]);
59+
}
60+
powers->max_pow = max_delta + 1;
61+
powers->pow_list = (size_t*) calloc(powers->max_pow,sizeof(size_t)); // allocate the memory for an unfilled powers list, index reduce will handle filling it in
62+
return powers;
63+
}
64+
65+
h2mm_mod* C_H2MM(unsigned long num_bursts, unsigned long *burst_sizes, unsigned long long **burst_times, unsigned long **burst_det, h2mm_mod *in_model, lm *limits)
66+
{
67+
size_t i, j;
68+
// alocate variables
69+
phstream *b = (phstream*) calloc(num_bursts,sizeof(phstream)); // remember to free all b[n]->delta to prevent memory leak
70+
// process burst arrays
71+
size_t num_burst = (size_t) num_bursts;
72+
//~ printf("Getting deltas\n");
73+
pwrs *powers = get_deltas(num_burst,burst_sizes,burst_times,burst_det,b); // note: allocates the powers->pow_list array, remember to free powers->pow_list before free powers or b, also, the stride lengths and td/tv/tq are not assigned (should be 0 because of calloc)
74+
//~ printf("Got powers\n");
75+
in_model->nphot = 0;
76+
for ( i = 0; i < num_bursts; i++) in_model->nphot += burst_sizes[i];
77+
if (powers == NULL)
78+
{
79+
printf("You have an out of order photon\n");
80+
return NULL;
81+
}
82+
for ( i = 0; i < num_bursts; i++)
83+
{
84+
for ( j = 0; j < b[i].nphot; j++)
85+
{
86+
if ( b[i].det[j] >= in_model->ndet)
87+
{
88+
printf("Your data has more photon streams than your h2mm model\n");
89+
return in_model;
90+
}
91+
}
92+
}
93+
powers->sk = in_model->nstate;
94+
powers->sj = powers->sk * in_model->nstate; // set strides, since these never change, we keep them the same
95+
powers->si = powers->sj * in_model->nstate;
96+
powers->sT = powers->si * in_model->nstate;
97+
powers->A = (double*) calloc(powers->sj * powers->max_pow,sizeof(double));
98+
powers->Rho = (double*) calloc(powers->sT * powers->max_pow,sizeof(double));
99+
// reduce indexes
100+
//~ index_reduce_end(num_burst, b, powers);
101+
// run main routine
102+
//~ printf("Entering main routine\n");
103+
h2mm_mod *out_model = compute_ess_dhmm(num_burst, b, powers, in_model, limits);
104+
// copy out to out_model
105+
//~ printf("\nPrior after copy is: \n");
106+
//~ for ( i = 0; i < out->nstate; i++) printf("%f ",out_model->prior[i]);
107+
//~ printf("\n");
108+
// free memory
109+
for ( i = 0; i < num_bursts; i++){
110+
free(b[i].delta);
111+
free(b[i].det);
112+
}
113+
free(b);
114+
free(powers->pow_list);
115+
free(powers->Rho);
116+
free(powers->A);
117+
free(powers);
118+
return out_model;
119+
}

C_H2MM.h

Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
// File: C_H2MM.h
2+
//
3+
// fwd_back_photonbyphoton
4+
#ifdef _WIN32
5+
#include <windows.h>
6+
#endif
7+
typedef struct
8+
{
9+
size_t nphot;
10+
size_t *delta;
11+
size_t *det;
12+
} phstream;
13+
14+
struct temp
15+
{
16+
long len_burst;
17+
unsigned long long *times;
18+
long *detectors;
19+
struct temp *next;
20+
};
21+
typedef struct temp temps;
22+
23+
typedef struct
24+
{
25+
size_t nstate;
26+
size_t ndet;
27+
size_t nphot;
28+
size_t niter;
29+
size_t conv;
30+
double *prior;
31+
double *trans;
32+
double *obs;
33+
double loglik;
34+
} h2mm_mod;
35+
36+
typedef struct
37+
{
38+
phstream *phot;
39+
size_t max_phot;
40+
size_t *cur_burst;
41+
size_t num_burst;
42+
size_t sk; // number of states, indexing chosen to match
43+
size_t sj; // square of the number of states
44+
size_t si; // cube of the number of states
45+
size_t sT; // fourth power of number of states
46+
double *Rho;
47+
double *A;
48+
h2mm_mod *current;
49+
h2mm_mod *new;
50+
#ifdef linux
51+
pthread_mutex_t *h2mm_lock;
52+
#endif
53+
} fback_vals;
54+
55+
// C_H2MM
56+
typedef struct
57+
{
58+
size_t max_iter;
59+
size_t num_cores;
60+
double max_time;
61+
double min_conv;
62+
} lm;
63+
64+
65+
// rho_calc
66+
typedef struct // pwrs is a structure that contains pointers to the A (transmat) and Rho arrays, plus information on dimensions and which values are to be calculated
67+
{
68+
size_t max_pow;
69+
size_t sT;
70+
size_t si;
71+
size_t sj; // note that this is also the stride for the delta t in the A array
72+
size_t sk; // note that this is also the number of states
73+
size_t tv;
74+
size_t tq;
75+
size_t td;
76+
size_t *pow_list;
77+
double *A;
78+
double *Rho;
79+
} pwrs;
80+
81+
// viterbi
82+
typedef struct
83+
{
84+
size_t nphot;
85+
size_t nstate;
86+
double loglik;
87+
size_t *path;
88+
double *scale;
89+
} ph_path;
90+
91+
92+
typedef struct
93+
{
94+
size_t si;
95+
size_t sT;
96+
double *A;
97+
phstream *phot;
98+
ph_path *path;
99+
h2mm_mod *model;
100+
} vit_vals;
101+
102+
103+
// C_H2MM
104+
105+
pwrs* get_deltas(unsigned long num_burst, unsigned long *burst_sizes, unsigned long long **burst_times, unsigned long **burst_det, phstream *b);
106+
107+
h2mm_mod* C_H2MM(unsigned long num_bursts, unsigned long *burst_sizes, unsigned long long **burst_times, unsigned long **burst_det, h2mm_mod *in_model, lm *limits);
108+
109+
// fwd_back_photonbyphoton
110+
#ifdef linux
111+
void* fwd_back_PhotonByPhoton(void* burst);
112+
#elif _WIN32
113+
DWORD WINAPI fwd_back_PhotonByPhoton(void* burst);
114+
#endif
115+
116+
void h2mm_normalize(h2mm_mod *model_params);
117+
118+
h2mm_mod* compute_ess_dhmm(size_t num_bursts, phstream *b, pwrs *powers, h2mm_mod *in, lm *limits);
119+
120+
// rho_calc
121+
122+
void* rhoulate(void *vals);
123+
124+
void* rho_all(size_t nstate, double* transmat, pwrs *powers);
125+
126+
// viterbi
127+
#ifdef linux
128+
void* viterbi_burst(void* in_vals);
129+
#elif _WIN32
130+
DWORD WINAPI viterbi_burst(void* in_vals);
131+
#endif
132+
int viterbi(unsigned long num_bursts, unsigned long *burst_sizes, unsigned long long **burst_times, unsigned long **burst_det, h2mm_mod *model, ph_path *path_array);
133+
134+
// C_H2MM_interface
135+
136+
temps* burst_read(char *fname, size_t *n);
137+
138+
h2mm_mod* h2mm_read(char *fname);

C_H2MM_interface.c

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
// File: C_H2MM_interface.c
2+
// Author: Paul David Harris
3+
// Purpose: Wrapper function for commandline interface with C_H2MM
4+
// Date: 03 Apr 2021
5+
6+
#ifdef _WIN32
7+
#include <windows.h>
8+
#endif
9+
10+
#include <stdio.h>
11+
#include <stdlib.h>
12+
#include <math.h>
13+
#include "C_H2MM.h"
14+
15+
int main(int argc, char **argv)
16+
{
17+
unsigned long long **times;
18+
unsigned long **detectors;
19+
long *len_bursts;
20+
size_t i, j;
21+
size_t num_burst = 0;
22+
char *eptr;
23+
temps *head;
24+
//temps *next; // unreferenced??
25+
temps *tmp;
26+
phstream *b;
27+
h2mm_mod *in_model;
28+
lm *limits = (lm*) calloc(1,sizeof(lm));
29+
limits->max_iter = 3600;
30+
limits->max_time = INFINITY;
31+
limits->min_conv = 1e-14;
32+
limits->num_cores = 4;
33+
int n = 0;
34+
if (argc > 2)
35+
{
36+
//~ printf("Read bursts\n");
37+
head = burst_read(argv[1],&num_burst);
38+
//~ printf("Read model\n");
39+
in_model = h2mm_read(argv[2]);
40+
if (argc > 3) limits->num_cores = (size_t) strtol(argv[3],&eptr,10);
41+
if (argc > 4) limits->max_iter = (size_t) strtol(argv[4],&eptr,10);
42+
if (argc > 5) limits->max_time = strtod(argv[4],&eptr);
43+
if (argc > 6) limits->min_conv = strtod(argv[5],&eptr);
44+
}
45+
else
46+
{
47+
fprintf(stderr,"Too few arguments");
48+
exit(EXIT_FAILURE);
49+
}
50+
// recast linked list of burst_read into
51+
// first step is to allocate the necessary arrays of pointers and lengths
52+
times = (unsigned long long**)calloc(num_burst, sizeof(unsigned long long*));
53+
detectors = (unsigned long**) calloc(num_burst, sizeof(unsigned long long*));
54+
len_bursts = (long*) calloc(num_burst, sizeof(long));
55+
// now follow the linked list, and put the pointers and lengths in the arrays
56+
for( i = 0; i < num_burst; i++)
57+
{
58+
len_bursts[i] = head->len_burst;
59+
times[i] = head->times;
60+
detectors[i] = head->detectors;
61+
tmp = head;
62+
head = head->next;
63+
free(tmp); // don't keep the linked list structure around
64+
//~ printf("Freed burst %d\n",i);
65+
}
66+
//~ printf("There are %d bursts\n",num_burst);
67+
b = (phstream*) calloc(num_burst,sizeof(phstream));
68+
printf("main(): num_burst: %d\n", (int)num_burst);
69+
printf("main(): in_model->ndet: %d\n", (int)in_model->ndet);
70+
printf("Entering main algorithm\n");
71+
h2mm_mod *out_model = C_H2MM(num_burst,len_bursts,times,detectors,in_model,limits);
72+
if (out_model == NULL) printf("You have an out of order photon\n");
73+
else if (out_model == in_model) printf("You have too many detectors in your data than allowed in your model\n");
74+
else
75+
{
76+
if (out_model->conv == 1)
77+
printf("Model converged after %ld iterations\n",out_model->niter);
78+
else if (out_model->conv ==2)
79+
printf("Maxiumum iterations reached\n");
80+
else if (out_model->conv == 3)
81+
printf("Maximum time reached\n");
82+
else
83+
printf("NAN error, returning last successful model\n");
84+
printf("The final model is:\n");
85+
printf("Prior:\n");
86+
for ( i = 0; i < out_model->nstate; i++) printf("%f ",out_model->prior[i]);
87+
printf("\nTrans:\n");
88+
for ( i = 0; i < out_model->nstate; i++)
89+
{
90+
for ( j = 0; j < out_model->nstate; j++) printf("%e ",out_model->trans[out_model->nstate * i + j]);
91+
printf("\n");
92+
}
93+
printf("Obs\n");
94+
for ( i = 0; i < out_model->ndet; i++)
95+
{
96+
for ( j = 0; j < out_model->nstate; j++) printf("%f ",out_model->obs[out_model->nstate * i + j]);
97+
printf("\n");
98+
}
99+
}
100+
}

0 commit comments

Comments
 (0)