Skip to content

Conversation

@mo-alistairp
Copy link
Collaborator

Adding code generation for ScalarArrays (towards #1312 ). The metadata support was added in #2173.

@mo-alistairp mo-alistairp self-assigned this Aug 19, 2025
@mo-alistairp mo-alistairp added in progress LFRic Issue relates to the LFRic domain labels Aug 19, 2025
def scalar_array(self, scalar_arr_arg, var_accesses=None):
'''
Override the default implementation as there's no need to specify
ScalarArrays for an OpenACC data region.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This isn't true I'm afraid - they will need to be added to a data region. However, you could leave this as a TODO as I'm not sure we're ever going to need data regions.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for that - it's currently a very rough draft so some of the comments are currently just borrowed from other functions. But, I will definitely note that down!

@codecov
Copy link

codecov bot commented Aug 19, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 99.95%. Comparing base (e9d4423) to head (f187466).

❌ Your project check has failed because you have indirect coverage changes. Learn more about Unexpected Coverage Changes and reasons for indirect coverage changes.

Additional details and impacted files
@@            Coverage Diff             @@
##           master    #3101      +/-   ##
==========================================
- Coverage   99.95%   99.95%   -0.01%     
==========================================
  Files         378      379       +1     
  Lines       53723    53822      +99     
==========================================
+ Hits        53701    53799      +98     
- Misses         22       23       +1     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@mo-alistairp
Copy link
Collaborator Author

This still isn't working as intended, but is getting closer to correct. As an example, the code gen is now adding the scalar arrays to the generated code, alongside the arrays containing their dimensions. However, it is not adding these dimensions to the generated code (e.g., no dimensions(...) mention). It is also assigning the field as intent(in) right now, which it shouldn't do either.

Furthermore, the stub_gen test is failing because we are currently adding the dimensions array to the psyir layer as an ArgumentInteraface which isn't there as an argument at the call. Need to find a way around this. I'm wondering if we need a dimensions array at all but I'll have to investigate that further.

@mo-alistairp
Copy link
Collaborator Author

mo-alistairp commented Dec 19, 2025

I'm having a little trouble getting testkern_scalar_array_mod via lfric_scalar_codegen_test to compile. Currently, it's erroring with
Error: Symbol 'gh_scalar_array' at (1) has no IMPLICIT type; did you mean 'gh_scalar'?

Still trying to find what needs adding to fix this.

@mo-alistairp
Copy link
Collaborator Author

mo-alistairp commented Jan 16, 2026

This is now working and passing the tests with and without compilation. I'm not sure why my commits have started coming up as unverified, but I'll try and fix that.

I'll warn you that I've had to do a slightly strange fix to correct the ordering of the declarations in code generation. As mentioned on Monday, there isn't a way of changing the order of declarations - they appear in the order that they are added to the symbol table. Since the ScalarArray is an argument it was always being added before the dimensions array, and this was causing compile time errors as the dimensions array is being used in the ScalarArray declaration. My fix for this is simply finding the ScalarArray in the symbol table and replacing it with itself, so that it is being added after the dimensions array. Hopefully you're happy with this

This should now be ready for review again

@mo-alistairp
Copy link
Collaborator Author

mo-alistairp commented Jan 16, 2026

I'm not sure why CodeCov has only just decided that this was a problem. I've looked at the line it's complaining about (line 773 in arg_ordering.py) and I don't see an easy way of avoiding this problem without splitting scalar_args out of the scalar function. The test for this is checking whether the argument isn't is_scalar or is_scalar_array, which I can't think of a way of doing independently without splitting the function into two. I don't think we want to do this from a design perspective.

I still think that this is ready for review, and would be interested if you have any thoughts about this

Copy link
Member

@arporter arporter left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking good @mo-alistairp - well done!
There's a bit of tidying-up still to do and I'm asking that you make the test case a bit more involved. I suspect what you have is vulnerable to a name clash so you'll see I've asked you to switch to using a tag for the new variables.
I'll fire off the integration tests in the meantime.

:py:class:`psyclone.core.VariablesAccessMap`]
'''
# TODO: Add implementation of OpenACC data region for ScalarArrays
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please remove the TODO as otherwise our rule is that you need an associated Issue and I don't think we want another Issue :-)

:py:class:`psyclone.core.VariablesAccessMap`]
'''
# TODO: Add implementation of OpenACC data region for ScalarArrays
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, please document the NotImplementedError as a ":raises ...." in the docstring.

Handles the declarations of ScalarArray kernel arguments appearing in
either an Invoke or a Kernel stub.
:param node: the Invoke or Kernel stub for which to manage the \
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please put back the description of the node argument.

super().__init__(node)

# Initialise dictionaries of 'real', 'integer' and 'logical'
# ScalarArray arguments by data type and intent
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, please update the comment.

if self._logical_scalar_arrays[intent]:
for arg in self._logical_scalar_arrays[intent]:
for arg in self._scalar_array_args[intent]:
if arg.intent in FORTRAN_INTENT_NAMES:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you need this if? If so, please add a comment.

integer(kind=i_def) :: a_scalar

call invoke( &
testkern_scalar_array_type(afield,real_array,logical_array,integer_array,a_scalar) &
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably worth making this more complicated by including a second kernel call (to one of the existing test kernels) in the invoke. If you could make one of the variable names such that you would get a clash with the dims_real_field name that PSyclone generates then that would be great. (e.g. you could re-name "a_scalar" to "dims_real_field")

if scal_multi_type:
raise GenerationError(
f"ScalarArray argument(s) {scal_multi_type} in Invoke "
f"'{self._invoke.name}' have different metadata for data "
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

perhaps replace everything after and including "have" with "is/are passed to more than one kernel and the kernel metadata for the corresponding arguments specifies different intrinsic types."? (I really struggled to understand this message at first.)

for intent in FORTRAN_INTENT_NAMES:
for arg in self._scalar_array_args[intent]:
# Distinguish whether they are ScalarArrays
if (arg.descriptor.data_type not in
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it would be simpler to put this check at L150 - i.e. before we add arg into the _scalar_array_arg dictionary. That would save us having to loop through again to check what we've just added.

f"{const.VALID_SCALAR_DATA_TYPES}.")

# Create declarations
self._create_declarations()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Regarding my comment on the special handling for kernel stubs in _create_declarations, I think probably you just get rid of this call and inline the relevant part of _create_declarations here.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @arporter, can I just check what you want here. If I inline the _create_declarations function and remove it, it will need to be inlined into both invoke_declarations and stub_declarations. This will create some code duplication - are you happy with this cost to remove _create_declarations?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi Alistair, that's not quite what I meant. You can keep _create_declarations but move the stub-specific code out of it. There will be a little bit of duplication but I don't think it's much.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok sure, thanks for the clarification 😄

create_arg_list.scalar(arg)
const = LFRicConstants()
assert (f"Expected argument type to be one of {const.VALID_SCALAR_NAMES} "
assert (f"Expected argument type to be one of "
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can probably extend this test to get coverage of that missed line. You'll neeed to create a create_arg_list = KernCallArgList(kernel) and then call scalar on it with an argument that isn't a scalar. If this works, please update the name and docstring of the test.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement LFRic Issue relates to the LFRic domain reviewed with actions

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants