static inline void K_lm_calc(ok_kernel* k, double* f, const int ndata, const double** compiled, ok_lm_params* params) { k->flags |= NEEDS_SETUP; K_calculate(k); for (int i = 0; i < k->ndata; i++) { const double* comprow = compiled[i]; int set = (int) comprow[T_SET]; double n = K_getPar(k, set + DATA_SETS_SIZE); double diff = (comprow[T_PRED] - comprow[T_SVAL]); double s = comprow[T_ERR]; if (((int) comprow[T_FLAG]) == T_RV && n > 1e-12) f[i] = diff / sqrt(s*s + n*n); else f[i] = diff / s; } if (k->chi2 < params->min_chi) { params->min_chi = k->chi2; for (int i = 0; i < params->npars; i++) params->best[i] = *(params->pars[i]); } }
double K_crossval_l1o(ok_kernel* k, int minalgo, int maxiter, double params[]) { int nd = K_getNdata(k); int np = omp_get_max_threads(); ok_kernel* ks[np]; double lh[np]; ok_progress prog = k->progress; for (int p = 0; p < np; p++) { ks[p] = K_clone(k); ks[p]->progress = NULL; lh[p] = 0.; } bool invalid = false; #pragma omp parallel for for (int i = 0; i < nd; i++) { if (invalid) continue; int p = omp_get_thread_num(); gsl_matrix_memcpy(ks[p]->system->elements, k->system->elements); gsl_vector_memcpy(ks[p]->params, k->params); K_calculate(ks[p]); double err = ks[p]->compiled[i][T_ERR]; int set = (int) (ks[p]->compiled[i][T_SET]); double n = K_getPar(ks[p], set + DATA_SETS_SIZE); ks[p]->compiled[i][T_ERR] = 100000.; K_minimize(ks[p], minalgo, maxiter, params); double s = sqrt(err*err + n*n); double diff = fabs(ks[p]->compiled[i][T_SVAL] - ks[p]->compiled[i][T_PRED]); lh[p] += log10(diff/s); ks[p]->compiled[i][T_ERR] = err; if (prog != NULL && omp_get_thread_num() == 0) { int ret = prog(i * np, nd, ks[p], "K_crossVal_l1o"); if (ret == PROGRESS_STOP) { invalid = true; } } } double lh2 = 0; for (int p = 0; p < np; p++) { lh2 += lh[p]; K_free(ks[p]); } if (invalid) return -1; return fabs(lh2); }
double K_getPhasedDataForPlanet(ok_kernel* k, int planet, int row, int column) { static gsl_matrix* phased_data = NULL; if (planet >= 1) { if (phased_data != NULL) { gsl_matrix_free(phased_data); phased_data = NULL; } double chi2 = k->chi2; double rms = k->rms; double jitter = k->jitter; double chi2_rvs = k->chi2_rvs; planet = MIN(planet, K_getNplanets(k)); double mass = K_getElement(k, planet, MASS); double period = K_getElement(k, planet, PER); K_setElement(k, planet, MASS, 0); K_calculate(k); phased_data = K_getCompiledDataMatrix(k); double mint = MGET(phased_data, 0, T_TIME); for (int i = 0; i < MROWS(phased_data); i++) { double t = fmod((MGET(phased_data, i, T_TIME) - mint), period); double v = MGET(phased_data, i, T_SVAL) - MGET(phased_data, i, T_PRED); MSET(phased_data, i, T_TIME, t); MSET(phased_data, i, T_VAL, v); } ok_sort_matrix(phased_data, T_TIME); K_setElement(k, planet, MASS, mass); K_calculate(k); k->chi2 = chi2; k->rms = rms; k->jitter = jitter; k->chi2_rvs = chi2_rvs; return 1; } else { return MGET(phased_data, row, column); } }
double _kminimize(ok_kernel* k, int algo) { K_calculate(k); double chi2 = K_getChi2_nr(k); while (true) { K_minimize(k, algo, 10000, NULL); if (K_getChi2_nr(k) - chi2 < -0.01) chi2 = K_getChi2_nr(k); else break; } return K_getChi2_nr(k); }
gsl_matrix* ok_periodogram_full(ok_kernel* k, int type, int algo, bool circular, unsigned int sample, const unsigned int samples, const double Pmin, const double Pmax) { k = K_clone(k); K_calculate(k); // Input data for LS periodogram gsl_matrix* data = ok_buf_to_matrix(K_compileData(k), K_getNdata(k), DATA_SIZE); if (type == PS_TYPE_RESIDUALS) { // If residuals periodogram, subtract signal from data for (int i = 0; i < data->size1; i++) MSET(data, i, T_SVAL, MGET(data, i, T_SVAL) - MGET(data, i, T_PRED)); } else if (type == PS_TYPE_DATA) { // If full periodogram, then start with no planets K_removePlanet(k, -1); } // Calculate LS periodogram gsl_matrix* ret = ok_periodogram_ls(data, samples, Pmin, Pmax, 0, T_TIME, T_SVAL, T_ERR, NULL); int np = K_getNplanets(k) + 1; // Number of minimizable offsets int no = 0; for (int i = 0; i < DATA_SETS_SIZE; i++) if (VIGET(k->parFlags, i) & MINIMIZE) { no++; } // Calculate baseline chi^2 (Chi^2_H) double Chi2_H = _kminimize(k, algo); // Normalizing factor for power double nd = 0.5 * (K_getNdata(k) - no); #pragma omp parallel for for (int r = 0; r < samples; r++) { double P = MGET(ret, r, PS_TIME); double K = sqrt(MGET(ret, r, PS_Z)); ok_kernel* k2 = K_clone(k); K_calculate(k2); double args[] = {PER, P, DONE}; K_addPlanet(k2, args); K_setElement(k2, np, SEMIAMP, K); K_setElementFlag(k2, np, PER, ACTIVE); if (circular) { K_setElementFlag(k2, np, ECC, ACTIVE); K_setElementFlag(k2, np, LOP, ACTIVE); } double Chi2_K = _kminimize(k2, algo); double z = nd * (Chi2_H - Chi2_K) / Chi2_H; MSET(ret, r, PS_Z, z); fflush(stdout); } return ret; }
int K_minimize_lm(ok_kernel* k, int maxiter, double params[]) { double min_chi_par = 1e-4; K_calculate(k); double prev_chi2 = k->chi2; bool high_df = false; int max_iter_at_scale = 200; double initial_st = 1.; int max_kt = 1; for (int i = 0; i < k->ndata; i++) if (k->compiled[i][T_FLAG] == T_TIMING) { high_df = true; max_kt = 2; max_iter_at_scale = 500; break; } if (params != NULL) { int i = 0; while (true) { if (params[i] == DONE) break; if (params[i] == OPT_LM_MINCHI_PAR) min_chi_par = params[i+1]; else if (params[i] == OPT_LM_HIGH_DF) high_df = !((int) params[i+1] == 0); else if (params[i] == OPT_LM_MAX_ITER_AT_SCALE) max_iter_at_scale = (int) params[i+1]; else if (params[i] == OPT_LM_INITIAL_SCALE) initial_st = params[i+1]; i+=2; } } unsigned int npars = 0; // Count all the parameters to minimize on for (int i = 1; i < k->system->nplanets + 1; i++) for (int j = 0; j < ELEMENTS_SIZE; j++) npars += (MIGET(k->plFlags, i, j) & MINIMIZE ? 1 : 0); for (int i = 0; i < k->parFlags->size; i++) npars += (VIGET(k->parFlags, i) & MINIMIZE ? 1 : 0); if (npars == 0) return 0; // Create a pointer table (flat array -> matrices) double** pars = (double**) malloc(sizeof(double*) * npars); double prevpars[npars]; double* steps = (double*) malloc(npars * sizeof(double)); double* stepscale = (double*) malloc(npars * sizeof(double)); int* parstype = (int*) malloc(npars * sizeof(int)); gsl_vector* x = gsl_vector_alloc(npars); int idx = 0; for (int i = 1; i < k->system->nplanets + 1; i++) for (int j = 0; j < ELEMENTS_SIZE; j++) if (MIGET(k->plFlags, i, j) & MINIMIZE) { pars[idx] = gsl_matrix_ptr(k->system->elements, i, j); x->data[idx] = MGET(k->system->elements, i, j); prevpars[idx] = x->data[idx]; steps[idx] = stepscale[idx] = MGET(k->plSteps, i, j); parstype[idx] = j; if (steps[idx] < 1e-10) { printf("Warning: step for element %d of planet %d is <= 0\n", j, i); } idx++; } for (int i = 0; i < k->parFlags->size; i++) if (VIGET(k->parFlags, i) & MINIMIZE) { pars[idx] = gsl_vector_ptr(k->params, i); x->data[idx] = VGET(k->params, i); prevpars[idx] = x->data[idx]; steps[idx] = stepscale[idx] = VGET(k->parSteps, i); parstype[idx] = PARTYPE_PAR; if (steps[idx] < 1e-10) printf("Warning: step for parameter %d is <= 0\n", i); idx++; } gsl_multifit_fdfsolver * s = gsl_multifit_fdfsolver_alloc (gsl_multifit_fdfsolver_lmsder, k->ndata, npars); ok_lm_params sp; sp.k = k; sp.pars = pars; sp.best = (double*) malloc(sizeof(double) * npars); sp.stepscale = stepscale; sp.compiled = k->compiled; sp.f0 = (double*) malloc(sizeof(double)*k->ndata); sp.f1 = (double*) malloc(sizeof(double)*k->ndata); sp.f2 = (double*) malloc(sizeof(double)*k->ndata); sp.f3 = (double*) malloc(sizeof(double)*k->ndata); sp.parstype = parstype; sp.ndata = k->ndata; sp.iterations = 0; sp.maxiterations = maxiter; sp.npars = npars; sp.every = (k->intMethod == KEPLER ? 10 : 1); sp.status = PROGRESS_CONTINUE; sp.high_df = high_df; sp.min_chi = k->chi2; sp.st = initial_st; for (int i = 0; i < npars; i++) sp.best[i] = *(pars[i]); gsl_multifit_function_fdf fdf; fdf.f = &K_lm_f; fdf.df = &K_lm_jac; fdf.fdf = &K_lm_fdf; fdf.n = k->ndata; fdf.p = npars; fdf.params = &sp; gsl_multifit_fdfsolver_set (s, &fdf, x); bool improved = true; int status = 0; int kt = 0; int tot_iter = 0; int iter_at_scale = 0; bool last_ditch = false; while (improved || last_ditch) { k->flags |= NEEDS_SETUP; iter_at_scale = 0; while (true) { double chi2 = sp.min_chi; int status = gsl_multifit_fdfsolver_iterate (s); iter_at_scale++; tot_iter++; if (chi2 - sp.min_chi > min_chi_par) iter_at_scale = 0; if (status || iter_at_scale > max_iter_at_scale) { break; } } gsl_multifit_fdfsolver_set (s, &fdf, x); for (int i = 0; i < npars; i++) { *(pars[i]) = sp.best[i]; x->data[i] = sp.best[i]; } k->flags |= NEEDS_SETUP; K_calculate(k); if (fabs(prev_chi2 - sp.min_chi)/fabs(sp.min_chi) > 1e-2 && iter_at_scale > 1) { kt = 0; last_ditch = false; } else { sp.st *= 0.1; } improved = (kt < max_kt || fabs(sp.min_chi - prev_chi2)/fabs(sp.min_chi) > 1e-2); if (last_ditch) break; if (! improved && kt <= 3) { last_ditch = true; sp.st *= 0.1; } kt++; //printf("-> %d %d %d %e %e, last_ditch=%d\n", iter_at_scale, kt, improved, sp.st, sp.min_chi, last_ditch); prev_chi2 = k->chi2; for (int idx = 0; idx < npars; idx++) stepscale[idx] = steps[idx] * sp.st; if (sp.iterations > maxiter || sp.st < 1e-12) break; } for (int i = 0; i < npars; i++) { *(pars[i]) = sp.best[i]; x->data[i] = sp.best[i]; } k->flags |= NEEDS_SETUP; K_calculate(k); free(sp.stepscale); free(sp.f0); free(sp.f1); free(sp.f2); free(sp.f3); free(sp.pars); free(sp.parstype); free(sp.best); if (sp.status == PROGRESS_STOP) return PROGRESS_STOP; else return status; }