aboria / Aboria

Enables computations over a set of particles in N-dimensional space
https://aboria.github.io/Aboria
Other
105 stars 30 forks source link

Condition as an Argument for Symbolic Expressions #34

Closed JabirSS closed 6 years ago

JabirSS commented 6 years ago

Hello @martinjrobins ,

Thank you for the recent updates, that was really helpful!

I noticed that I can't do the following:

p[a] = sum(b, norm(dx)<2, 1.0/pow(norm(dx),2))

Namely, have a boolean condition as an argument in uni/bivariate expressions in Aboria, despite the fact that it's stated in the documentation. My compiler throws many errors.

An if_else() operation would do the job in most circumstances, especially when the right hand side is added to left hand side, but unfortunately I'm not sure how to go about doing that when it's assignment, like the case above.

I'd appreciate your thoughts on this!

Many thanks,

Jabir

martinjrobins commented 6 years ago

Hi @JabirSS. Thanks for pointing that out, I hadn't updated the documentation for the symbolic expressions in a while, and it is out of date. The accumulations only take 2 args now (i.e. they don't support the boolean arg), and instead you can choose between Accumulate and AccumulateWithinDistance. I'll fix that in the docs.

What is the problem with the assignment expression that you give? It looks like you are just summing up contributions from particles within a certain distance, which is fine. If the particle a does not have any neighbours then the sum is zero, or do you want a different behaviour?

JabirSS commented 6 years ago

Thanks for your swift reply, as always!

Actually the code snippet was meant as an example, but what I'm trying to do looks like:

x[a]=sum(b, condition , somefunction(a,b));

where my condition is trying to prevent particles with a specific type in my code from interacting with each other. i.e.condition = !(type[a]==1 && type[b]==1)

and sum is an AccumulateWithinDistance accumulator.

My problem is that if the if_else() condition needs to know what to do if the condition returns false, but I would like to keep x[a] unchanged if the condition fails.

It might not make sense (from an Aboria syntax point of view), but the following might help clarify what I'm trying to do. I also tried doing this:

x[a] = if_else( condition, sum(b,someFunction(a,b)), x[a])

The code above would not compile. Is there another way to do this with the symbolic API or is the lower API the way to go? :)

martinjrobins commented 6 years ago

Well, its a sum so if you use 0 as the else condition then it won't have any impact on your sum:

x[a]=sum(b, if_else(condition, somefunction(a,b), 0));

Will that work for you?

JabirSS commented 6 years ago

Unfortunately not, since the summation will still be evaluated over particles that I wish to avoid. This will be problematic in areas of the domain where only particles of the problematic type exist, consequently the summation will be evaluated and the value of the summation will be zero, which is wrong.

I managed to do this with the lower level API successfully. However, having the old style of accumulators (with the condition as a parameter) would have actually been quite nice and useful.

martinjrobins commented 6 years ago

I'm not sure if the old style would have helped, if you wrote (using the old syle of accumulators):

x[a]=sum(b, condition , somefunction(a,b));

If condition evaluated false for all neighbours b, then the result of the sum is zero. While the default initial value of the sum is zero, you can optionally supply an initial value for the sum, would this help?

What do you want the result of the sum (i.e. x[a]) to be in the case that there are no problematic particles and therefore condition is always false?

JabirSS commented 6 years ago

I see! I thought the sum would not be evaluated at all and thus the value of x[a] would remain unchanged.

If the condition is false for the particle and all it's neighbors, then I would like the value of x[a] to remain unchanged.

Being able to do something like:

x[a] = if_else( condition, sum(b,someFunction(a,b)), x[a])

Would do the job, but unfortunately that does not compile.

martinjrobins commented 6 years ago

You could do it easily enough in two steps like (where tmp is an other variable you have already set up):

tmp[a] = sum(b,someFunction(a,b))
x[a] = if_else(tmp[a]>0, tmp[a], x[a])

Mind you, you might have problems since now the value of x[a] can change suddenly with the type of neighbouring particles. How about if all the neighbours of a given particle are those for which condition evaluates false (so x[a] is constant over time), then a single particle that evaluates true enters its neighbourhood, then the value of x[a] suddenly is set by someFunction(a,b) evaluated on that single particle. Is this going to work?

JabirSS commented 6 years ago

Yes actually that would work just fine! You're quite right about that scenario being potentially problematic, however luckily in the case of the simulation I'm running it's infrequent enough to not be a show-stopper. I might however have to re-think it pretty soon in the future!

Introducing that additional temporary variable (got plenty of them) gives me another problem, but I'll post a separate issue for that.

Thanks a lot!

martinjrobins commented 6 years ago

great, glad that worked. I'll close this now