timesync1

Two models, A & B, run simulations over time and exchange data via a timestep synchronization communication pattern. Both models compute the same variables (x and y) via the same source code and output data at each time step to a file, but they have different time steps.

C Version

Model Code:

  1#define _USE_MATH_DEFINES  // Required to use M_PI with MSVC
  2#include <math.h>
  3#include <stdio.h>
  4#include "YggInterface.h"
  5
  6
  7int timestep_calc(double t, const char* t_units, generic_t state) {
  8  double x_period = 10.0; // Days
  9  double y_period = 5.0;  // Days
 10  double x, y;
 11  int ret = 0;
 12  if (strcmp(t_units, "day") == 0) {
 13    // No conversion necessary
 14  } else if (strcmp(t_units, "hr") == 0) {
 15    x_period = x_period * 24.0;
 16    y_period = y_period * 24.0;
 17  } else {
 18    printf("timestep_calc: Unsupported unit '%s'\n", t_units);
 19    ret = -1;
 20  }
 21  if (ret >= 0) {
 22    x = sin(2.0 * M_PI * t / x_period);
 23    y = cos(2.0 * M_PI * t / y_period);
 24    ret = generic_map_set_double(state, "x", x, "");
 25    ret = generic_map_set_double(state, "y", y, "");
 26  }
 27  return ret;
 28}
 29
 30
 31int main(int argc, char *argv[]) {
 32
 33  double t_step = atof(argv[1]);
 34  char* t_units = argv[2];
 35  int exit_code = 0;
 36  printf("Hello from C timesync: timestep %f %s\n", t_step, t_units);
 37  double t_start = 0.0;
 38  double t_end = 5.0;
 39  if (strcmp(t_units, "hr") == 0) {
 40    t_end = 24.0 * t_end;
 41  }
 42  int ret;
 43  generic_t state = init_generic_map();
 44  ret = timestep_calc(t_start, t_units, state);
 45  if (ret < 0) {
 46    printf("timesync(C): Error in initial timestep calculation.");
 47    return -1;
 48  }
 49
 50  // Set up connections matching yaml
 51  // Timestep synchronization connection will be 'timesync'
 52  comm_t* timesync = yggTimesync("timesync", t_units);
 53  dtype_t* out_dtype = create_dtype_json_object(0, NULL, NULL, true);
 54  comm_t* out = yggOutputType("output", out_dtype);
 55
 56  // Initialize state and synchronize with other models
 57  double t = t_start;
 58  ret = rpcCall(timesync, t, state, &state);
 59  if (ret < 0) {
 60    printf("timesync(C): Initial sync failed.\n");
 61    return -1;
 62  }
 63  printf("timesync(C): t = %5.1f %-3s, x = %+ 5.2f, y = %+ 5.2f\n",
 64	 t, t_units, generic_map_get_double(state, "x"),
 65	 generic_map_get_double(state, "y"));
 66
 67  // Send initial state to output
 68  generic_t msg = copy_generic(state);
 69  ret = generic_map_set_double(msg, "time", t, t_units);
 70  if (ret < 0) {
 71    printf("timesync(C): Failed to set time in initial output map.\n");
 72    return -1;
 73  }
 74  ret = yggSend(out, msg);
 75  if (ret < 0) {
 76    printf("timesync(C): Failed to send initial output for t=%f.\n", t);
 77    return -1;
 78  }
 79  destroy_generic(&msg);
 80
 81  // Iterate until end
 82  while (t < t_end) {
 83
 84    // Perform calculations to update the state
 85    t = t + t_step;
 86    ret = timestep_calc(t, t_units, state);
 87    if (ret < 0) {
 88      printf("timesync(C): Error in timestep calculation for t = %f.\n", t);
 89      return -1;
 90    }
 91
 92    // Synchronize the state
 93    ret = rpcCall(timesync, t, state, &state);
 94    if (ret < 0) {
 95      printf("timesync(C): sync for t=%f failed.\n", t);
 96      return -1;
 97    }
 98    printf("timesync(C): t = %5.1f %-3s, x = %+ 5.2f, y = %+ 5.2f\n",
 99	   t, t_units, generic_map_get_double(state, "x"),
100	   generic_map_get_double(state, "y"));
101
102    // Send output
103    msg = copy_generic(state);
104    ret = generic_map_set_double(msg, "time", t, t_units);
105    if (ret < 0) {
106      printf("timesync(C): Failed to set time in output map.\n");
107      return -1;
108    }
109    ret = yggSend(out, msg);
110    if (ret < 0) {
111      printf("timesync(C): Failed to send output for t=%f.\n", t);
112      return -1;
113    }
114    destroy_generic(&msg);
115  }
116
117  printf("Goodbye from C timesync\n");
118  destroy_generic(&state);
119  return 0;
120    
121}

Model YAML:

 1---
 2
 3models:
 4  - name: modelA
 5    language: c
 6    args:
 7      - ./src/timesync.c
 8      - 7  # Pass the timestep in hours
 9      - hr
10    timesync: True
11    outputs:
12      name: output
13      default_file:
14        name: modelA_output.txt
15        in_temp: True
16        filetype: table
17  - name: modelB
18    language: c
19    args:
20      - ./src/timesync.c
21      - 1  # Pass the timestep in days
22      - day
23    timesync: True
24    outputs:
25      name: output
26      default_file:
27        name: modelB_output.txt
28        in_temp: True
29        filetype: table

C++ Version

Model Code:

 1#define _USE_MATH_DEFINES  // Required to use M_PI with MSVC
 2#include <math.h>
 3#include <stdio.h>
 4#include "YggInterface.hpp"
 5
 6
 7void timestep_calc(rapidjson::units::Quantity<double>& t,
 8		  rapidjson::Document& state) {
 9  rapidjson::units::Quantity<double> x_period(10.0, "days");
10  rapidjson::units::Quantity<double> y_period(5.0, "days");
11  double x = sin(2.0 * M_PI * (t / x_period).value());
12  double y = cos(2.0 * M_PI * (t / y_period).value());
13#define SET_(key, val)							\
14  if (!state.HasMember(key))						\
15    state.AddMember(key, rapidjson::Value(val).Move(),			\
16		    state.GetAllocator());				\
17  else									\
18    state[key].SetDouble(val)
19  SET_("x", x);
20  SET_("y", y);
21}
22
23
24int main(int argc, char *argv[]) {
25
26  char* t_units = argv[2];
27  rapidjson::units::Quantity<double> t_step(atof(argv[1]), t_units);
28  std::cout << "Hello from C++ timesync: timestep " << t_step << std::endl;
29  rapidjson::units::Quantity<double> t_start(0.0, t_units);
30  rapidjson::units::Quantity<double> t_end(5.0, "days");
31  rapidjson::Document state(rapidjson::kObjectType);
32  timestep_calc(t_start, state);
33  int ret = 0;
34
35  // Set up connections matching yaml
36  // Timestep synchronization connection will default to 'timesync'
37  YggTimesync timesync("timesync", t_units);
38  dtype_t* out_dtype = create_dtype_json_object(0, NULL, NULL, true);
39  YggOutput out("output", out_dtype);
40
41  // Initialize state and synchronize with other models
42  rapidjson::units::Quantity<double> t = t_start;
43  ret = timesync.call(3, t.value(), &state, &state);
44  if (ret < 0) {
45    std::cerr << "timesync(C++): Initial sync failed." << std::endl;
46    return -1;
47  }
48  std::cout << "timesync(C++): t = " << t <<
49    ", x = " << state["x"].GetDouble() <<
50    ", y = " << state["x"].GetDouble() << std::endl;
51
52  // Send initial state to output
53  rapidjson::Document msg;
54  msg.CopyFrom(state, msg.GetAllocator());
55  msg.AddMember("time",
56		rapidjson::Value(t, msg.GetAllocator()).Move(),
57		msg.GetAllocator());
58  ret = out.send(1, &msg);
59  if (ret < 0) {
60    std::cerr << "timesync(C++): Failed to send initial output for t=" << t << std::endl;
61    return -1;
62  }
63
64  // Iterate until end
65  while (t < t_end) {
66
67    // Perform calculations to update the state
68    t = t + t_step;
69    timestep_calc(t, state);
70
71    // Synchronize the state
72    ret = timesync.call(3, t.value(), &state, &state);
73    if (ret < 0) {
74      std::cerr << "timesync(C++): sync for t=" << t << " failed" << std::endl;
75      return -1;
76    }
77    std::cout << "timesync(C++): t = " << t <<
78      ", x = " << state["x"].GetDouble() <<
79      ", y = " << state["x"].GetDouble() << std::endl;
80
81    // Send output
82    msg.CopyFrom(state, msg.GetAllocator());
83    msg.AddMember("time",
84		  rapidjson::Value(t, msg.GetAllocator()).Move(),
85		  msg.GetAllocator());
86    ret = out.send(1, &msg);
87    if (ret < 0) {
88      std::cerr << "timesync(C++): Failed to send output for t=" << t << std::endl;
89      return -1;
90    }
91  }
92
93  std::cout << "Goodbye from C++ timesync" << std::endl;
94  return 0;
95    
96}

Model YAML:

 1---
 2
 3models:
 4  - name: modelA
 5    language: c++
 6    args:
 7      - ./src/timesync.cpp
 8      - 7  # Pass the timestep in hours
 9      - hr
10    timesync: True
11    outputs:
12      name: output
13      default_file:
14        name: modelA_output.txt
15        in_temp: True
16        filetype: table
17  - name: modelB
18    language: c++
19    args:
20      - ./src/timesync.cpp
21      - 1  # Pass the timestep in days
22      - day
23    timesync: True
24    outputs:
25      name: output
26      default_file:
27        name: modelB_output.txt
28        in_temp: True
29        filetype: table

Fortran Version

Model Code:

  1program main
  2  use fygg
  3
  4  ! Declare resulting variables and create buffer for received message
  5  logical :: timestep_calc
  6  logical :: ret = .true.
  7  type(yggcomm) :: timesync, out
  8  character(len=32) :: arg
  9  character(len=0), dimension(0) :: dtype_keys
 10  type(yggdtype), dimension(0) :: dtype_vals
 11  type(yggdtype) :: out_dtype
 12  real(kind=8) :: t_step, t_start, t_end, t
 13  character(len=32) :: t_units
 14  type(ygggeneric) :: state, msg
 15  real(kind=8), pointer :: x, y
 16
 17  call get_command_argument(1, arg)
 18  read(arg, *) t_step
 19  call get_command_argument(2, arg)
 20  read(arg, *) t_units
 21  write (*, '("Hello from Fortran timesync: timestep ",F10.5," ",A)') &
 22       t_step, trim(t_units)
 23  t_start = 0.0
 24  t_end = 5.0
 25  if (t_units.eq."hr") then
 26     t_end = 24.0 * t_end
 27  end if
 28  state = init_generic_map()
 29  ret = timestep_calc(t_start, t_units, state)
 30  if (.not.ret) then
 31     write (*, '("timesync(Fortran): Error in initial timestep &
 32          &calculation.")')
 33  end if
 34
 35  ! Set up connections matching yaml
 36  ! Timestep synchronization connection will be 'timesync'
 37  timesync = ygg_timesync("timesync", t_units)
 38  out_dtype = create_dtype_json_object(0, dtype_keys, dtype_vals, .true.)
 39  out = ygg_output_type("output", out_dtype)
 40
 41  ! Initialize state and synchronize with other models
 42  t = t_start
 43  ret = ygg_rpc_call(timesync, [yggarg(t), yggarg(state)], &
 44       yggarg(state))
 45  if (.not.ret) then
 46     write (*, '("timesync(Fortran): Initial sync failed.")')
 47     stop 1
 48  end if
 49  call generic_map_get(state, "x", x)
 50  call generic_map_get(state, "y", y)
 51  write (*, '("timesync(Fortran): t = ",F5.1," ",A3,", x = ",&
 52       &SP,F5.2,", y = ",F5.2)') t, adjustl(t_units), x, y
 53
 54  ! Send initial state to output
 55  msg = copy_generic(state)
 56  call generic_map_set(msg, "time", t, t_units)
 57  ret = ygg_send_var(out, yggarg(msg))
 58  if (.not.ret) then
 59     write (*, '("timesync(Fortran): Failed to send initial output &
 60          &for t=",F10.5,".")') t
 61     stop 1
 62  end if
 63  call free_generic(msg)
 64
 65  ! Iterate until end
 66  do while (t.lt.t_end)
 67
 68     ! Perform calculations to update the state
 69     t = t + t_step
 70     ret = timestep_calc(t, t_units, state)
 71     if (.not.ret) then
 72        write (*, '("timesync(Fortran): Error in timestep &
 73             &calculation for t = ",F10.5,".")') t
 74        stop 1
 75     end if
 76
 77     ! Synchronize the state
 78     ret = ygg_rpc_call(timesync, [yggarg(t), yggarg(state)], &
 79          yggarg(state))
 80     if (.not.ret) then
 81        write (*, '("timesync(Fortran): sync failed for t=",F10.5,&
 82             &".")') t
 83        stop 1
 84     end if
 85     call generic_map_get(state, "x", x)
 86     call generic_map_get(state, "y", y)
 87     write (*, '("timesync(Fortran): t = ",F5.1," ",A3,", x = ",&
 88          &SP,F5.2,", y = ",F5.2)') t, adjustl(t_units), x, y
 89
 90     ! Send output
 91     msg = copy_generic(state)
 92     call generic_map_set(msg, "time", t, t_units)
 93     ret = ygg_send_var(out, yggarg(msg))
 94     if (.not.ret) then
 95        write (*, '("timesync(Fortran): Failed to send output for &
 96             &t=",F10.5,".")') t
 97        stop 1
 98     end if
 99     call free_generic(msg)
100
101  end do
102
103  write (*, '("Goodbye from Fortran timesync")')
104  call free_generic(state)
105
106end program main
107
108
109function timestep_calc(t, t_units, state) result (ret)
110  use fygg
111  implicit none
112  real(kind=8) :: t
113  character(len=*) :: t_units
114  type(ygggeneric) :: state
115  logical :: ret
116  real(kind=8) :: x_period = 10.0  ! Days
117  real(kind=8) :: y_period = 10.0  ! Days
118  real(kind=8) :: x, y
119  ret = .true.
120  if (t_units.eq."day") then
121     ! No conversion necessary
122  else if (t_units.eq."hr") then
123     x_period = x_period * 24.0
124     y_period = y_period * 24.0
125  else
126     write (*, '("timestep_calc: Unsupported unit ''",A,"''")') t_units
127     ret = .false.
128  end if
129  if (ret) then
130     x = sin(2.0 * PI_8 * t / x_period)
131     y = cos(2.0 * PI_8 * t / y_period)
132     call generic_map_set(state, "x", x)
133     call generic_map_set(state, "y", y)
134  end if
135end function timestep_calc

Model YAML:

 1---
 2
 3models:
 4  - name: modelA
 5    language: fortran
 6    args:
 7      - ./src/timesync.f90
 8      - 7  # Pass the timestep in hours
 9      - hr
10    timesync: True
11    outputs:
12      name: output
13      default_file:
14        name: modelA_output.txt
15        in_temp: True
16        filetype: table
17  - name: modelB
18    language: fortran
19    args:
20      - ./src/timesync.f90
21      - 1  # Pass the timestep in days
22      - day
23    timesync: True
24    outputs:
25      name: output
26      default_file:
27        name: modelB_output.txt
28        in_temp: True
29        filetype: table

Julia Version

Model Code:

 1using Yggdrasil
 2using Unitful
 3using Printf
 4
 5function timestep_calc(t::Unitful.Quantity)
 6  state = Dict("x"=>sin(2.0 * t / Unitful.Quantity(10.0, u"d")),
 7               "y"=>cos(2.0 * t / Unitful.Quantity(5.0, u"d")))
 8  return state
 9end
10
11function main(t_step::Float64, t_units::String)
12
13  @printf("Hello from Julia timesync: timestep = %f %s\n", t_step, t_units)
14  t_step = Unitful.Quantity(t_step, Unitful.uparse(t_units))
15  t_start = Unitful.Quantity(0.0, Unitful.uparse(t_units))
16  t_end = Unitful.Quantity(1.0, u"d")
17  state = timestep_calc(t_start)
18
19  # Set up connections matching yaml
20  # Timestep synchronization connection will default to 'timesync'
21  timesync = Yggdrasil.YggInterface("YggTimesync", "timesync")
22  out = Yggdrasil.YggInterface("YggOutput", "output")
23
24  # Initialize state and synchronize with other models
25  t = t_start
26  ret, state = timesync.call(t, state)
27  if (!ret)
28    error("timesync(Julia): Initial sync failed.")
29  end
30  @printf("timesync(Julia): t = %s, x = %s, y = %s\n", t, state["x"], state["y"])
31
32  # Send initial state to output
33  msg = state
34  msg["time"] = t
35  flag = out.send(msg)
36  if (!flag)
37    error(@sprintf("timesync(Julia): Failed to send initial output for t=%s\n", t))
38  end
39
40  # Iterate until end
41  while (t < t_end)
42
43    # Perform calculations to update the state
44    t = t + t_step
45    state = timestep_calc(t)
46
47    # Synchronize the state
48    ret, state = timesync.call(t, state)
49    if (!ret)
50      error(@sprintf("timesync(Julia): sync for t=%s failed.", t))
51    end
52    @printf("timesync(Julia): t = %s, x = %s, y = %s\n", t, state["x"], state["y"])
53
54    # Send output
55    msg = state
56    msg["time"] = t
57    flag = out.send(msg)
58    if (!flag)
59      error(@sprintf("timesync(Julia): Failed to send output for t=%s.", t))
60    end
61
62  end
63
64  println("Goodbye from Julia timesync")
65
66end
67
68main(parse(Float64, ARGS[1]), ARGS[2])

Model YAML:

 1---
 2
 3models:
 4  - name: modelA
 5    language: julia
 6    args:
 7      - ./src/timesync.jl
 8      - 7  # Pass the timestep in hours
 9      - hr
10    timesync: True
11    outputs:
12      name: output
13      default_file:
14        name: modelA_output.txt
15        in_temp: True
16        filetype: table
17  - name: modelB
18    language: julia
19    args:
20      - ./src/timesync.jl
21      - 1  # Pass the timestep in days
22      - d
23    timesync: True
24    outputs:
25      name: output
26      default_file:
27        name: modelB_output.txt
28        in_temp: True
29        filetype: table

Matlab Version

Model Code:

 1function timesync(t_step, t_units)
 2
 3  t_step = str2num(t_step);
 4  fprintf('Hello from Matlab timesync: timestep = %f %s\n', t_step, t_units);
 5  t_step = t_step * str2symunit(t_units);
 6  t_start = 0.0000000000000001 * str2symunit(t_units);
 7  t_end = 5.0 * str2symunit('day');
 8  state = containers.Map('UniformValues', false, 'ValueType', 'any');
 9  state('x') = sin(2.0 * pi * t_start / (10.0 * str2symunit('day')));
10  state('y') = cos(2.0 * pi * t_start / (5.0 * str2symunit('day')));
11
12  % Set up connections matching yaml
13  % Timestep synchonization connection will default to 'timesync'
14  timesync = YggInterface('YggTimesync', 'timesync');
15  out = YggInterface('YggOutput', 'output');
16
17  % Initialize state and synchronize with other models
18  t = t_start;
19  [ret, state] = timesync.call(t, state);
20  if (~ret);
21    error('timesync(Matlab): Initial sync failed.');
22  end;
23  [t_data, t_unit] = separateUnits(t);
24  fprintf('timesync(Matlab): t = %5.1f %-1s, x = %+ 5.2f, y = %+ 5.2f\n', ...
25	  t_data, symunit2str(t_unit), state('x'), state('y'));
26
27  % Send initial state to output
28  msg_keys = keys(state);
29  msg_keys{length(msg_keys) + 1} = 'time';
30  msg_vals = values(state);
31  msg_vals{length(msg_vals) + 1} = t;
32  msg = containers.Map(msg_keys, msg_vals, 'UniformValues', false);
33  flag = out.send(msg);
34
35  % Iterate until end
36  while (simplify(t/t_end) < 1)
37
38    % Perform calculations to update the state
39    t = t + t_step;
40    state = containers.Map('UniformValues', false, 'ValueType', 'any');
41    state('x') = sin(2.0 * pi * t / (10.0 * str2symunit('day')));
42    state('y') = cos(2.0 * pi * t / (5.0 * str2symunit('day')));
43
44    % Synchronize the state
45    [ret, state] = timesync.call(t, state);
46    if (~ret);
47      error(sprintf('timesync(Matlab): sync for t=%f failed.\n', t));
48    end;
49    [t_data, t_unit] = separateUnits(t);
50    fprintf('timesync(Matlab): t = %5.1f %-1s, x = %+ 5.2f, y = %+ 5.2f\n', ...
51  	    t_data, symunit2str(t_unit), state('x'), state('y'));
52
53    % Send output
54    msg_keys = keys(state);
55    msg_keys{length(msg_keys) + 1} = 'time';
56    msg_vals = values(state);
57    msg_vals{length(msg_vals) + 1} = t;
58    msg = containers.Map(msg_keys, msg_vals, 'UniformValues', false);
59    flag = out.send(msg);
60    if (~flag);
61      error(sprintf('timesync(Matlab): Failed to send output for t=%s.\n', t));
62    end;
63  end;
64
65  disp('Goodbye from Matlab timesync');
66  
67end

Model YAML:

 1---
 2
 3models:
 4  - name: modelA
 5    language: matlab
 6    args:
 7      - ./src/timesync.m
 8      - 7  # Pass the timestep in hours
 9      - hr
10    timesync: True
11    use_symunit: True
12    outputs:
13      name: output
14      default_file:
15        name: modelA_output.txt
16        in_temp: True
17        filetype: table
18  - name: modelB
19    language: matlab
20    args:
21      - ./src/timesync.m
22      - 1  # Pass the timestep in days
23      - day
24    timesync: True
25    use_symunit: True
26    outputs:
27      name: output
28      default_file:
29        name: modelB_output.txt
30        in_temp: True
31        filetype: table

Python Version

Model Code:

 1import sys
 2import numpy as np
 3from yggdrasil import units
 4from yggdrasil.interface.YggInterface import (
 5    YggTimesync, YggOutput)
 6
 7
 8def timestep_calc(t):
 9    r"""Updates the state based on the time where x is a sine wave
10    with period of 10 days and y is a cosine wave with a period of 5 days.
11
12    Args:
13        t (float): Current time.
14
15    Returns:
16        dict: Map of state parameters.
17
18    """
19    state = {
20        'x': np.sin(2.0 * np.pi * t / units.add_units(10, 'day')),
21        'y': np.cos(2.0 * np.pi * t / units.add_units(5, 'day'))}
22    return state
23
24
25def main(t_step, t_units):
26    r"""Function to execute integration.
27
28    Args:
29        t_step (float): The time step that should be used.
30        t_units (str): Units of the time step.
31
32    """
33    print('Hello from Python timesync: timestep = %s %s' % (t_step, t_units))
34    t_step = units.add_units(t_step, t_units)
35    t_start = units.add_units(0.0, t_units)
36    t_end = units.add_units(5.0, 'day')
37    state = timestep_calc(t_start)
38
39    # Set up connections matching yaml
40    # Timestep synchonization connection will default to 'timesync'
41    timesync = YggTimesync('timesync')
42    out = YggOutput('output')
43
44    # Initialize state and synchronize with other models
45    t = t_start
46    ret, state = timesync.call(t, state)
47    if not ret:
48        raise RuntimeError("timesync(Python): Initial sync failed.")
49    print('timesync(Python): t = % 8s, x = %+ 5.2f, y = %+ 5.2f' % (
50        t, state['x'], state['y']))
51
52    # Send initial state to output
53    flag = out.send(dict(state, time=t))
54    if not flag:
55        raise RuntimeError("timesync(Python): Failed to send "
56                           "initial output for t=%s." % t)
57    
58    # Iterate until end
59    while t < t_end:
60
61        # Perform calculations to update the state
62        t = t + t_step
63        state = timestep_calc(t)
64
65        # Synchronize the state
66        ret, state = timesync.call(t, state)
67        if not ret:
68            raise RuntimeError("timesync(Python): sync for t=%f failed." % t)
69        print('timesync(Python): t = % 8s, x = %+ 5.2f, y = %+ 5.2f' % (
70            t, state['x'], state['y']))
71
72        # Send output
73        flag = out.send(dict(state, time=t))
74        if not flag:
75            raise RuntimeError("timesync(Python): Failed to send output for t=%s." % t)
76
77    print('Goodbye from Python timesync')
78
79
80if __name__ == '__main__':
81    # Take time step from the first argument
82    main(float(sys.argv[1]), sys.argv[2])

Model YAML:

 1---
 2
 3models:
 4  - name: modelA
 5    language: python
 6    args:
 7      - ./src/timesync.py
 8      - 7  # Pass the timestep in hours
 9      - hr
10    timesync: True
11    outputs:
12      name: output
13      default_file:
14        name: modelA_output.txt
15        in_temp: True
16        filetype: table
17  - name: modelB
18    language: python
19    args:
20      - ./src/timesync.py
21      - 1  # Pass the timestep in days
22      - day
23    timesync: True
24    outputs:
25      name: output
26      default_file:
27        name: modelB_output.txt
28        in_temp: True
29        filetype: table

R Version

Model Code:

 1library(yggdrasil)
 2
 3
 4timestep_calc <- function(t) {
 5  state = list(x=sinpi(2.0 * t / units::set_units(10.0, 'day', mode="standard")),
 6               y=cospi(2.0 * t / units::set_units(5.0, 'day', mode="standard")))
 7  return(state)
 8}
 9
10main <- function(t_step, t_units) {
11
12  fprintf('Hello from R timesync: timestep = %f %s', t_step, t_units)
13  t_step <- units::set_units(t_step, t_units, mode="standard")
14  t_start <- units::set_units(0.0, t_units, mode="standard")
15  t_end <- units::set_units(5.0, 'day', mode="standard")
16  state <- timestep_calc(t_start)
17
18  # Set up connections matching yaml
19  # Timestep synchronization connection will default to 'timesync'
20  timesync <- YggInterface('YggTimesync', 'timesync')
21  out <- YggInterface('YggOutput', 'output')
22
23  # Initialize state and synchronize with other models
24  t <- t_start
25  c(ret, state) %<-% timesync$call(t, state)
26  if (!ret) {
27    stop('timesync(R): Initial sync failed.')
28  }
29  fprintf('timesync(R): t = %5.1f %-1s, x = %+ 5.2f, y = %+ 5.2f\n',
30          units::drop_units(t), units::deparse_unit(t),
31	  state[['x']], state[['y']])
32
33  # Send initial state to output
34  msg = state
35  msg[['time']] = t
36  flag <- out$send(msg)
37  if (!flag) {
38    stop(sprintf('timesync(R): Failed to send initial output for t=%s', t))
39  }
40
41  # Iterate until end
42  while (t < t_end) {
43        
44    # Perform calculations to update the state
45    t <- t + t_step
46    state <- timestep_calc(t)
47
48    # Synchronize the state
49    c(ret, state) %<-% timesync$call(t, state)
50    if (!ret) {
51      stop(sprintf('timesync(R): sync for t=%f failed.', t))
52    }
53    fprintf('timesync(R): t = %5.1f %-1s, x = %+ 5.2f, y = %+ 5.2f\n',
54            units::drop_units(t), units::deparse_unit(t),
55  	    state[['x']], state[['y']])
56
57    # Send output
58    msg = state
59    msg[['time']] = t
60    flag <- out$send(msg)
61    if (!flag) {
62      stop(sprintf('timesync(R): Failed to send output for t=%s.', t))
63    }
64  }
65
66  print('Goodbye from R timesync')
67  
68}
69
70
71args = commandArgs(trailingOnly=TRUE)
72main(as.double(args[[1]]), args[[2]])

Model YAML:

 1---
 2
 3models:
 4  - name: modelA
 5    language: R
 6    args:
 7      - ./src/timesync.R
 8      - 7  # Pass the timestep in hours
 9      - hr
10    timesync: True
11    outputs:
12      name: output
13      default_file:
14        name: modelA_output.txt
15        in_temp: True
16        filetype: table
17  - name: modelB
18    language: R
19    args:
20      - ./src/timesync.R
21      - 1  # Pass the timestep in days
22      - day
23    timesync: True
24    outputs:
25      name: output
26      default_file:
27        name: modelB_output.txt
28        in_temp: True
29        filetype: table