PYTHON callback with mask

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

fish operator test_EL(pnt1)
local d_rf = zone.extra(pnt1,1)
zone.density(pnt1) = d_rf
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)
E_0 = E_0ref
K_0 = K_0ref
E_t = E_0
K_t = K_0
zone.prop(pnt1,‘bulk’) = K_t
zone.prop(pnt1,‘shear’) = 3.K_tE_t/(9.*K_t-E_t)
local ii = zone.force.update()

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.


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.

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.

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?

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 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 =‘sig_0ref’)

elastic_zones =‘ElasticZones’)

n_zones =

bulk_array = np.zeros(n_zones)

bulk_array[elastic_zones] = K_0ref*(math.abs(itasca.zonearray.stress_max()/sig_0ref))^n1)


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

def mask_gen(*args)
array_mask =
for z in
elastic_zones[z] = (( == ‘Elastic’) & ~(,‘Slot’) == ‘Concrete’))
return elastic_zones

Thank you for the support!!!

This line will not work because ElasticZones is a list of pointer in Fish
elastic_zones =‘ElasticZones’)

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

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

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