33# The file LICENCE, distributed with this code, contains details of the terms
44# under which the code may be used.
55##############################################################################
6-
76# Summary
87# =======
98#
4544# * fulldom_size_name: name of variable holding full-domain size
4645# * asad_call_name: name of the top-level ASAD solver routine
4746#
47+ # OpenMP can also be added to the chunked loop by setting the environment
48+ # variable UKCA_FULL_CHUNK_OMP to True. By default it will be turned on
49+ # provided the chunk size is not equal to domain size, i.e. loop of length 1
50+ #
51+ # OpenMP parallelism is then added to the chunking loop using an omp parallel do
52+ # directive to allow for top level parallelism on the ASAD solver. Importantly
53+ # a call to ukca_reallocate_asad_arrays which reallocates the THREADPRIVATE
54+ # arrays. This is done within the parallel region to account for the potential
55+ # for chunk_size to be different between iterations, i.e. smaller last
56+ # iteration. Dynamic scheduling has been selected based upon the number of
57+ # solver iterations varying between chunks depending on the complexity of the
58+ # chemistry.
59+ #
4860# Example
4961# =======
5062#
98110# =======
99111
100112import os
101-
102- from psyclone .version import (__MAJOR__ , __MINOR__ , __MICRO__ )
113+ import logging
103114from psyclone .psyir .nodes import (
104- ArrayReference , Assignment , BinaryOperation , Call , IntrinsicCall ,
105- Literal , Loop , Routine , Reference , Schedule )
115+ ArrayReference ,
116+ Assignment ,
117+ BinaryOperation ,
118+ Call ,
119+ IfBlock ,
120+ IntrinsicCall ,
121+ Literal ,
122+ Loop ,
123+ Reference ,
124+ Routine ,
125+ Schedule ,
126+ UnaryOperation ,
127+ )
106128from psyclone .psyir .symbols import (
107- INTEGER_TYPE , REAL_TYPE , CHARACTER_TYPE , Symbol , DataSymbol , ArrayType ,
108- RoutineSymbol )
129+ CHARACTER_TYPE ,
130+ INTEGER_TYPE ,
131+ REAL_TYPE ,
132+ ArrayType ,
133+ ContainerSymbol ,
134+ DataSymbol ,
135+ ImportInterface ,
136+ RoutineSymbol ,
137+ Symbol ,
138+ )
109139from psyclone .psyir .transformations .reference2arrayrange_trans import (
110- Reference2ArrayRangeTrans )
140+ Reference2ArrayRangeTrans ,
141+ )
142+ from psyclone .transformations import OMPParallelLoopTrans , TransformationError
143+ from psyclone .version import __MAJOR__ , __MICRO__ , __MINOR__
144+
145+ # Conditonal imports
146+ # ==================
111147
112148psy_version = (__MAJOR__ , __MINOR__ , __MICRO__ )
113149
128164# Name of the routine in which to apply the transformation
129165routine_name = "ukca_chemistry_ctl_full"
130166
131- # Transformation
167+ # Source and name of the reallocation routine
168+ asad_realloc_routine = ("ukca_chemistry_ctl_col_mod" ,
169+ "ukca_reallocate_asad_arrays" )
170+
171+
172+ # Utility
132173# ==============
174+ def get_bool_env (var_name : str , default : bool = False ) -> bool :
175+ val = os .getenv (var_name )
176+ if val is None :
177+ return default
178+ return val .strip ().lower () in ('1' , 'true' , 't' , 'yes' , 'y' , 'on' )
179+
133180
181+ # Transformation
182+ # ==============
134183
135184def trans (psyir ):
136185 desired_chunk_size = os .getenv ("UKCA_FULL_CHUNK_SIZE" )
@@ -149,6 +198,12 @@ def trans(psyir):
149198 message_text = ("UKCA full-domain chunking enabled with " +
150199 "a chunk size of " + desired_chunk_size )
151200
201+ use_omp = get_bool_env ("UKCA_FULL_CHUNK_OMP" , True )
202+ if desired_chunk_size is None and use_omp :
203+ logging .WARNING (
204+ "Turning off omp as chunk size is set to full domain size" )
205+ use_omp = False
206+
152207 # Locate correct routine within which to apply the transformation
153208 for routine in psyir .walk (Routine ):
154209 if routine .name != routine_name :
@@ -348,3 +403,66 @@ def trans(psyir):
348403 # -------------------------
349404
350405 loop .parent .addchild (assign_desired_chunk_size , index = loop .position )
406+
407+ if use_omp :
408+ # Add import for ASAD reallocation routine
409+ # ----------------------------------------
410+
411+ asad_realloc_mod_sym = ContainerSymbol (asad_realloc_routine [0 ])
412+ routine .symbol_table .add (asad_realloc_mod_sym )
413+ asad_realloc_routine_sym = Symbol (asad_realloc_routine [1 ])
414+ asad_realloc_routine_sym .interface = ImportInterface (
415+ asad_realloc_mod_sym )
416+ routine .symbol_table .add (asad_realloc_routine_sym )
417+
418+ # Add Reallocation Call to within Loop
419+ # ------------------------------------
420+ # Create reallocation call
421+ realloc_call = Call ()
422+ realloc_call .addchild (Reference (RoutineSymbol (
423+ asad_realloc_routine [1 ])))
424+ realloc_call .addchild (Reference (chunk_size_var ))
425+
426+ # Create conditional reallocation call
427+ realloc_block = IfBlock .create (
428+ BinaryOperation .create (
429+ BinaryOperation .Operator .OR ,
430+ UnaryOperation .create (
431+ UnaryOperation .Operator .NOT ,
432+ IntrinsicCall .create (
433+ IntrinsicCall .Intrinsic .ALLOCATED ,
434+ [Reference (
435+ Symbol (next (iter (asad_vars .keys ()))))])),
436+ BinaryOperation .create (
437+ BinaryOperation .Operator .NE ,
438+ Reference (chunk_size_var ),
439+ IntrinsicCall .create (
440+ IntrinsicCall .Intrinsic .SIZE ,
441+ [Reference (Symbol (next (iter (asad_vars .keys ())))),
442+ ("dim" , Literal ("1" , INTEGER_TYPE ))]))),
443+ [realloc_call ])
444+
445+ loop .loop_body .addchild (realloc_block , index = 2 )
446+
447+ # Added OMP transformation on desired loop
448+ # ----------------------------------------
449+
450+ omp_trans = OMPParallelLoopTrans (omp_schedule = "static" )
451+ opts = {
452+ # some non-PURE subroutines called within this loop
453+ "force" : True ,
454+ # several WRITE statements used for diagnostics
455+ "node-type-check" : False ,
456+ }
457+
458+ try :
459+ omp_trans .apply (
460+ loop , options = opts ,
461+ )
462+
463+ except TransformationError as err :
464+ err_msg = ("ukca_chemistry_ctl_full_mod.py: Error: "
465+ "could not apply OMP transformation "
466+ f"to loop: { err .message_text } " )
467+
468+ raise TransformationError (err_msg ) from err
0 commit comments