/** Evaluation function for 'sunpos' @return 0 on success */ static int sunpos_nrel_calc(struct BBoxInterp *bbox, int ninputs, int noutputs, double *inputs, double *outputs, double *jacobian ){ CALCPREPARE(4,2); double t, p, T, t_offset; t = inputs[0]; /* convert from JD seconds to JD days */ p = inputs[1] / 100. /* convert Pa to mbar */; T = inputs[2] - 273.15 /* convert °C to K */; t_offset = inputs[3]; spa_data S = *sunpos1; S.pressure = p; S.temperature = T; S.jd = (t + t_offset) / 3600 / 24; /* convert to days */ int res = spa_calculate(&S); //CONSOLE_DEBUG("Sun position: t = %f JD, p %f mbar, T = %f C: res = %d, az = %f, zen = %f",S.jd, p, T, res, S.azimuth, S.zenith); /* returned values are in degrees, need to convert back to base SI: radians */ outputs[0] = S.zenith * PI/180.; outputs[1] = S.azimuth180 * PI/180.; switch(res){ case 0: break; case 16: CONSOLE_DEBUG("Calculated julian day (t + offset) = %f is out of permitted range",S.jd); break; default: CONSOLE_DEBUG("Error code %d returned from spa_calculate",res); } /* 0 on success, non-zero is error code from spa_calculate (would prob be input parameters out-of-range) */ return res; }
int main (int argc, char *argv[]) { spa_data spa; //declare the SPA structure int result; float min, sec; //enter required input values into SPA structure spa.year = 2003; spa.month = 10; spa.day = 17; spa.hour = 12; spa.minute = 30; spa.second = 30; spa.timezone = -7.0; spa.delta_ut1 = 0; spa.delta_t = 67; spa.longitude = -105.1786; spa.latitude = 39.742476; spa.elevation = 1830.14; spa.pressure = 820; spa.temperature = 11; spa.slope = 30; spa.azm_rotation = -10; spa.atmos_refract = 0.5667; spa.function = SPA_ALL; //call the SPA calculate function and pass the SPA structure result = spa_calculate(&spa); if (result == 0) //check for SPA errors { //display the results inside the SPA structure printf("Julian Day: %.6f\n",spa.jd); printf("L: %.6e degrees\n",spa.l); printf("B: %.6e degrees\n",spa.b); printf("R: %.6f AU\n",spa.r); printf("H: %.6f degrees\n",spa.h); printf("Delta Psi: %.6e degrees\n",spa.del_psi); printf("Delta Epsilon: %.6e degrees\n",spa.del_epsilon); printf("Epsilon: %.6f degrees\n",spa.epsilon); printf("Zenith: %.6f degrees\n",spa.zenith); printf("Azimuth: %.6f degrees\n",spa.azimuth); printf("Incidence: %.6f degrees\n",spa.incidence); min = 60.0*(spa.sunrise - (int)(spa.sunrise)); sec = 60.0*(min - (int)min); printf("Sunrise: %02d:%02d:%02d Local Time\n", (int)(spa.sunrise), (int)min, (int)sec); min = 60.0*(spa.sunset - (int)(spa.sunset)); sec = 60.0*(min - (int)min); printf("Sunset: %02d:%02d:%02d Local Time\n", (int)(spa.sunset), (int)min, (int)sec); } else printf("SPA Error Code: %d\n", result); return 0; }
int calculate_position(spa_data *spa, struct tm *t) { int result; spa->year = t->tm_year + 1900; spa->month = t->tm_mon + 1; spa->day = t->tm_mday; spa->hour = t->tm_hour; spa->minute = t->tm_min; spa->second = t->tm_sec; result = spa_calculate(spa); return result; }
void SunPos (int t, double latitude, double longitude, double elevation, double tmp, double *zenith, double *azimuth) { spa_data spa; int spa_result; time_t rawtime; struct tm *timestamp; rawtime = (time_t) t; timestamp = gmtime (&rawtime); spa.year = timestamp->tm_year + 1900; spa.month = timestamp->tm_mon + 1; spa.day = timestamp->tm_mday; spa.hour = timestamp->tm_hour; spa.minute = timestamp->tm_min; spa.second = timestamp->tm_sec; spa.timezone = 0; spa.delta_t = 67; spa.delta_ut1 = 0; spa.atmos_refract = 0.5667; spa.longitude = longitude; spa.latitude = latitude; spa.elevation = elevation; /* Calculate surface pressure based on fao 1998 method (narasimhan 2002) */ spa.pressure = 1013.25 * pow ((293.0 - 0.0065 * spa.elevation) / 293.0, 5.26); spa.temperature = tmp; spa.function = SPA_ZA; spa_result = spa_calculate (&spa); if (spa_result != 0) { printf ("spa error code: %d\n", spa_result); PihmExit (1); } *azimuth = Mod ((360.0 + spa.azimuth180), 360.0); *zenith = spa.zenith; }
/////////////////////////////////////////////////////// //For easy integration into the VTP // void SetCommonValues(spa_data &spa, float longitude, float latitude, int year, int month, int day, int hour, int minute, int second, float timezone, float elevation) { spa.year = year; spa.month = month; spa.day = day; spa.hour= hour; spa.minute= minute; spa.second = second; spa.delta_t = 67.0f; // Found this value somewhere on the Internet (seems to work). spa.timezone = timezone; spa.longitude = longitude; spa.latitude = latitude; spa.elevation = elevation; spa.pressure=800.0f; // A reasonable value (?) ~ most users/locations are somewhat above sea level spa.temperature =18.0f; // A reasonable value ~ about average for most inhabited places spa.slope = 0.0f; // I think this is for a solar panel; we want flat ground. spa.azm_rotation=0.0f; // I think this is for a solar panel; we want flat ground. spa.atmos_refract=0.5667f; spa_calculate(&spa); }
static PyObject *spa_calc(PyObject *self, PyObject *args) { int N_IN, N_DOUBLE_IN, N_ARRAY_IN, N_DOUBLE_OUT, N_ARRAY_OUT, N; PyObject *input_obj[PYSPA_MAX_ARGS]; double input_double[PYSPA_MAX_ARGS]; PyArrayObject *input_arr[PYSPA_MAX_ARGS], *output_arr[PYSPA_MAX_ARGS]; double *input_arr_ptr[PYSPA_MAX_ARGS], *output_arr_ptr[PYSPA_MAX_ARGS]; int input_arr_map[PYSPA_MAX_ARGS], input_double_map[PYSPA_MAX_ARGS], input_type[PYSPA_MAX_ARGS]; double year=0, month=0, day=0, hour=0, minute=0, second=0, latitude=0, longitude=0, elevation=0, slope=0, aspect=0; double zenith, azimuth, incidence; double value; int flag; int i, j, ndim, dims[NPY_MAXDIMS], rc=0; spa_data spa; static const double m_air = 0.02896; // molecular mass of air, kg mol^-1 static const double R_const = 8.3143; // gas constant, N M mol^-1 K^-1 static const double g_const = 9.807; // gravity constant, m s^-2 static const double T_const = 288.15; // "default" air temperature, K /* Parse the input tuple */ for (i=0; i<64; i++) input_obj[i] = NULL; if (!PyArg_ParseTuple(args, "OOOOOOOO|OOO", &input_obj[0], &input_obj[1], &input_obj[2], &input_obj[3], &input_obj[4], &input_obj[5], &input_obj[6], &input_obj[7], &input_obj[8], &input_obj[9], &input_obj[10])) return NULL; if (input_obj[8] == NULL) { // fprintf(stderr, "Running SPA_ZA mode ...\n"); spa.function = SPA_ZA; N_IN = 8; N_DOUBLE_OUT = 0; N_ARRAY_OUT = 2; } else { // fprintf(stderr, "Running SPA_ZA_INC mode ...\n"); spa.function = SPA_ZA_INC; N_IN = 11; N_DOUBLE_OUT = 0; N_ARRAY_OUT = 3; } N_DOUBLE_IN = 0; N_ARRAY_IN = 0; for (i=0; i<N_IN; i++) { /* Interpret the input objects as numpy arrays. */ input_arr[i] = (PyArrayObject *) PyArray_FROM_OTF(input_obj[i], NPY_DOUBLE, NPY_IN_ARRAY); /* Is is really a numpy array? */ if (PyArray_NDIM(input_arr[i])==0) { input_type[i] = 0; input_double_map[N_DOUBLE_IN] = i; N_DOUBLE_IN++; input_double[i] = PyFloat_AsDouble(input_obj[i]); Py_XDECREF(input_arr[i]); } else { input_type[i] = 1; input_arr_map[N_ARRAY_IN] = i; N_ARRAY_IN++; } } /* If that didn't work, throw an exception. */ flag = 0; for (i=0; i<N_ARRAY_IN; i++) if (input_arr[input_arr_map[i]]==NULL) flag = 1; if (flag==1) { for (i=0; i<N_ARRAY_IN; i++) Py_XDECREF(input_arr[input_arr_map[i]]); return NULL; } /* Get pointers to the data as C-types. */ for (i=0; i<N_ARRAY_IN; i++) input_arr_ptr[input_arr_map[i]] = (double*) PyArray_DATA(input_arr[input_arr_map[i]]); /* How many data points are there? */ ndim = (int)PyArray_NDIM(input_arr[input_arr_map[0]]); N=1; for (j=0; j<ndim; j++) { dims[j] = PyArray_DIM(input_arr[input_arr_map[0]], j); N *= dims[j]; /* check for dimension size compatibility */ flag = 0; for (i=1; i<N_ARRAY_IN; i++) if (dims[j] != PyArray_DIM(input_arr[input_arr_map[i]], j)) flag = 1; if (flag==1) { for (i=0; i<N_ARRAY_IN; i++) Py_XDECREF(input_arr[input_arr_map[i]]); PyErr_SetString(PyExc_RuntimeError, "different dimensions of input arrays."); return NULL; } } for (i=0; i<N_ARRAY_OUT; i++) { output_arr[i] = (PyArrayObject *) PyArray_FromDims(ndim, dims, NPY_DOUBLE); output_arr_ptr[i] = (double*) PyArray_DATA(output_arr[i]); } /* Call the external C function to compute the results. */ for (j=0; j<N; j++) { for (i=0; i<N_IN; i++) { if (input_type[i] == 0) value = input_double[i]; else value = input_arr_ptr[i][j]; switch (i) { case 0: year = value; case 1: month = value; case 2: day = value; case 3: hour = value; case 4: minute = value; case 5: second = value; case 6: latitude = value; case 7: longitude = value; case 8: elevation = value; case 9: slope = value; case 10: aspect = value; } } /* some checks */ if (longitude>180) longitude -= 360; /* SPA's azm_rotation angle is measured from south and most aspect angle is measured from north */ aspect -= 180; if (aspect<-360) aspect += 360; spa.year = (int) year; spa.month = (int) month; spa.day = (int) day; spa.hour = (int) hour; spa.minute = (int) minute; spa.second = (int) second; spa.latitude = latitude; spa.longitude = longitude; spa.timezone = 0.0; spa.delta_t = 0; spa.elevation = elevation; spa.pressure = 1000*exp(-m_air*g_const*elevation/(R_const*T_const)); spa.temperature = 0; spa.slope = slope; spa.azm_rotation = aspect; spa.atmos_refract = 0.5667; rc = spa_calculate(&spa); if (rc == 0) { zenith = spa.zenith; azimuth = spa.azimuth; incidence = spa.incidence; } else { zenith = -9999; azimuth = -9999; incidence = -9999; } output_arr_ptr[0][j] = zenith; output_arr_ptr[1][j] = azimuth; if (spa.function == SPA_ZA_INC) output_arr_ptr[2][j] = incidence; } /* Clean up. */ for (i=0; i<N_ARRAY_IN; i++) Py_XDECREF(input_arr[input_arr_map[i]]); /* Build the output tuple */ if (spa.function == SPA_ZA) return Py_BuildValue("OO", output_arr[0], output_arr[1]); else return Py_BuildValue("OOO", output_arr[0], output_arr[1], output_arr[2]); }