[Dart-dev] [4649] DART/trunk/time_manager/time_manager_mod.f90: Added SOLAR_MARS as a separate calendar type, code from Christopher Lee,

nancy at ucar.edu nancy at ucar.edu
Tue Jan 11 16:01:14 MST 2011


Revision: 4649
Author:   nancy
Date:     2011-01-11 16:01:14 -0700 (Tue, 11 Jan 2011)
Log Message:
-----------
Added SOLAR_MARS as a separate calendar type, code from Christopher Lee, 
JPL/Ashima Research.  Will be used for WRF/Mars soon-to-be released code.

Modified Paths:
--------------
    DART/trunk/time_manager/time_manager_mod.f90

-------------- next part --------------
Modified: DART/trunk/time_manager/time_manager_mod.f90
===================================================================
--- DART/trunk/time_manager/time_manager_mod.f90	2011-01-11 22:53:21 UTC (rev 4648)
+++ DART/trunk/time_manager/time_manager_mod.f90	2011-01-11 23:01:14 UTC (rev 4649)
@@ -54,34 +54,35 @@
 
 ! List of available calendar types
 public :: THIRTY_DAY_MONTHS,    JULIAN,    GREGORIAN,  NOLEAP,   NO_CALENDAR, &
-          GREGORIAN_MARS
+          GREGORIAN_MARS,   SOLAR_MARS
 
 ! Subroutines and functions involving relations between time and calendar
 public :: set_calendar_type, get_calendar_type, get_calendar_string
 public :: set_date,       set_date_gregorian,         set_date_julian, &
                           set_date_thirty,            set_date_no_leap, &
-                          set_date_gregorian_mars
+                          set_date_gregorian_mars, set_date_solar_mars
 public :: get_date,       get_date_gregorian,         get_date_julian, &
                           get_date_thirty,            get_date_no_leap, &
-                          get_date_gregorian_mars
+                          get_date_gregorian_mars, get_date_solar_mars
 public :: increment_date, increment_gregorian,        increment_julian, &
                           increment_thirty,           increment_no_leap, &
-                          increment_gregorian_mars
+                          increment_gregorian_mars, increment_solar_mars
 public :: decrement_date, decrement_gregorian,        decrement_julian, &
                           decrement_thirty,           decrement_no_leap, &
-                          decrement_gregorian_mars
+                          decrement_gregorian_mars, decrement_solar_mars
 public :: days_in_month,  days_in_month_gregorian,    days_in_month_julian, &
                           days_in_month_no_leap,      days_in_month_thirty, &
-                          days_in_month_gregorian_mars
+                          days_in_month_gregorian_mars, days_in_month_solar_mars
 public :: leap_year,      leap_year_gregorian,        leap_year_julian, &
                           leap_year_no_leap,          leap_year_thirty, &
-                          leap_year_gregorian_mars
+                          leap_year_gregorian_mars, leap_year_solar_mars
 public :: length_of_year, length_of_year_thirty,      length_of_year_julian, &
                           length_of_year_gregorian,   length_of_year_no_leap, &
-                          length_of_year_gregorian_mars
+                          length_of_year_gregorian_mars, length_of_year_solar_mars
 public :: days_in_year,   days_in_year_thirty,        days_in_year_julian, &
                           days_in_year_gregorian,     days_in_year_no_leap, &
-                          days_in_year_gregorian_mars
+                          days_in_year_gregorian_mars, days_in_year_solar_mars
+
 public :: month_name
 
 public :: julian_day
@@ -99,10 +100,11 @@
 ! Global data to define calendar type
 integer, parameter :: THIRTY_DAY_MONTHS = 1,      JULIAN = 2, &
                       GREGORIAN = 3,              NOLEAP = 4, &
-                      NO_CALENDAR = 0,            GREGORIAN_MARS = 5
+                      NO_CALENDAR = 0,            GREGORIAN_MARS = 5, &
+                      SOLAR_MARS = 6
 ! FIXME: should be a namelist to select default calendar.  make no calendar the
 ! default for now
-integer, private :: calendar_type = NO_CALENDAR, max_type = 5
+integer, private :: calendar_type = NO_CALENDAR, max_type = 6
 
 ! Define number of days per month
 integer, private :: days_per_month(12) = (/31,28,31,30,31,30,31,31,30,31,30,31/)
@@ -779,6 +781,10 @@
            calendar_type  = GREGORIAN_MARS
            found_calendar = .true.
            exit WhichCalendar
+   elseif ( cstring == 'SOLAR_MARS' ) then
+           calendar_type  = SOLAR_MARS
+           found_calendar = .true.
+           exit WhichCalendar
    elseif ( cstring == 'GREGORIAN' ) then
            calendar_type  = GREGORIAN
            found_calendar = .true.
@@ -833,6 +839,7 @@
    if (calendar_type ==         GREGORIAN) mystring = 'GREGORIAN'
    if (calendar_type ==       NO_CALENDAR) mystring = 'NO_CALENDAR'
    if (calendar_type ==    GREGORIAN_MARS) mystring = 'GREGORIAN_MARS'
+   if (calendar_type ==        SOLAR_MARS) mystring = 'SOLAR_MARS'
    if (calendar_type == THIRTY_DAY_MONTHS) mystring = 'THIRTY_DAY_MONTHS'
 enddo
 
@@ -874,6 +881,9 @@
 case(GREGORIAN_MARS)
    ! NOTE: "month" has no meaning in Mars calendar
    call get_date_gregorian_mars(time, year, month, day, hour, minute, second)
+case(SOLAR_MARS)
+   ! NOTE: "month" has no meaning in Mars calendar
+   call get_date_solar_mars(time, year, month, day, hour, minute, second)
 case default
    write(errstring,*)'type is ',calendar_type,' must be one of ', &
                       THIRTY_DAY_MONTHS,GREGORIAN,JULIAN,NOLEAP,GREGORIAN_MARS
@@ -1147,6 +1157,64 @@
 end subroutine get_date_gregorian_mars
 
 
+subroutine get_date_solar_mars(time, year, month, day, hour, minute, second)
+!------------------------------------------------------------------------
+!
+! Computes date corresponding to time for solar MARS calendar
+! wgl - we need this to easily map from MarsWRF calendar to time_type
+!         NOTE :: "month" has no meaning for the Mars calendar
+!         ALSO :: the first day of the year is day 1, not 0
+!         PlanetWRF wrfout files follow :: YYYY-DDDDD_HH:MM:SS
+!
+! CL New method uses Mars Solar Date with no concept of 'year' in the date string
+! The year still starts on day 1
+! year is always 1
+
+implicit none
+
+type(time_type), intent(in)  :: time
+integer,         intent(out) :: second, minute, hour, day, month, year
+
+integer :: t
+integer :: num_days, iyear, days_this_year
+
+! "base_year" for Mars will be defined as 1 (earliest wrfout file has year = 1)
+integer, parameter :: base_year= 1
+
+if ( .not. module_initialized ) call time_manager_init
+
+year = 1
+num_days = time%days
+
+111 continue
+
+
+! No need to deal with months on Mars -- make it 1 by default so that other
+!    functions do not break (like print_date and month_name)
+month = 1
+
+! Need to add 1 because Mars has NO day 0
+day = num_days + 1
+
+!cl Time here corresponds to Martian Local Mean Solar Time (LMST), which is what the model 
+!cl uses without telling anybody. Essentially, we assume that the Sun 'moves' at a constant
+!cl rate across the sky, completing a circle in 24 Mars hours, and we arbitrarily split the 
+!cl Mars hour into 3600 Mars seconds, which correspons to roughly 1.02 SI seconds
+!cl Inside WRF, Mars delta seconds are converted to SI delta seconds, and the Mars LMST
+!cl is used to calculate the position of the sun either as (LMST)*360/24 or (LTST)*360/24. where 
+!cl LTST is Local True Solar Time, accounting for variable Solar day length
+!cl with orbit (Equation Of Time).
+! Find hour,minute and second
+
+t      = time%seconds
+hour   = t / (60 * 60)
+t      = t - hour * (60 * 60)
+minute = t / 60
+second = t - 60 * minute
+
+end subroutine get_date_solar_mars
+
+
 !========================================================================
 ! END OF get_date BLOCK
 !========================================================================
@@ -1186,9 +1254,11 @@
    set_date =   set_date_no_leap(year, month, day, ohours, ominutes, oseconds)
 case(GREGORIAN_MARS)
    set_date =   set_date_gregorian_mars(year, month, day, ohours, ominutes, oseconds)
+case(SOLAR_MARS)
+   set_date =   set_date_solar_mars(year, month, day, ohours, ominutes, oseconds)
 case default
    write(errstring,*)'type is ',calendar_type,' must be one of ', &
-                      THIRTY_DAY_MONTHS,GREGORIAN,JULIAN,NOLEAP,GREGORIAN_MARS
+                      THIRTY_DAY_MONTHS,GREGORIAN,JULIAN,NOLEAP,GREGORIAN_MARS,SOLAR_MARS
    call error_handler(E_ERR,'set_date',errstring,source,revision,revdate)
 end select
 end function set_date
@@ -1484,7 +1554,65 @@
 
 end function set_date_gregorian_mars
 
+function set_date_solar_mars(year, month, day, hours, minutes, seconds)
+!------------------------------------------------------------------------
+!
+! Computes time corresponding to date for gregorian MARS calendar.
+! wgl - we need this to easily map from MarsWRF calendar to time_type
+!         NOTE :: "month" has no meaning for the Mars calendar
+!         ALSO :: the first day of the year is day 1, not 0
+!         PlanetWRF wrfout files follow :: YYYY-DDDDD_HH:MM:SS
+!
+!cl number of days in year is now 100000, and there can only be 1 year.
+!cl valid until 2050 Earth date, by which time WRF will not be used.
 
+implicit none
+
+integer, intent(in)           :: year, month, day
+integer, intent(in), optional :: hours, minutes, seconds
+type(time_type)               :: set_date_solar_mars
+
+integer :: oseconds, ominutes, ohours
+
+! "base_year" for Mars will be defined as 1 (earliest wrfout file has year = 1)
+integer :: base_year = 1
+
+if ( .not. module_initialized ) call time_manager_init
+
+! Missing optionals are set to 0
+
+oseconds = 0; if(present(seconds)) oseconds = seconds
+ominutes = 0; if(present(minutes)) ominutes = minutes
+ohours   = 0; if(present(hours  ))   ohours = hours
+
+! Need to check for bogus dates
+
+! Do not bother checking month bounds because it has no meaning (though it should
+!   be set to 1)
+if(    oseconds > 59 .or. oseconds < 0 .or. &
+       ominutes > 59 .or. ominutes < 0 .or. &
+       ohours   > 23 .or. ohours   < 0 .or. &
+                          day      < 1 .or. &
+                          year     < base_year) then
+   write(errstring,'(''year,mon,day,hour,min,sec'',6(1x,i4),'' not a valid date.'')') &
+              year,month,day,ohours,ominutes,oseconds
+   call error_handler(E_ERR,'set_date_solar_mars',errstring,source,revision,revdate)
+endif
+
+! Month has no meaning for Mars calendar
+
+! Currently there is no leap year defined for Mars
+
+
+set_date_solar_mars%seconds = oseconds + 60*(ominutes + 60 * ohours)
+
+!cl set_date_solar_mars%days = day - 1 + 669*(year - base_year)
+!cl number of days in year changed to 100000 to allow MSD orbital calculation
+!cl to allow simpler interface between data and model in the assimilation
+set_date_solar_mars%days = day - 1 !this is always 0 -> + 100000*(year - base_year)
+
+end function set_date_solar_mars
+
 !=========================================================================
 ! END OF set_date BLOCK
 !=========================================================================
@@ -1536,6 +1664,9 @@
 case(GREGORIAN_MARS)
    increment_date = increment_gregorian_mars(time, oyears, omonths, odays, &
                                      ohours, ominutes, oseconds)
+case(SOLAR_MARS)
+   increment_date = increment_solar_mars(time, oyears, omonths, odays, &
+                                     ohours, ominutes, oseconds)
 case default
    write(errstring,*)'calendar type (',calendar_type,') must be one of ', &
                       THIRTY_DAY_MONTHS ,GREGORIAN,JULIAN,NOLEAP,GREGORIAN_MARS
@@ -1834,8 +1965,30 @@
 
 end function increment_gregorian_mars
 
+function increment_solar_mars(time, years, months, days, hours, minutes, seconds)
+!-------------------------------------------------------------------------
+!
+! Given time and some date increment, computes new time for gregorian MARS calendar.
 
+implicit none
 
+type(time_type), intent(in)           :: time
+integer,         intent(in), optional :: seconds, minutes, hours, days, months, years
+type(time_type)                       :: increment_solar_mars
+
+!integer :: oseconds, ominutes, ohours, odays, omonths, oyears
+!integer :: csecond, cminute, chour, cday, cmonth, cyear
+
+if ( .not. module_initialized ) call time_manager_init
+
+call error_handler(E_ERR,'increment_solar_mars','not implemented',source,revision,revdate)
+
+! FIXME: set a return value to avoid compiler warnings
+increment_solar_mars = time
+
+end function increment_solar_mars
+
+
 !=========================================================================
 ! END OF increment_date BLOCK
 !=========================================================================
@@ -1887,6 +2040,9 @@
 case(GREGORIAN_MARS)
    decrement_date = decrement_gregorian_mars(time, oyears, omonths, odays, &
                        ohours, ominutes, oseconds)
+case(SOLAR_MARS)
+   decrement_date = decrement_solar_mars(time, oyears, omonths, odays, &
+                       ohours, ominutes, oseconds)
 case default
    write(errstring,*)'calendar type (',calendar_type,') not allowed.'
    call error_handler(E_ERR,'decrement_date',errstring,source,revision,revdate)
@@ -2180,8 +2336,30 @@
 
 end function decrement_gregorian_mars
 
+function decrement_solar_mars(time, years, months, days, hours, minutes, seconds)
+!-------------------------------------------------------------------------
+!
+! Given time and some date decrement, computes new time for gregorian MARS calendar.
 
+implicit none
 
+type(time_type), intent(in)           :: time
+integer,         intent(in), optional :: seconds, minutes, hours, days, months, years
+type(time_type)                       :: decrement_solar_mars
+
+!integer :: oseconds, ominutes, ohours, odays, omonths, oyears
+!integer :: csecond, cminute, chour, cday, cmonth, cyear
+
+if ( .not. module_initialized ) call time_manager_init
+
+call error_handler(E_ERR,'decrement_gregorian','not implemented',source,revision,revdate)
+
+! FIXME: set a return value to avoid compiler warnings
+decrement_solar_mars = time
+
+end function decrement_solar_mars
+
+
 !=========================================================================
 ! END OF decrement_date BLOCK
 !=========================================================================
@@ -2214,6 +2392,8 @@
    days_in_month = days_in_month_no_leap(time)
 case(GREGORIAN_MARS)
    days_in_month = days_in_month_gregorian_mars(time)
+case(SOLAR_MARS)
+   days_in_month = days_in_month_solar_mars(time)
 case default
    write(errstring,*)'Invalid calendar type (',calendar_type,')'
    call error_handler(E_ERR,'days_in_month',errstring,source,revision,revdate)
@@ -2319,7 +2499,26 @@
 
 end function days_in_month_gregorian_mars
 
+function days_in_month_solar_mars(time)
+!--------------------------------------------------------------------------
+!
+! Returns the number of days in a gregorian MARS month.
 
+implicit none
+
+type(time_type), intent(in) :: time
+integer                     :: days_in_month_solar_mars
+
+if ( .not. module_initialized ) call time_manager_init
+
+call error_handler(E_ERR,'days_in_month_solar_mars', &
+                  'not implemented; Mars has no months',&
+                  source,revision,revdate)
+days_in_month_solar_mars = -1
+
+end function days_in_month_solar_mars
+
+
 !==========================================================================
 ! END OF days_in_month BLOCK
 !==========================================================================
@@ -2349,6 +2548,8 @@
    leap_year = leap_year_no_leap(time)
 case(GREGORIAN_MARS)
    leap_year = leap_year_gregorian_mars(time)
+case(SOLAR_MARS)
+   leap_year = leap_year_solar_mars(time)
 case default
    write(errstring,*)'invalid calendar type (',calendar_type,')'
    call error_handler(E_ERR,'leap_year',errstring,source,revision,revdate)
@@ -2458,8 +2659,28 @@
 
 end function leap_year_gregorian_mars
 
+function leap_year_solar_mars(time)
+!--------------------------------------------------------------------------
+!
+! Is this a leap year for gregorian calendar?
+! trick question: answer is always no.
 
+implicit none
 
+type(time_type), intent(in) :: time
+logical                     :: leap_year_solar_mars
+
+if ( .not. module_initialized ) call time_manager_init
+
+call error_handler(E_MSG,'leap_year_solar_mars', &
+                  'not implemented; Mars has no leap year',&
+                   source,revision,revdate)
+
+leap_year_solar_mars = .FALSE.
+
+end function leap_year_solar_mars
+
+
 !==========================================================================
 ! END OF leap_year BLOCK
 !==========================================================================
@@ -2489,6 +2710,8 @@
    length_of_year = length_of_year_no_leap()
 case(GREGORIAN_MARS)
    length_of_year = length_of_year_gregorian_mars()
+case(SOLAR_MARS)
+   length_of_year = length_of_year_solar_mars()
 case default
    write(errstring,*)'invalid calendar type (',calendar_type,')'
    call error_handler(E_ERR,'length_of_year',errstring,source,revision,revdate)
@@ -2574,7 +2797,19 @@
 
 end function length_of_year_gregorian_mars
 
+function length_of_year_solar_mars()
+!---------------------------------------------------------------------------
 
+implicit none
+
+type(time_type) :: length_of_year_solar_mars
+
+if ( .not. module_initialized ) call time_manager_init
+
+length_of_year_solar_mars = set_time(0, 669)
+
+end function length_of_year_solar_mars
+
 !==========================================================================
 ! END OF length_of_year BLOCK
 !==========================================================================
@@ -2605,6 +2840,8 @@
    days_in_year = days_in_year_no_leap(time)
 case(GREGORIAN_MARS)
    days_in_year = days_in_year_gregorian_mars(time)
+case(SOLAR_MARS)
+   days_in_year = days_in_year_solar_mars(time)
 case default
    write(errstring,*)'invalid calendar type (',calendar_type,')'
    call error_handler(E_ERR,'days_in_year',errstring,source,revision,revdate)
@@ -2699,7 +2936,24 @@
 
 end function days_in_year_gregorian_mars
 
+function days_in_year_solar_mars(time)
+!---------------------------------------------------------------------------
 
+implicit none
+
+type(time_type), intent(in) :: time
+integer                     :: days_in_year_solar_mars
+
+if ( .not. module_initialized ) call time_manager_init
+
+!CL METHOD, with realistic rotation
+days_in_year_solar_mars = 100000 
+! 100000 days is the maximum number of days representable in the format used by planetWRF for days
+! we ignore the years and assume that 'days' represents the Mars Solar Date (MSD)
+! from MSD we can calculate all required astronomical data using Allison and McEwan(2000)
+
+end function days_in_year_solar_mars
+
 !==========================================================================
 ! END OF days_in_year BLOCK
 !==========================================================================
@@ -2870,6 +3124,14 @@
         write (unit_in,10)       'DATE: ', y,mon(1:3),' ',d,' ',h,':',m,':',s
      endif
 10   format (a,i4,1x,a3,a1,i3.3,3(a1,i2.2))
+  else if (calendar_type == SOLAR_MARS ) then
+     mon = 'sol'
+     if (present(str)) then
+        write (unit_in,12) trim(str)//' ', y,mon(1:3),' ',d,' ',h,':',m,':',s
+     else
+        write (unit_in,12)       'DATE: ', y,mon(1:3),' ',d,' ',h,':',m,':',s
+     endif
+12   format (a,i4,1x,a3,a1,i5.5,3(a1,i2.2))
 
   ! if not Mars, then use Earth calendar
   else
@@ -3010,6 +3272,12 @@
    ! NOTE: "month" has no meaning for Mars calendar
    month = 1
    time = set_date(year, month, day, hour, minute, second)
+elseif (calendar_type == SOLAR_MARS) then
+   write(*, *) 'input date (as integers): year day hour minute second'
+   read(*, *) year, day, hour, minute, second
+   ! NOTE: "month" has no meaning for Mars calendar
+   month = 1
+   time = set_date(year, month, day, hour, minute, second)
 else
    write(*, *) 'input time in days and seconds (as integers)'
    read(*, *) day, second


More information about the Dart-dev mailing list