![]() ![]() |
![]() |
File: [Development] / JSOC / proj / mag / polarfield / apps / meanpf.c
(download)
Revision: 1.1, Fri Aug 28 20:02:30 2015 UTC (7 years, 9 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, Ver_9-0, Ver_8-12, Ver_8-11, Ver_8-10, HEAD new add cp_polarfield: copy content from su_xudong.polmf_f to hmi.meanpf_720s meanpf: populate hmi.meanpf_720s |
/* * Module name: meanpf.c * * Description: * Taking ab HMI magnetogram and compute mean field * in various lat/lon windows, adapted from polmf.c * The original, double 180x4 segment is splitted into * four 180-element, Rice compressed segments * * Written by: Xudong Sun (xudongs@stanford.edu) * * Version: * v1.0 Aug 27 2015 * * Issues: * v1.0 No error checking as of now * * * Example: * meanpf "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.995) // Br threshold for FWTLAT #define BRTHRESH (120.) // Test //#define TESTOUT 1 /* ############# 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) }; struct fwt { double fluxn[2]; // flux below 40 lat for north [pos,neg], in 1e20 Mx double fluxs[2]; // flux below 40 lat for south [pos,neg], in 1e20 Mx double latn[2]; // flux weighted centroid for north double lats[2]; // flux weighted centroid for south }; /* ############# 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 mean values in certain bins void compute_mf(int *dims, double *br, double *bl, double *lon, double *lat, double *wght, int *outDims, double *mf); // Compute flux weighted lat void compute_fwtlat(int *dims, double *br, double *lon, double *lat, double *wght, struct fwt *fwtlat); // Set polar field keywords void set_mf_keys(DRMS_Record_t *outRec, int *outDims, double *mf, struct fwt *fwtlat); /* ################################################# */ /* ################## Main Module ################## */ /* ################################################# */ char *module_name = "meanpf"; ModuleArgs_t module_args[] = { {ARG_STRING, "in", "", "Input query"}, {ARG_STRING, "out", "hmi.meanpf_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 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); // Timing wt1 = getwalltime(); ct1 = getcputime(&ut1, &st1); // 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 MF SHOW("Compute mf...\n"); int nlat = 180; int outDims_mf[2] = {nlat,4}; double *mf = (double *) (calloc(sizeof(double), outDims_mf[0]*outDims_mf[1])); /* double *mf_br = mf; double *mf_bl = mf + row_offset; double *w = mf + row_offset * 2; double *num = mf + row_offset * 3; */ compute_mf(dims, br, bl, lon, lat, wght, outDims_mf, mf); // Compute flux weighted centroid struct fwt fwtlat; compute_fwtlat(dims, br, lon, lat, wght, &fwtlat); fwtlat.fluxn[0] *= ephem.da; // 1e20 Mx fwtlat.fluxn[1] *= ephem.da; fwtlat.fluxs[0] *= ephem.da; fwtlat.fluxs[1] *= ephem.da; // Split into four 180-element arrays double *mf_br = (double *) (malloc(nlat * sizeof(double))); double *mf_bl = (double *) (malloc(nlat * sizeof(double))); double *w = (double *) (malloc(nlat * sizeof(double))); double *num = (double *) (malloc(nlat * sizeof(double))); for (int i = 0; i < nlat; i++) { mf_br[i] = mf[i]; mf_bl[i] = mf[nlat + i]; w[i] = mf[nlat * 2 + i]; num[i] = mf[nlat * 3 + i]; } // 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"); int outDims[1] = {nlat}; DRMS_Record_t *outRec = outRS->records[irec]; DRMS_Segment_t *outSeg_br = drms_segment_lookup(outRec, "mf_br"); DRMS_Array_t *outArray_br = drms_array_create(DRMS_TYPE_DOUBLE, 1, outDims, mf_br, &status); status = drms_segment_write(outSeg_br, outArray_br, 0); DRMS_Segment_t *outSeg_bl = drms_segment_lookup(outRec, "mf_bl"); DRMS_Array_t *outArray_bl = drms_array_create(DRMS_TYPE_DOUBLE, 1, outDims, mf_bl, &status); status = drms_segment_write(outSeg_bl, outArray_bl, 0); DRMS_Segment_t *outSeg_w = drms_segment_lookup(outRec, "w"); DRMS_Array_t *outArray_w = drms_array_create(DRMS_TYPE_DOUBLE, 1, outDims, w, &status); status = drms_segment_write(outSeg_w, outArray_w, 0); DRMS_Segment_t *outSeg_num = drms_segment_lookup(outRec, "num"); DRMS_Array_t *outArray_num = drms_array_create(DRMS_TYPE_DOUBLE, 1, outDims, num, &status); status = drms_segment_write(outSeg_num, outArray_num, 0); // Keywords SHOW("Set keywords...\n"); 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); drms_setkey_double(outRec, "THRESH", BRTHRESH); drms_setkey_double(outRec, "DA", ephem.da); 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"); drms_copykey(outRec, inRec, "INTERVAL"); // for MDI // Keywords of mf set_mf_keys(outRec, outDims_mf, mf, &fwtlat); // do nothing for now // Clean up DRMS_FREE_ARR(outArray_br); DRMS_FREE_ARR(outArray_bl); DRMS_FREE_ARR(outArray_w); DRMS_FREE_ARR(outArray_num); FREE_ARR(mf); // 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 mean values in certain bins void compute_mf(int *dims, double *br, double *bl, double *lon, double *lat, double *wght, int *outDims, double *mf) { int row_offset = outDims[0]; // 180 double *mf_br = mf; double *mf_bl = mf + row_offset; double *w = mf + row_offset * 2; double *num = mf + row_offset * 3; int nx = dims[0], ny = dims[1]; int nxny = nx * ny; int ngood = 0; int ilat; double s, v1, v2; // Int Loop for (int idx = 0; idx < nxny; idx++) { if (isnan(lon[idx])) continue; ngood++; // lon if (fabs(lon[idx]) > 45.) continue; // dob't use lon gt \pm 45 // lat ilat = floor(lat[idx] + 90.); // 0S, 180N if (ilat >= 180 || ilat < 0) continue; // compute mf_br[ilat] += (br[idx] * wght[idx]); mf_bl[ilat] += (bl[idx]); w[ilat] += wght[idx]; num[ilat] ++; } // MF loop for (ilat = 0; ilat < 180; ilat ++) { num[ilat] = fabs(num[ilat]); if (num[ilat] < EPSL) { mf_br[ilat] = DRMS_MISSING_DOUBLE; mf_bl[ilat] = DRMS_MISSING_DOUBLE; continue; } mf_br[ilat] /= (w[ilat]); mf_bl[ilat] /= (num[ilat]); } } // Compute flux weighted lat void compute_fwtlat(int *dims, double *br, double *lon, double *lat, double *wght, struct fwt *fwtlat) { int nx = dims[0], ny = dims[1]; int nxny = nx * ny; double fln[2] = {0, 0}, fls[2] = {0, 0}; // product of flux and lat double f, fl; for (int idx = 0; idx < nxny; idx++) { // sanction if (fabs(lon[idx]) > 45. || fabs(lat[idx]) > 40. || fabs(br[idx]) < BRTHRESH) continue; // flux, flux times lat f = fabs(br[idx] * wght[idx]); fl = f * lat[idx]; // north pos if (lat[idx] >= 0 && br[idx] >= 0) { fwtlat->fluxn[0] += f; fln[0] += fl; } // north neg if (lat[idx] >= 0 && br[idx] < 0) { fwtlat->fluxn[1] += f; fln[1] += fl; } // south pos if (lat[idx] < 0 && br[idx] >= 0) { fwtlat->fluxs[0] += f; fls[0] += fl; } // sorth neg if (lat[idx] < 0 && br[idx] < 0) { fwtlat->fluxs[1] += f; fls[1] += fl; } } fwtlat->latn[0] = fln[0] / fwtlat->fluxn[0]; fwtlat->latn[1] = fln[1] / fwtlat->fluxn[1]; fwtlat->lats[0] = fls[0] / fwtlat->fluxs[0]; fwtlat->lats[1] = fls[1] / fwtlat->fluxs[1]; fwtlat->fluxn[0] *= (1.e-4); // in 1.e4 G^2 fwtlat->fluxn[1] *= (-1.e-4); fwtlat->fluxs[0] *= (1.e-4); fwtlat->fluxs[1] *= (-1.e-4); } // Set polar field keywords void set_mf_keys(DRMS_Record_t *outRec, int *outDims, double *mf, struct fwt *fwtlat) { int row_offset = outDims[0]; // 180 double *mf_br = mf; double *mf_bl = mf + row_offset; double *w = mf + row_offset * 2; double *num = mf + row_offset * 3; int idxn, idxs; // 70-90 band double bn3 = 0, bs3 = 0, wn3 = 0, ws3 = 0, numn3 = 0, nums3 = 0; for (int i = 0; i < 20; i++) { // 20 lat bins idxn = 179 - i; if (num[idxn] > EPSL) { // skip NaN's and average available ones bn3 += mf_br[idxn] * w[idxn]; wn3 += w[idxn]; numn3 += num[idxn]; } // idxs = i; if (num[idxs] > EPSL) { bs3 += mf_br[idxs] * w[idxs]; ws3 += w[idxs]; nums3 += num[idxs]; } } // 50-60 and 60-70 double bn2 = 0, bs2 = 0, wn2 = 0, ws2 = 0, numn2 = 0, nums2 = 0; double bn1 = 0, bs1 = 0, wn1 = 0, ws1 = 0, numn1 = 0, nums1 = 0; for (int i = 0; i < 10; i++) { idxn = 159 - i; bn2 += mf_br[idxn] * w[idxn]; wn2 += w[idxn]; numn2 += num[idxn]; // idxn = 149 - i; bn1 += mf_br[idxn] * w[idxn]; wn1 += w[idxn]; numn1 += num[idxn]; // idxs = i + 20; bs2 += mf_br[idxs] * w[idxs]; ws2 += w[idxs]; nums2 += num[idxs]; // idxs = i + 30; bs1 += mf_br[idxs] * w[idxs]; ws1 += w[idxs]; nums1 += num[idxs]; } // Set keys drms_setkey_double(outRec, "BANDN3", bn3 / wn3); drms_setkey_double(outRec, "BANDS3", bs3 / ws3); drms_setkey_double(outRec, "BANDN2", bn2 / wn2); drms_setkey_double(outRec, "BANDS2", bs2 / ws2); drms_setkey_double(outRec, "BANDN1", bn1 / wn1); drms_setkey_double(outRec, "BANDS1", bs1 / ws1); drms_setkey_double(outRec, "CAPN2", (bn2 + bn3) / (wn2 + wn3)); drms_setkey_double(outRec, "CAPS2", (bs2 + bs3) / (ws2 + ws3)); drms_setkey_double(outRec, "CAPN1", (bn1 + bn2 + bn3) / (wn1 + wn2 + wn3)); drms_setkey_double(outRec, "CAPS1", (bs1 + bs2 + bs3) / (ws1 + ws2 + ws3)); drms_setkey_double(outRec, "NUMN3", numn3); drms_setkey_double(outRec, "NUMS3", nums3); drms_setkey_double(outRec, "NUMN2", numn2); drms_setkey_double(outRec, "NUMS2", nums2); drms_setkey_double(outRec, "NUMN1", numn1); drms_setkey_double(outRec, "NUMS1", nums1); drms_setkey_double(outRec, "WN3", wn3); drms_setkey_double(outRec, "WS3", ws3); drms_setkey_double(outRec, "WN2", wn2); drms_setkey_double(outRec, "WS2", ws2); drms_setkey_double(outRec, "WN1", wn1); drms_setkey_double(outRec, "WS1", ws1); // Set keys drms_setkey_double(outRec, "FLUXN_P", fwtlat->fluxn[0]); drms_setkey_double(outRec, "FLUXN_N", fwtlat->fluxn[1]); drms_setkey_double(outRec, "FLUXS_P", fwtlat->fluxs[0]); drms_setkey_double(outRec, "FLUXS_N", fwtlat->fluxs[1]); drms_setkey_double(outRec, "FLATN_P", fwtlat->latn[0]); drms_setkey_double(outRec, "FLATN_N", fwtlat->latn[1]); drms_setkey_double(outRec, "FLATS_P", fwtlat->lats[0]); drms_setkey_double(outRec, "FLATS_N", fwtlat->lats[1]); }
Karen Tian |
Powered by ViewCVS 0.9.4 |