g_solposition.c 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  1. /*
  2. * G_calc_solar_position() calculates solar position parameters from
  3. * given position, date and time
  4. *
  5. * Written by Markus Neteler <neteler@geog.uni-hannover.de>
  6. * with kind help from Morten Hulden <morten untamo.net>
  7. *
  8. *----------------------------------------------------------------------------
  9. * using solpos.c with permission from
  10. * From rredc@nrel.gov Wed Mar 21 18:37:25 2001
  11. * Message-Id: <v04220805b6de9b1ad6ff@[192.174.39.30]>
  12. * Mary Anderberg
  13. * http://rredc.nrel.gov
  14. * National Renewable Energy Laboratory
  15. * 1617 Cole Boulevard
  16. * Golden, Colorado, USA 80401
  17. *
  18. * http://rredc.nrel.gov/solar/codes_algs/solpos/
  19. *
  20. * G_calc_solar_position is based on: soltest.c
  21. * by
  22. * Martin Rymes
  23. * National Renewable Energy Laboratory
  24. * 25 March 1998
  25. *----------------------------------------------------------------------------*/
  26. /* uncomment to get debug output */
  27. #include <math.h>
  28. #include <string.h>
  29. #include <stdio.h>
  30. #include <grass/gis.h>
  31. #include <grass/glocale.h>
  32. #include <grass/gprojects.h>
  33. #include "solpos00.h"
  34. struct posdata pd, *pdat; /* declare solpos data struct and a pointer for it */
  35. long calc_solar_position(double longitude, double latitude, double timezone,
  36. int year, int month, int day, int hour, int minute,
  37. int second)
  38. {
  39. /* Note: this code is valid from year 1950 to 2050 (solpos restriction)
  40. - the algorithm will compensate for leap year.
  41. - longitude, latitude: decimal degree
  42. - timezone: DO NOT ADJUST FOR DAYLIGHT SAVINGS TIME.
  43. - timezone: negative for zones west of Greenwich
  44. - lat/long: east and north positive
  45. - the atmospheric refraction is calculated for 1013hPa, 15 degrees C
  46. - time: local time from your watch
  47. */
  48. long retval; /* to capture S_solpos return codes */
  49. struct Key_Value *in_proj_info, *in_unit_info; /* projection information of input map */
  50. struct pj_info iproj; /* input map proj parameters */
  51. struct pj_info oproj; /* output map proj parameters */
  52. extern struct Cell_head window;
  53. int inside;
  54. /* we don't like to run G_calc_solar_position in xy locations */
  55. if (window.proj == 0)
  56. G_fatal_error(_("Unable to calculate sun position in un-projected locations. "
  57. "Specify sunposition directly."));
  58. pdat = &pd; /* point to the structure for convenience */
  59. /* Initialize structure to default values. (Optional only if ALL input
  60. parameters are initialized in the calling code, which they are not
  61. in this example.) */
  62. S_init(pdat);
  63. /* check if given point is in current window */
  64. G_debug(1, "window.north: %f, window.south: %f\n", window.north,
  65. window.south);
  66. G_debug(1, "window.west: %f, window.east : %f\n", window.west,
  67. window.east);
  68. inside = 0;
  69. if (latitude >= window.south && latitude <= window.north &&
  70. longitude >= window.west && longitude <= window.east)
  71. inside = 1;
  72. if (!inside)
  73. G_warning(_("Specified point %f, %f outside of current region, "
  74. "is that intended? Anyway, it will be used."),
  75. longitude, latitude);
  76. /* if coordinates are not in lat/long format, transform them: */
  77. if ((G_projection() != PROJECTION_LL) && window.proj != 0) {
  78. G_debug(1, "Transforming input coordinates to lat/long (req. for solar position)");
  79. /* read current projection info */
  80. if ((in_proj_info = G_get_projinfo()) == NULL)
  81. G_fatal_error(_("Unable to get projection info of current location"));
  82. if ((in_unit_info = G_get_projunits()) == NULL)
  83. G_fatal_error(_("Unable to get projection units of current location"));
  84. if (pj_get_kv(&iproj, in_proj_info, in_unit_info) < 0)
  85. G_fatal_error(_("Unable to get projection key values of current location"));
  86. G_free_key_value(in_proj_info);
  87. G_free_key_value(in_unit_info);
  88. /* Try using pj_print_proj_params() instead of all this */
  89. G_debug(1, "Projection found in location:");
  90. G_debug(1, "IN: meter: %f zone: %i proj: %s (iproj struct)",
  91. iproj.meters, iproj.zone, iproj.proj);
  92. G_debug(1, "IN coord: longitude: %f, latitude: %f", longitude,
  93. latitude);
  94. /* see src/include/projects.h, struct PJconsts */
  95. /* set output projection to lat/long for solpos */
  96. oproj.zone = 0;
  97. oproj.meters = 1.;
  98. sprintf(oproj.proj, "ll");
  99. if ((oproj.pj = pj_latlong_from_proj(iproj.pj)) == NULL)
  100. G_fatal_error("Unable to set up lat/long projection parameters");
  101. /* XX do the transform
  102. * outx outy in_info out_info */
  103. if (pj_do_proj(&longitude, &latitude, &iproj, &oproj) < 0) {
  104. G_fatal_error(_("Error in pj_do_proj (projection of input coordinate pair)"));
  105. }
  106. G_debug(1, "Transformation to lat/long:");
  107. G_debug(1, "OUT: longitude: %f, latitude: %f", longitude,
  108. latitude);
  109. } /* transform if not LL */
  110. pdat->longitude = longitude; /* Note that latitude and longitude are */
  111. pdat->latitude = latitude; /* in DECIMAL DEGREES, not Deg/Min/Sec */
  112. pdat->timezone = timezone; /* DO NOT ADJUST FOR DAYLIGHT SAVINGS TIME. */
  113. pdat->year = year; /* The year */
  114. pdat->function &= ~S_DOY;
  115. pdat->month = month;
  116. pdat->day = day; /* the algorithm will compensate for leap year, so
  117. you just count days). S_solpos can be
  118. configured to accept day-of-the year */
  119. /* The time of day (STANDARD (GMT) time) */
  120. pdat->hour = hour;
  121. pdat->minute = minute;
  122. pdat->second = second;
  123. /* Let's assume that the temperature is 20 degrees C and that
  124. the pressure is 1013 millibars. The temperature is used for the
  125. atmospheric refraction correction, and the pressure is used for the
  126. refraction correction and the pressure-corrected airmass. */
  127. pdat->temp = 20.0;
  128. pdat->press = 1013.0;
  129. /* Finally, we will assume that you have a flat surface
  130. facing nowhere, tilted at latitude. */
  131. pdat->tilt = pdat->latitude; /* tilted at latitude */
  132. pdat->aspect = 180.0;
  133. /* perform the calculation */
  134. retval = S_solpos(pdat); /* S_solpos function call: returns long value */
  135. S_decode(retval, pdat); /* prints an error in case of problems */
  136. return retval;
  137. }