ansys / pydpf-core

Data Processing Framework - Python Core
http://dpf.docs.pyansys.com/
MIT License
68 stars 25 forks source link

filter operation inside FC #136

Closed jlcuadros closed 2 years ago

jlcuadros commented 2 years ago

Thank you for this fantastic tool!

Please I dont figure out this How can I apply a operation (ie invert the value) to certain elements of a FC?

I have a mesh and several load Cases I compute for each node the max over time and min over time stresses (Smax, Smin). I compute for each node Sm =(Smax+Smin)*0.5 I compute for each node R=Smin/Smax I want to invert in R only for those nodes with Sm<0

Thank you in advance

Best regards

Jose

cbellot000 commented 2 years ago

Hi @jlcuadros, thank you for your enthusiasm! To apply an operator on a custom part of a field, you can use filtering operators. With your example, you can use a field_low_pass_fc operator with your fields_container as input and 0. as threshold. You can then connect this filtering operator as an input of the invert operator. Does that help?

jlcuadros commented 2 years ago

Thank you for you quick response @cbellot000

I've tried but I dont understand

I have:

> s_m
DPF stress_1.s Field
  Location: Nodal
  Unit: MPa
  3 entities 
  Data:6 components and 3 elementary `data`
> s_m.Data
[-0.17979685543105, 0.0533131614793092, ...
> Ratio
DPF  Fields Container
  with 1 field(s)
  defined on labels: unknown 

  with:
  - field 0 {unknown:  1} with Nodal location, 6 components and 3 entities.
> Ratio[0].Data
[1.5000009356126, 0.66666745519402, 0.666666726794763 ...

Then I do

op = dpf.operators.filter.field_low_pass() # operator instanciation
op.inputs.field.Connect(s_m)
op.inputs.threshold.Connect(0)
my_LowFilter = op.outputs.field.GetData()
my_LowFilter.Data
[-0.17979685543105, 0.0533131614793092, ...

but now... how can I use my_LowFilter to invert only those values in Ratio that correspond to nodes with s_m <0?

op = dpf.operators.math.invert_fc() # operator instanciation
op.inputs.fields_container.Connect(Ratio)
# where and how connect my_LowFilter??
my_fields_container = op.outputs.fields_container.GetData()

I´m sorry but I´m very new at dpf... I really appreciate your help, maybe there is an example with filters somewhere (I didn't find anything)

I feel that when I undestand the way this tool works it can changes all our workflow

Best regards

Jose

cbellot000 commented 2 years ago

Are you using dpf in cpython with the ansys-dpf-core package or in mechanical? (I see that the syntax that you use is not the one of ansys-dpf-core). But anyways to connect your operators you can do:

low_pass = dpf.operators.filter.field_low_pass_fc() # operator instanciation  
low_pass.inputs.fields_container.Connect(s_m)
low_pass.inputs.threshold.Connect(0.)
invert = dpf.operators.math.invert_fc() # operator instanciation
invert.inputs.fields_container.Connect(low_pass.outputs.fields_container)
my_fields_container = op.outputs.fields_container.GetData()
jlcuadros commented 2 years ago

I´m using inside mechanical In your code, you dont use 'ratio', it looks like your are inverting the values of s_m that are <0 but that is not what I need I want to invert only those values in Ratio that correspond to values in s_m that are <0

s_m has 3 elementary data (3 nodes) and 6 components ratio has 3 elementary data (3 nodes) and 6 components

for each component ins_m that is <0 I want to invert the component in ratio that is in the same position

I also do not understand why after the aplication of the filter there are positive and negative values (-0.17.. and 0.05 for instance)

op = dpf.operators.filter.field_low_pass() # operator instanciation
op.inputs.field.Connect(s_m)
op.inputs.threshold.Connect(0.)
my_LowFilter = op.outputs.field.GetData()
[-0.17979685543105, 0.0533131614793092, 0.542114140465856, 0.000454103919764748, 1.3995936177671, 0.000625587835202168, -0.145697603467852, 0.0486476499354467, ...

Thanks again

cbellot000 commented 2 years ago

Okay, sorry I misunderstood your needs, you can then use:

low_pass = dpf.operators.filter.scoping_low_pass() # operator instanciation  
low_pass.inputs.fields_container.Connect(s_m)
low_pass.inputs.threshold.Connect(0.)
rescope = dpf.operators.scoping.rescope()
rescope.inputs.fields.Connect(Ratio)
rescope.inputs.mesh_scoping.Connect(low_pass.outputs.scoping)
invert = dpf.operators.math.invert_fc() # operator instantiation
invert.Connect(rescope)
my_fields_container = invert.outputs.fields_container.GetData()

scoping_low_pass returns the entity ids of the filtering and you can then rescope a field to those ids.

jlcuadros commented 2 years ago

I needed a small change to run your code (field in stead of fields_container) low_pass.inputs.field.Connect(s_m) but still it does not do the job, it inverts everything. , that is not what I need, what i need is for each component in s_m that is <0 I want to invert the component in ratio that is in the same position

Ratio[0].Data
[1.5000009356126, 0.66666745519402, 0.666666726794763, 0.66653856190867, 0.666666611954064, 0.66670685133499, 1.50000022772077, 0.666664463751834, 0.666666619278295, 1.50000526100635, 0.666666662262696, 0.666667075884813, 1.49999693971766, 0.666667565459518, 0.666666673980272, 0.666666293928673, 0.666666655373701, 0.666666622787982]
>>> 
my_fields_container[0].Data
[0.666666250839105, 1.49999822581555, 1.4999998647118, 1.50028829110268, 1.50000012310337, 1.49990958994592, 0.666666565457453, 1.50000495657475, 1.50000010662384, 0.666664328449823, 1.50000000990893, 1.49999907925974, 0.666668026794924, 1.49999797771881, 1.49999998354439, 1.50000083866095, 1.50000002540917, 1.50000009872705]
>>> 
s_m.Data
[-0.17979685543105, 0.0533131614793092, 0.542114140465856, 0.000454103919764748, 1.3995936177671, 0.000625587835202168, -0.145697603467852, 0.0486476499354467, 0.545916012488306, -0.0191545530105941, 1.40982243791223, 0.0629022142384201, -0.0530191787402146, 0.034251943230629, 0.565960440784693, 0.0123628541768994, 1.46612031012774, 0.106124712154269]
jlcuadros commented 2 years ago

This is the only way I could perform what i was looking for. I suppose it is very slow but I find no other way

Any suggestion to avoid the for loop is more than wellcome

thank you in advance and best regards

Jose Luis

op = dpf.operators.math.component_wise_divide_fc()
op.inputs.fields_containerA.Connect(sv_max)
op.inputs.fields_containerB.Connect(sv_min)
RatioMm = op.outputs.fields_container.GetData()
op.inputs.fields_containerA.Connect(sv_min)
op.inputs.fields_containerB.Connect(sv_max)
Ratio = op.outputs.fields_container.GetData()
lista =[]
for i,val in enumerate(s_m.Data):
    if val >0:
        lista.append(Ratio[0].Data[i])
    else:
        lista.append(RatioMm[0].Data[i])
Ratio[0].Data=lista
del(RatioMm)

sv_max, sv_min are nodal based DPF Fields Container with 1 field(s) defined on labels: unknown

with: field 0 {unknown: 1} with Nodal location, 6 components and 3 entities.

stress.inputs.mesh_scoping.Connect(scoping)
stress.inputs.time_scoping.Connect(time_scoping)
sv =stress.outputs.fields_container.GetData()
op_maxm = dpf.operators.min_max.min_max_over_time_by_entity()
op_maxm.inputs.fields_container.Connect(sv)
sv_max = sx_max=op_maxm.outputs.max.GetData() 
sv_min = sx_min=op_maxm.outputs.min.GetData()

# s_m is 
suma = dpf.operators.math.add()
suma.inputs.fieldA.Connect(sv_max)
suma.inputs.fieldB.Connect(sv_min)
aux= suma.outputs.field.GetData()
escala = dpf.operators.math.scale()
escala.inputs.field.Connect(aux)
escala.inputs.ponderation.Connect(0.5)
s_m = escala.outputs.field.GetData()
jlcuadros commented 2 years ago

In stead of using a 6 component FC now I use 6 Fields so I can use rescoping to perform the task. Maybe there is a better way but this should be much faster than the "for" loop

Regards

Jose

cbellot000 commented 2 years ago

Yes, dividing your stress fields by component (using the operator "component_selector_fc" for example) will allow you to remove the loops