hibtc / cpymad

Cython binding to MAD-X
http://hibtc.github.io/cpymad/
Other
27 stars 18 forks source link

Twiss at certain positions #98

Closed Rasimilian closed 3 years ago

Rasimilian commented 3 years ago

Hello! I'm trying to get Twiss at BPMs positions via a select command, but I get a full twiss table:

madx.input('select,flag=twiss_in_bpms,class=monitor,full=False,column=name,s,betx,bety,dx;')
madx.twiss(sequence='RING', centre=True, table='twiss_in_bpms')
twiss_table = madx.table.twiss_in_bpms.betx

The only way to get at certain positions is to save a table to a file and then to read the file:

madx.input('select,flag=twiss_in_bpms,class=monitor,full=False,column=name,s,betx,bety,dx;')
madx.twiss(sequence='RING', centre=True, table='twiss_in_bpms', file="log_file.txt")
madx.input('readtable,file="log_file.txt",table=twiss_in_bpms;')
twiss_table = madx.table.twiss_in_bpms.betx

Is it possible not to create an additional file? Could you help me with this please?

fsoubelet commented 3 years ago

Hi @Rasimilian, I believe the flag should be the generic name of a MADX table, and this will work if you just change select, flag=twiss_in_bpms,... to select, flag=twiss,....

Rasimilian commented 3 years ago

@fsoubelet it doesn't work too :(

fsoubelet commented 3 years ago

That's unfortunate. Could you provide your script, or a minimal version so we can have a look at the issue?

Rasimilian commented 3 years ago

Actually, this doesn't work for any element selected via the command. But here is the code:

madx = Madx(stdout=True)
madx.call(file='structure.txt')
madx.input('beam,particle=electron,energy=1.8;')
madx.input('use,sequence=RING;')

madx.input('select,flag=twiss,class=monitor,full=False,column=name,s,betx,bety,dx;')
madx.twiss(sequence='RING', centre=True, table='twiss_in_bpms')
twiss_table = madx.table.twiss_in_bpms.betx
fsoubelet commented 3 years ago

Could you also provide the contents of structure.txt?

fsoubelet commented 3 years ago

I can confirm the behavior here. While waiting for @coldfix's take, the simplest I can suggest for now would be to make use of the associated pandas.DataFrame from the TWISS results:

madx = Madx()
madx.call(file="structure.txt")
madx.command.beam(particle="electron", energy=1.8)
madx.use(sequence="RING")

madx.command.select(flag="twiss", class_="monitor", full=False, column=["name", "s", "betx", "bety", "dx"])
madx.twiss(sequence="RING", centre=True)

twiss_table = madx.table.twiss.dframe().copy()
monitors = twiss_table[twiss_table.keyword == "monitor"][madx.table.twiss.selected_columns()]

Alternatively, if you have a know regex pattern (beware of MADX's own regex) for your monitors you can use select, pattern=... which has always worked fine on my side.

Rasimilian commented 3 years ago

@fsoubelet, do you suggest to use select, pattern=monitor1;select, pattern=monitor2..., if there are monitors named as monitor1, monitor2 ...? if I understand you correctly, this doesn't work too. Anyway, thank you!

coldfix commented 3 years ago

Hi, cpymad has the Table.selected_rows() method that can be used to retrieve which rows were selected by a previous SELECT statement. It can currently be used as follows:

twiss = madx.table.twiss

selection = np.array(twiss.selected_rows(), dtype=bool)
rows = twiss.dframe().iloc[selection]

However, the function is currently not implemented according to its documentation which means that I will change the implementation to fit the documentation, so this will be slightly different (removing the need for the manual np.array creation).

I will also add rows keyword arguments to some relevant methods to allow the user querying only specified rows. We should maybe even make the default to return only the selected rows. What do you think?

coldfix commented 3 years ago

Also for an unknown reason, it currently doesn't seem to work if specifying a custom table name, I will check if anything can be done about that.

coldfix commented 3 years ago

Scrap my last comment, it does work, but the flag parameter of SELECT must be set to the table name, e.g.:

madx.input('SELECT, flag=twiss_in_bpms, class=monitor;')
madx.twiss(sequence=..., table='twiss_in_bpms')

(but this also seems to be the case when exporting the table to a file using the filename argument)

Rasimilian commented 3 years ago

@coldfix, the reason I asked is that I'm struggling for milliseconds now. For my current problem the code speed is essential. So I have measured time of program execution for suggested methods and the best time is for the code with a created file. I thought avoidance of file creating and accessing an internal table instead would buy me time. But your suggestions are relevant and great.

coldfix commented 3 years ago

Sure. I will change it so that the selected rows are applied on the C side without having to read out the entire table, so you won't have to worry about performance. But I can't promise I'll be able to do it today.

Rasimilian commented 3 years ago

Thank you! :)