"display condition"/Relevance not working for calculation

Dear Dev,

On the commcare APP the calculation are done without taking the “display condition” into account. this is really annoying for our project where we have 100+ calculation.

I am quite sure it is the case because the “same” questionnaire on ODK collect doesn’t freeze durign the update of some fields (the calculation slow the app later, when the calculation are supposed to happen based on relevance fields )

Br

Hi Patrick,

This is intentional behavior as prescribed in the XForms specification. The relevant= and calculate= properties are part of the same directed graph of calculation, and we sort triggered updates topographically to ensure a single-pass of the graph on any input event change. Deferring evaluation would require the graph to perform multiple passes which would cause drastic performance problems on forms that use nested query scopes. The underlying ODK engine is able to work around this because it is based on an older fork of the javarosa engine that has more limited support for the XPath query constructs and scopes that let CommCare manage longitudinal data and have dynamic models.

You can defer calculation of expressions in CommCare explicitly using any short-circuiting operator ( if(), and, or) in the expression evaluation path.

IE:

if( var1 = '' or var2 = '' or var3 = '' or var4 = '', '', really_expensive_calculation())

will only perform the latter part of the calculation if all of the variables are defined.

-Clayton

Thank you,
"
I did implement the “if” approach, how I did it:
I ask the weight and age then I show the entered values and ask the user to confirm (select question)

I put the confirmation answer as a condition for age calculation (which is used in many calculations) like if(conf=1, ageEntered,0)

–> no improvement, it can take few seconds to enter a 2 digits age …

There is also a weird behavior of the calculation that might be related:it seems (an the app) that if a calculation depends on another question then it gets evaluated even if the group relevance is false (only way I explain the slowness) but another question in the same group that doesn’t use a question external to this group won’t be evaluated (I have to use coalesce function for those)

best regards

Hi Patrick,

I’ll provide some clarifications to close things out / settle any lingering questions.

You are also correct that using the “if()” approach won’t help performance issues which are caused by very broad or very deep question dependencies. It’s primarily helpful when you have a single (or small number) expression which consumes a significant amount of time (such as a lookup into the casedb database or a large lookup table).

In the pattern I mentioned above, the only effect of the if() function is that the last function call isn’t triggered, but the calculation itself is always triggered when var1, var2, var3, etc are changed. This is because the engine determines the graph of calculations to update before it identifies what the new values themselves are. This makes the engine performance deterministic and overall more efficient, but does make it difficult to defer “no-op” calculation updates where a value didn’t actually change.

There are a few ways to work around this challenge depending on the size of the form, but the most reliable one is to split up very long forms into multiple forms and to store the values from earlier logic into cases which can be loaded back as “default value” calculations later, rather than having a single form needing to keep the complex web of updates up to date consistently.

It can also help to minimize the “Depth” of dependent calculations. (IE: “A effects B which effect C and D, which …”). One way to accomplish that is to remove most hidden value calculations from groups, where they are affected by relevant conditions from the parents, into a separate section of the form where they can be updated in isolation.

-Clayton

Thanks for your reply but we cannot split the form unless there a way to move from the registration form case to a follow up form seamlessly because a “single form” is critical for user experience

I still think it will be good if commcare would stop propagating the calculation when the result isn’t change or if the calculation’s (or its parent groups’) relevance condition is not met.

br