(file) Return to usflux.c CVS log (file) (dir) Up to [Development] / JSOC / proj / mag / polarfield / apps

File: [Development] / JSOC / proj / mag / polarfield / apps / usflux.c (download)
Revision: 1.1, Wed Mar 29 23:06:36 2017 UTC (6 years, 2 months ago) by xudong
Branch: MAIN
CVS Tags: Ver_LATEST, Ver_9-5, Ver_9-41, Ver_9-4, Ver_9-3, Ver_9-2, Ver_9-1, HEAD
added usflux for computing unsigned flux

/*
 * Module name:		usflux.c
 *
 * Description:
 *  Taking ab HMI magnetogram and compute unsigned flux
 *
 * Written by:		Xudong Sun (xudongs@stanford.edu)
 *
 * Version:
 *  v1.0		Apr 19 2016
 *
 * Issues:
 *  v1.0    No error checking as of now
 *
 *
 * Example:
 *  usflux "in=hmi.M_720s[2011.11.01]"
 *
 */

#include <jsoc_main.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "cartography.c"

/* ############# Macros ############# */

#ifndef MIN
#define MIN(a,b) (((a)<(b)) ? (a) : (b))
#endif
#ifndef MAX
#define MAX(a,b) (((a)>(b)) ? (a) : (b))
#endif

#define SHOW(msg) {printf("%s", msg); fflush(stdout);}
#define DIE(msg) {fflush(stdout); fprintf(stderr,"%s (status=%d)\n", msg, status); return(status);}

#define FREE_ARR(arr) {if (arr) {free(arr);}}
#define DRMS_FREE_ARR(arr) {if (arr) {drms_free_array(arr);}}

#define EPSL (1.0E-5)
#define RAD2DEG       (180. / M_PI)
#define RAD2ARCSEC      (648000. / M_PI)

// apodize radius
#define APOD    (0.990)
#define BRTHRESH    (0.0)
#define BLTHRESH    (0.0)

/* ############# Structures ############# */

struct ephemeris {
    double rsun_obs;    // solar disk, in arcsec
    double asd;         // solar disk, in radian
    double xc, yc;      // disk center in pixel, lower-left (0,0)
    double cdelt;       // plate scale, in arcsec, assuming x & y same
    double p0, b0;      // p angle, b angle, in radian
    double rsun;        // in pixel
    double da;          // pixel area, in 1.e16 cm2 (1 Mm2)
};

/* ############# Pre-emb ############# */

/* Timing by T. P. Larson */

double getwalltime(void)
{
    struct timeval tv;
    gettimeofday(&tv, NULL);
    return tv.tv_sec * 1000.0 + tv.tv_usec/1000.0;
}

double getcputime(double *utime, double *stime)
{
    struct rusage ru;
    getrusage(RUSAGE_SELF, &ru);
    *utime = ru.ru_utime.tv_sec * 1000.0 + ru.ru_utime.tv_usec/1000.0;
    *stime = ru.ru_stime.tv_sec * 1000.0 + ru.ru_stime.tv_usec/1000.0;
    return *utime + *stime;
}


// Get ephemeris
int get_ephemeris(DRMS_Record_t *inRec, struct ephemeris *ephem);

// Get lon/lat for each pixel
void get_lonlat(struct ephemeris *ephem, int *dims, double *lon, double *lat, double *wght);

// Convert LOS field to radial
void los2radial(struct ephemeris *ephem, int *dims, double *bl, double *br, double *wght);

// Compute flux
void compute_flux(int *dims, double *br, double *bl, double *wght,
                  double *ntflux_bl, double *ntflux_br, double *usflux_bl, double *usflux_br,
                  double *w_bl, double *w_br, double *r_bl, double *r_br);



/* ################################################# */
/* ################## Main Module ################## */
/* ################################################# */

char *module_name = "usflux";

ModuleArgs_t module_args[] =
{
    {ARG_STRING, "in", "", "Input query"},
    {ARG_STRING, "out", "hmi_test.usflux_720s", "Output query"},
    {ARG_END}
};

int DoIt(void)
{
    
    int status = DRMS_SUCCESS;
    
    // Time measuring
    
    double wt0, wt1, wt;
    double ut0, ut1, ut;
    double st0, st1, st;
    double ct0, ct1, ct;
    wt0 = getwalltime();
    ct0 = getcputime(&ut0, &st0);

    /* ============== */
    /* Get parameters */
    /* ============== */
    
    char *inQuery = (char *)params_get_str(&cmdparams, "in");
    char *outQuery = (char *)params_get_str(&cmdparams, "out");
    
    /* ============= */
    /* Input records */
    /* ============= */
    
    DRMS_RecordSet_t *inRS = NULL;
    inRS = drms_open_records(drms_env, inQuery, &status);
    if (status || inRS->n == 0) DIE("Input records error.");
    
    int nrecs = inRS->n;
    
    /* ============== */
    /* Output records */
    /* ============== */
    
    DRMS_RecordSet_t *outRS = drms_create_records(drms_env, nrecs, outQuery, DRMS_PERMANENT, &status);
    if (status) DIE("Output records not created.");
    
    /* ============ */
    /* Loop records */
    /* ============ */

    printf("Start, %d records in total\n", nrecs);
    
    for (int irec = 0; irec < nrecs; irec++) {
        
        // Time measure
        
        wt1 = getwalltime();
        ct1 = getcputime(&ut, &st);
        
        // Input ecord
        
        DRMS_Record_t *inRec = inRS->records[irec];
        TIME t_rec = drms_getkey_time(inRec, "T_REC", &status);
        
        char t_rec_str[100];
        sprint_time(t_rec_str, t_rec, "TAI", 0);
        printf("==============\nRecord #%d, [%s]\n", irec, t_rec_str);
        
        struct ephemeris ephem;
        status = get_ephemeris(inRec, &ephem);
        if (status) {
            SHOW("Input record ephemeris error, record skipped.\n");
        }
        
        DRMS_Segment_t *inSeg = drms_segment_lookupnum(inRec, 0);
        DRMS_Array_t *inArray = NULL;
        inArray = drms_segment_read(inSeg, DRMS_TYPE_DOUBLE, &status);
        if (status) {
            SHOW("Input array read error, record skipped.\n");
            if (inArray) drms_free_array(inArray);
            continue;
        }
        
        int nx = inArray->axis[0], ny = inArray->axis[1];       // size
        int nxny = nx * ny;
        int dims[2] = {nx, ny};
        
        // Lon, Lat
        
        SHOW("Get lon/lat...\n");
        
        double *lon = NULL, *lat = NULL, *wght = NULL;
        lon = (double *) (calloc(sizeof(double), nxny));
        lat = (double *) (calloc(sizeof(double), nxny));
        wght = (double *) (calloc(sizeof(double), nxny));
        
        get_lonlat(&ephem, dims, lon, lat, wght);
        
        // LOS to Radial
        
        double *bl = NULL, *br = NULL;
        bl = (double *) (inArray->data);
        br = (double *) (calloc(sizeof(double), nxny));
        
        SHOW("Convert bl to br...\n");
        los2radial(&ephem, dims, bl, br, wght);
        
        // Compute flux
        
        SHOW("Compute usflux...\n");
        
        // LOS flux and radial (read) flux, for net and unsigned, not scaled by area
        double ntflux_bl = 0, ntflux_br = 0, usflux_bl = 0, usflux_br = 0;
        // sum of pixel, pixel area, percentage above threshold
        double w_bl = 0, w_br = 0, r_bl = 0, r_br = 0;
        
        compute_flux(dims, br, bl, wght,
                     &ntflux_bl, &ntflux_br, &usflux_bl, &usflux_br,
                     &w_bl, &w_br, &r_bl, &r_br);
        
        // Clean up #1
        
        drms_free_array(inArray);       // bl
        FREE_ARR(br); FREE_ARR(wght); FREE_ARR(lon); FREE_ARR(lat);
        
        // Output record
        
        SHOW("Output...\n");
        printf("mean bl: %.4f G\n", ntflux_bl / w_bl);
        
        DRMS_Record_t *outRec = outRS->records[irec];
        
        drms_copykey(outRec, inRec, "T_REC");
        
        char timebuf[1024];
        double UNIX_epoch = -220924792.0;	/* 1970.01.01_00:00:00_UTC */
        sprint_time(timebuf, (double)time(NULL) + UNIX_epoch, "ISO", 0);
        drms_setkey_string(outRec, "DATE", timebuf);
        
        double k = ephem.da * 1.e-4;            // 1d20 cm^2
        drms_setkey_double(outRec, "NTFLUX_BL", ntflux_bl * k);
        drms_setkey_double(outRec, "NTFLUX_BR", ntflux_br * k);
        drms_setkey_double(outRec, "USFLUX_BL", usflux_bl * k);
        drms_setkey_double(outRec, "USFLUX_BR", usflux_br * k);

        drms_setkey_double(outRec, "BRTHRESH", BRTHRESH);
        drms_setkey_double(outRec, "BLTHRESH", BRTHRESH);
        drms_setkey_double(outRec, "W_BL", w_bl);
        drms_setkey_double(outRec, "W_BR", w_br);
        drms_setkey_double(outRec, "R_BL", r_bl);
        drms_setkey_double(outRec, "R_BR", r_br);
        drms_setkey_double(outRec, "DA", ephem.da);
        drms_setkey_double(outRec, "APOD", APOD);
        
        drms_copykey(outRec, inRec, "QUALITY");
        drms_copykey(outRec, inRec, "CRLT_OBS");
        drms_copykey(outRec, inRec, "CRLN_OBS");
        drms_copykey(outRec, inRec, "CAR_ROT");
        drms_copykey(outRec, inRec, "OBS_VR");
        
        // Time measure
        
        wt = getwalltime();
        ct = getcputime(&ut, &st);
        printf("Record %d of %d done, %.2f ms wall time, %.2f ms cpu time\n",
               irec + 1, nrecs, wt - wt1, ct - ct1);
        
    }   // irec
    
    /* ============= */
    
    drms_close_records(inRS, DRMS_FREE_RECORD);
    drms_close_records(outRS, DRMS_INSERT_RECORD);
    
    wt = getwalltime();
    ct = getcputime(&ut, &st);
    printf("==============\nTotal time spent: %.2f ms wall time, %.2f ms cpu time\n",
           wt - wt0, ct - ct0);
    
    return DRMS_SUCCESS;
    
}   // DoIt

/* ############# Helper functions ############# */

// Get ephemeris

int get_ephemeris(DRMS_Record_t *inRec, struct ephemeris *ephem)
{
    
    int status = 0;
    
    ephem->rsun_obs = drms_getkey_double(inRec, "RSUN_OBS", &status);   // in arcsec
    if (status) return status;
    ephem->asd = ephem->rsun_obs / RAD2ARCSEC;      // in rad
    
    ephem->xc = drms_getkey_double(inRec, "CRPIX1", &status) - 1.;      // start from (0,0)
    if (status) return status;
    ephem->yc = drms_getkey_double(inRec, "CRPIX2", &status) - 1.;
    if (status) return status;
    
    double cdelt1 = drms_getkey_double(inRec, "CDELT1", &status);
    if (status) return status;
    double cdelt2 = drms_getkey_double(inRec, "CDELT2", &status);
    if (status) return status;
    if (fabs(cdelt1 - cdelt2) > EPSL) return 1;
    ephem->cdelt = cdelt1;
    
    ephem->rsun = ephem->rsun_obs / ephem->cdelt;     // in pixel
    
    ephem->p0 = drms_getkey_double(inRec, "CROTA2", &status) / RAD2DEG * (-1.);
    if (status) return status;
    
    ephem->b0 = drms_getkey_double(inRec, "CRLT_OBS", &status) / RAD2DEG;
    if (status) return status;
    
    double dsun_obs = drms_getkey_double(inRec, "DSUN_OBS", &status) / 1.e6;   // in Mm, or 1.e8 cm
    double dx = cdelt1 * ((dsun_obs - 696.) / RAD2ARCSEC);       // pixel size in Mm, or 1.e8 cm
    ephem->da = dx * dx;        // in 1.e16 cm^2
    
    return 0;
    
}

// Get lon/lat for each pixel

void get_lonlat(struct ephemeris *ephem, int *dims, double *lon, double *lat, double *wght)
{
    
    int ncol = dims[0], nrow = dims[1];
    int idx;
    int status = 0;
    
    double x, y, r;        // dist to center, in solar radius
    double rho, sinlat, coslat, sig, mu, chi;
    double lat0, lon0;
    
    for (int row = 0; row < nrow; row++) {
        y = (row - ephem->yc) / ephem->rsun;
        for (int col = 0; col < ncol; col++) {
            x = (col - ephem->xc) / ephem->rsun;
            r = hypot(x, y);
            idx = row * ncol + col;
            if (r <= APOD) {
                status = img2sphere(x, y, ephem->asd, ephem->b0, 0.0, ephem->p0,
                                    &rho, &lat0, &lon0, &sinlat, &coslat, &sig, &mu, &chi);
                if (status) {
                    lon[idx] = lat[idx] =  wght[idx] = DRMS_MISSING_DOUBLE;
                } else {
                    lon[idx] = ((lon0 > M_PI) ? (lon0 - M_PI * 2) : lon0) * RAD2DEG;
                    lat[idx] = lat0 * RAD2DEG;
                    wght[idx] = 1.0 / mu;       // changed to mu from cos(rho) on Apr 16
                }
            } else {
                lon[idx] = lat[idx] = wght[idx] = DRMS_MISSING_DOUBLE;
            }
        }
    }
    
}

// Convert LOS field to radial

void los2radial(struct ephemeris *ephem, int *dims, double *bl, double *br, double *wght)
{
    
    int nxny = dims[0] * dims[1];
    int idx;
    
    double x, y, r;        // dist to center, in solar radius
    double crho;
    
    for (int idx = 0; idx < nxny; idx++) {
        if (isnan(wght[idx])) {
            br[idx] = bl[idx] = DRMS_MISSING_DOUBLE;
        } else {
            br[idx] = bl[idx] * wght[idx];      // wght = 1/mu
        }
    }
}

// Compute flux

void compute_flux(int *dims, double *br, double *bl, double *wght,
                  double *ntflux_bl, double *ntflux_br, double *usflux_bl, double *usflux_br,
                  double *w_bl, double *w_br, double *r_bl, double *r_br)
{
    int nx = dims[0], ny = dims[1];
    int nxny = nx * ny;
    
    // Int Loop
    for (int idx = 0; idx < nxny; idx++) {
        if (isnan(wght[idx])) continue;
        (*w_bl) += 1;
        (*w_br) += wght[idx];
        // compute
        if (fabs(bl[idx]) >= BLTHRESH) {
            (*ntflux_bl) += (bl[idx]);
            (*usflux_bl) += fabs(bl[idx]);
            (*r_bl) += 1;
        }
        if (fabs(br[idx]) >= BRTHRESH) {
            (*ntflux_br) += (br[idx] * wght[idx]);
            (*usflux_br) += fabs(br[idx] * wght[idx]);
            (*r_br) += wght[idx];
        }
    }
    
    (*r_bl) /= (*w_bl);
    (*r_br) /= (*w_br);
    
}


Karen Tian
Powered by
ViewCVS 0.9.4