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:

;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_tE_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

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 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!!!

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:

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