The source code of pyOASIS is in the directory pyoasis/src. Complete documentation is available in pyoasis/pyoasis.pdf. The pyoasis interface ultimately call the Fortran version. This is done by wrapping the Fortran in ISO-C bindings (see lib/cbindings/fortran_isoc), then wrapping the Fortran ISO-C bindings in C (see lib/cbindings/c), then wrapping the C bindings in python (see pyoasis/src). This method provides both the C and python bindings. Examples on how to use pyOASIS are provided in pyoasis/examples. To run all tests including python, C, and Fortran examples, use make test. The python wrapper functions are briefly described next.
In pyOASIS, components are instances of the Component class. To initialise a component, its name has to be supplied. It is also possible to provide an optional coupling_flag argument which defaults to “True”, which means the component is coupled through OASIS3_MCT.
OASIS3_MCT couples models which communicate using MPI. If the global communicator at the start of the run is different from the default MPI_COMM_WORLD communicator, the global communicator has to be passed to the Component class through the third optional argument. By default, the Component class will set up MPI internally and provides methods to get access to information such as rank and number of processes in the local communicator gathering only the component processes.
____________________________________________________________ import pyoasis [...] comm = my_global_comm component_name = "component" coupling_flag = True comp = pyoasis.Component(component_name, coupling_flag, comm) print("Hello world from process " + str(comp.localcomm.rank) + " of " + str(comp.localcomm.size)) ____________________________________________________________
To create a coupling communicator for a subset of processes, one can use the method create_couplcomm, with a flag being True for all these processes; see pyoasis/examples/4-orange/python for a practical example.
If such a communicator already exists in the code, it should simply be provided to OASIS3_MCT with the method set_couplcomm; as in pyoasis/examples/6-apple_and_orange/python.
To set up an MPI intra communicator or inter communicator between the local component and
another component, one can use the methods get_intracomm or get_intercomm;
as in pyoasis/examples/3-box/python .
To set up an MPI intra-communicator among some of the coupled components, listed in the comp_list list, one can use the method get_multi_intracomm, as in 9-python_fortran_C-multi_intracomm.
Also, the current OASIS3-MCT internal debug level ($NLOGPRT value in the namcouple), can be retrieved as a property of a component, namely debug_level, and can be changed by directly modifying this property, as in pyoasis/examples/7-multiple-puts/python.
The data can be partitioned in various ways. These correspond to the SerialPartition, ApplePartition, BoxPartition, OrangePartition and PointsPartition classes which are inherited from the Partition abstract class. For details on the different ways to describe the partitions, see OASIS3_MCT User Guide, section 2.2.3 and examples 1_serial, 2_apple, 3_box, 4_orange, 5_points in pyoasis/examples.
The simplest situation is the serial partitioning where all the data is held by a single process and only the number of points has to be specified (see example 1_serial)
In the case of the Apple partitioning, each process contains a segment of a linear domain. To initialise such a partitioning, an offset has to be supplied for each rank as well as the number of data points that will be stored locally (see example 2_apple).
When we use the Box partitioning, a two-dimensional domain is split into several rectangles. The global offset, local extents in the x and y directions and the global extent in the x direction have to be supplied to the constructor. The global offset is the index of the corner of the local rectangle (see example in 3_box) .
The Orange partitioning consists of several segments of a linear domain (see an example with only one segment per process in 4_orange.)
The last type of partitioning is Points, where we have to specify, in a list, the global indices of the points stored by the process (see example in 5_points).
The grid data files, containing the definition of the grids onto which the coupling data is defined, can be created by the user before the run or can be written directly at run time by the components, either by one component process to write the whole grid or by each process holding a part of a grid. Details about the grid definition can be found in section 2.2.4 of OASIS3_MCT User Guide. A full example of writing a grid in sequential and parallel models can be found in examples/10_grid .
To initialise a grid and write the grid longitudes and latitudes, one has to create an instance of the Grid class. Then to write the grid cell corner longitudes and latitudes, areas, mask, cell valid fraction, angle, the set_corners, set_area, set_mask, set_frac, and set_angle methods can be used respectively.
The coupling data is handled by the class Var. Its constructor requires its symbolic name, as it appears in the namcouple file, the partition and a flag indicating whether the data is incoming or outgoing. The latter is an enumerated type and can have the values pyoasis.OasisParameters.OASIS_OUT or pyoasis.OasisParameters.OASIS_IN.
The property is_active can be tested to check if the variable is activated in the namcouple configuring file (see example 3-box/python).
The coupling period(s) of the data, as defined in the namcouple, can be accessed with the property cpl_freqs and the number of coupling exchanges in which the data is involved by len(cpl_freqs) (see example 7-multiple-puts/python).
The property put_inquire of the variable tells what would happen to the corresponding data at that date below the corresponding send action. This maybe useful if, for example, the calculation of a coupling field is costly and if one wants to compute it only when it is really sent out. The different possible return codes are listed in section 2.2.9 of OASIS3_MCT User Guide.
Then the definition of the component must be ended by calling the enddef() method. This must be done only once the partitioning and the variable data have been initalised.
pyOASIS expects data to be provided as a pyoasis.asarray object:
____________________________________________________________ field = pyoasis.asarray(range(n_points)) ____________________________________________________________
This is a numpy array but ordered in the Fortran way. In C, multidimensional arrays store data in row_major order where contiguous elements are accessed by incrementing the rightmost index while varying the other indices will correspond to increasing strides in memory as we use indices further towards the left. By default, numpy arrays use that ordering as well. Fortran, on the other hand, uses column_major order. In that case, contiguous elements are accessed by incrementing the leftmost index. pyoasis.asarray objects use the same ordering as Fortran. As a consequence, it is not necessary to transform data in order to use it in the OASIS3_MCT Fortran library.
The sending and receiving actions may be called by the component at each timestep. The date argument is automatically analysed and actions are actually performed only if date corresponds to a time for which it should be activated, given the period indicated by the user in the namcouple. See OASIS3_MCT User Guide section 2.2.7 for details.
The data is sent with the put function.
____________________________________________________________ date = int(0) variable.put(date, field) ____________________________________________________________
Conversely, it is received with the get function, which fills the pyoasis.asarray object.
____________________________________________________________ variable.get(date, field) ____________________________________________________________
Finally, the coupling is terminated with the destruction of the component:
____________________________________________________________ del comp ____________________________________________________________
When an error occurs in OASIS3_MCT, the code coupler returns an error code and an OasisException is raised. In practice, OASIS3_MCT will internally handle the error, write an error message in its debug log files and to the screen, and abort before the exception is raised. It may also happen that the code aborts before the error message appears on the screen.
When an error is caught by the pyOASIS wrapper, such as an incorrect parameter or a wrong argument type, a PyOasisException is raised.
In the following example, where we attempt to initialise a component, a PyOasisException will be raised as the user supplies an empty name :
____________________________________________________________ try: comp = pyoasis.Component("") except (pyoasis.PyOasisException) as exception: pyoasis.pyoasis_abort(exception) ____________________________________________________________
The function pyoasis.pyoasis_abort takes an exception as argument. It stops the execution of all the processes after having displayed an error message and written information in the log files about the error and the context in which it took place.
Another function is available, pyoasis.oasis_abort, for the cases where a voluntary abort is needed in the code where or not an exception has been raised. Its interface mimics the corresponding OASIS3_MCT functio oasis_abort.