# PYTHON callback with mask

**URL:** <https://forum.itascainternational.com/t/python-callback-with-mask/729>\
**Category:** FLAC3D\
**Created:** [August 29, 2022, 7:17am UTC](https://forum.itascainternational.com/t/python-callback-with-mask/729 "2022-08-29T07:17:03Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![Francesco\_IT](https://avatars.discourse-cdn.com/v4/letter/f/b5a626/32.png) [@Francesco\_IT](https://forum.itascainternational.com/u/Francesco_IT)\
**Post date:** [August 29, 2022, 7:17am UTC](https://forum.itascainternational.com/t/python-callback-with-mask/729/1 "2022-08-29T07:17:03Z")

</div>

Hi everyone,  
I’m trying to replace my FISH function with splitting with an analogous PYTHON function.  
Simplifying, the FISH function is like this:

;NON LINEAR ELASTIC (ROCKFILL)  
fish operator test\_EL(pnt1)  
;  
;Density  
local d\_rf = zone.extra(pnt1,1)  
zone.density(pnt1) = d\_rf  
;  
;BG  
local E\_0ref = zone.extra(pnt1,5)  
local K\_0ref = zone.extra(pnt1,6)  
local n1 = zone.extra(pnt1,7)  
local n2 = zone.extra(pnt1,8)  
local n3 = zone.extra(pnt1,9)  
;  
local E\_0  
local K\_0  
local E\_t  
local K\_t  
;  
;Tangent Young’s modulus  
if zone.stress.max(pnt1) \< sig\_0ref  
;  
E\_0 = E\_0ref\*((math.abs(zone.stress.max(pnt1)/sig\_0ref))^n1)  
K\_0 = K\_0ref\*((math.abs(zone.stress.max(pnt1)/sig\_0ref))^n2)  
;  
else  
E\_0 = E\_0ref  
K\_0 = K\_0ref  
;  
endif  
;  
E\_t = E\_0  
K\_t = K\_0  
;  
zone.prop(pnt1,‘bulk’) = K\_t  
zone.prop(pnt1,‘shear’) = 3._K\_t_E\_t/(9.\*K\_t-E\_t)  
;  
local ii = zone.force.update()  
;  
end

global ElasticZones = list(zone.list)((zone.model(::zone.list) == “Elastic”) & ~(zone.isgroup(::zone.list,“Concrete”) | zone.isgroup(::zone.list,“Plinth”)))

fish callback add test\_EL([::ElasticZones]) -1  
model solve  
fish callback remove test\_EL -1

I would like to use itasca.zonearray but, as far as I understood, there is no (or at least it’s not documented) a function like itasca.zonearray.model() to be used together with itasca.zonearray.in\_group() to replace the FISH filtering statement.  
How is it possible to perform array operations on a subset of zones obtained combining zone model with zone group? This subset changes at each step (because of activations, deactivations and model changes in the list of zones).  
Thank you in advance for your suggestions.

Francesco

---

<div class="post-metadata">

**Author:** ![Huy](https://avatars.discourse-cdn.com/v4/letter/h/c5a1d2/32.png) [@Huy](https://forum.itascainternational.com/u/Huy)\
**Post date:** [August 29, 2022, 2:14pm UTC](https://forum.itascainternational.com/t/python-callback-with-mask/729/2 "2022-08-29T14:14:59Z")

</div>

if the subset changes during the simulation, I think that the simplest way is just to add the condition for the zone model and zone group in the fish function.

---

<div class="post-metadata">

**Author:** ![Francesco\_IT](https://avatars.discourse-cdn.com/v4/letter/f/b5a626/32.png) [@Francesco\_IT](https://forum.itascainternational.com/u/Francesco_IT)\
**Post date:** [August 29, 2022, 2:53pm UTC](https://forum.itascainternational.com/t/python-callback-with-mask/729/3 "2022-08-29T14:53:57Z")

</div>

Hi Huy,  
thank you for your reply. Can you be more explicit?  
Should I pass _ElasticZones_ to Python function? And if yes, how? As I have 140 phases, I would like to avoid to generate (also with a Fish) 140 specific incremental groups to be used in the Python at each phase.

---

<div class="post-metadata">

**Author:** ![Huy](https://avatars.discourse-cdn.com/v4/letter/h/c5a1d2/32.png) [@Huy](https://forum.itascainternational.com/u/Huy)\
**Post date:** [September 1, 2022, 7:38am UTC](https://forum.itascainternational.com/t/python-callback-with-mask/729/4 "2022-09-01T07:38:02Z")

</div>

Hi Francesco,  
What I means is to generate the mask directly for each step. You can create a function to check if a zone is elastic and in a group you want. Then you can map the function over zonearray. Since you just need to do that at the beginning of each sequence step, it should be ok?

---

<div class="post-metadata">

**Author:** ![Francesco\_IT](https://avatars.discourse-cdn.com/v4/letter/f/b5a626/32.png) [@Francesco\_IT](https://forum.itascainternational.com/u/Francesco_IT)\
**Post date:** [September 1, 2022, 8:29am UTC](https://forum.itascainternational.com/t/python-callback-with-mask/729/5 "2022-09-01T08:29:50Z")

</div>

Hi Huy,  
thank you for your suggestion. Do you have an example of such function and of the syntax for mapping?  
I don’t know if this can work (using FISH global ElasticZones passed via itasca.fish.get to Python):

_E0\_ref = itasca.zonearray.extra(5)_

_K0\_ref = itasca.zonearray.extra(6)_

_n1 = itasca.zonearray.extra(7)_

_n1 = itasca.zonearray.extra(8)_

_n3 = itasca.zonearray.extra(9)_

_sig\_0ref = itasca.fish.get(‘sig\_0ref’)_

_elastic\_zones = itasca.fish.get(‘ElasticZones’)_

_n\_zones = itasca.zone.count()_

_bulk\_array = np.zeros(n\_zones)_

_bulk\_array[elastic\_zones] = K\_0ref\*(math.abs(itasca.zonearray.stress\_max()/sig\_0ref))^n1)_

_itasca.zonearray.set\_prop\_scalar(‘bulk’,bulk\_array)_

Otherwise, could a function to generate the mask be as follows?

def mask\_gen(\*args)  
array\_mask = np.zero(itasca.zone.count())  
for z in itasca.zone.list():  
elastic\_zones[z] = ((itasca.zone.Zone.model(z) == ‘Elastic’) & ~(itasca.zone.Zone.group(z,‘Slot’) == ‘Concrete’))  
return elastic\_zones

Thank you for the support!!!

---

<div class="post-metadata">

**Author:** ![Huy](https://avatars.discourse-cdn.com/v4/letter/h/c5a1d2/32.png) [@Huy](https://forum.itascainternational.com/u/Huy)\
**Post date:** [September 1, 2022, 10:05am UTC](https://forum.itascainternational.com/t/python-callback-with-mask/729/6 "2022-09-01T10:05:40Z")

</div>

This line will not work because _ElasticZones_ is a list of pointer in Fish  
`elastic_zones = itasca.fish.get(‘ElasticZones’)`

To generate the mask, I just rewrite your script a little bit:

```auto
def fcheck(z):
    return z.model() == "elastic" and z.in_group("Concrete","Slot")
mask = np.array([fcheck(z) for z in it.zone.list()])

```

You can try to use **np.fromiter** which could be faster. But you should avoid np.vectorize

---

<div class="post-metadata">

**Author:** ![Francesco\_IT](https://avatars.discourse-cdn.com/v4/letter/f/b5a626/32.png) [@Francesco\_IT](https://forum.itascainternational.com/u/Francesco_IT)\
**Post date:** [July 21, 2025, 10:07am UTC](https://forum.itascainternational.com/t/python-callback-with-mask/729/7 "2025-07-21T10:07:37Z")

</div>

Hi,  
I’m trying to callback a function with a mask but I don’t know the syntax. I tried the following but it doesn’t work:

it.set\_callback(“test\_EL\_py(mask)”,-1)

It seems the interpreter read **test\_EL\_py(mask)** as the name of the function but **test\_EL\_py** is the name and **mask** is the mask.

In the function, to avoid cycles I used **where** like this:

bulk\_array[args] = np.where(stress\_array[args] \< sig\_0ref,K\_0ref[args]\*np.power(np.absolute(stress\_array[args]/sig\_0ref),n1[args]),K\_0ref[args])

Is it correct? For more complex conditions, is the use of **nested where** the only way or there are other ways to avoid cycles?

Thank you
