Closed aljosahafner closed 3 years ago
Hello, I started digging into the code to get out the data needed. I do not know how you guys store the electric field. In any event this is how I got thus far: if you run and SRW undulator source in OASYS, then connect a python script widget:
srw_beam=in_object_1
print(dir(srw_beam))
['_SRWDatasrw_beamline', '_SRWDatasrw_wavefront', 'class', 'delattr', 'dict', 'dir', 'doc', 'eq', 'format', 'ge', 'getattribute', 'gt', 'hash', 'init', 'init_subclass', 'le', 'lt', 'module', 'ne', 'new', 'reduce', 'reduce_ex', 'repr', 'setattr', 'sizeof', 'str', 'subclasshook', 'weakref', 'get_srw_beamline', 'get_srw_wavefront', 'get_working_srw_beamline', 'reset_working_srw_beamline', 'set_working_srw_beamline']
srw_wf=srw_beam._SRWData__srw_wavefront
print(dir(srw_wf)) ['Rx', 'Ry', 'ScanningData', 'class', 'delattr', 'dict', 'dir', 'doc', 'eq', 'format', 'ge', 'getattribute', 'gt', 'hash', 'init', 'init_subclass', 'le', 'lt', 'module', 'ne', 'new', 'reduce', 'reduce_ex', 'repr', 'setattr', 'sizeof', 'str', 'subclasshook', 'weakref', 'addE', 'allocate', 'arElecPropMatr', 'arEx', 'arEy', 'arMomX', 'arMomY', 'arWfrAuxData', 'avgPhotEn', 'calc_stokes', 'copy_comp', 'dRx', 'dRy', 'decorateSRWWF', 'delE', 'duplicate', 'fromGenericWavefront', 'get_1D_intensity_distribution', 'get_2D_intensity_distribution', 'get_dimension', 'get_flux', 'get_intensity', 'get_intensity_from_electric_field', 'get_phase', 'get_photon_energy', 'get_wavelength', 'mesh', 'numTypeElFld', 'partBeam', 'presCA', 'presFT', 'scanned_variable_data', 'setScanningData', 'toGenericWavefront', 'unitElFld', 'unitElFldAng', 'xc', 'yc']
These are all the methods available. Their definitions sits in srw_wavefront.py, which in turns is: wofrysrw.propagator.wavefront2D
Inside there, there are methods for converting wavefronts between numpy-digestible and SRW-data: SRWEFieldAsNumpy SRWWavefrontFromElectricField numpyArrayToSRWArray SRWArrayToNumpy
Please do tell me if this helps, or if you need further info.
Thanks, very helpful
Do we need a source only, or a source + a "continuation plane"? Can you also provide an example file, with a configured test source?
I do not work on OASYS-GUI right now, so I will need someone's assistance to extract the field.
@aljosahafner: can you do that, just throwing out a .txt? Guess that np.savetxt('outfile.txt', MyArray.view(complex))
would be fine. I think that the candidate function is SRWEFieldAsNumpy
. Let's start with a distance of... 5m from the source.
Thanks.
You cannot have a source without a continuation plane: SRW calculates the field at a certain, specified distance. See attached ows file. SRW field data extraction.ows.zip
After being generated (through GUI or script), the wavefront is accessible as:
import wofrysrw
srwData = in_object_1
srwWavefront = srwData._SRWData__srw_wavefront
efield = np.array(srwWavefront.arEx) # 1D array of E field with real, imaginary, real, etc. components
dim_x = srwWavefront.mesh.nx # Number of points - sampling
dim_y = srwWavefront.mesh.ny
re = np.array(efield[::2], dtype=np.float)
im = np.array(efield[1::2], dtype=np.float)
e = re + 1j * im # Make the array out of real and imaginary components
e = e.reshape((dim_x, dim_y)) # If necessary, reshape into a regular grid
# Access single wavelength, single polarization from the 4D array
asNpy = wofrysrw.propagator.wavefront2D.srw_wavefront.SRWEFieldAsNumpy(srwWavefront)[0][0, :, :, 0]
I inspected a little bit SRW data.
All the intensity profiles
The averaged Intensity
This seems to be what is shown in the "screen" widget.
I need info on what the widget that converts from 2D wavefront <--> 1d wavevront does. (by the way, where is it?).
As a general concept I guess it ahs the following parameters
2D wavefront -> 1D wavefront widget is a part of Wofry widgets Tools package: https://github.com/oasys-kit/OASYS-WOFRY/tree/master/orangecontrib/wofry/widgets/tools
Ok, to complete the link b\w SRW and WISER we need the long awaited SourceNumeric. This is what I have in mind:
I don't think we can plug "wofry2wiser" directly to wiser. WISER does need a "source" and I would be quite surprised if the direct link wored.
I have implemented SourceNumeric in Optics.py
And its usage is (for example)
The novelty is line88.
The present design of LibWiser is such that CoreOptics contain the geometric information and OpticalElement contains ComputationData, where the field is stored. A posteriori this is not that great, but line 88 just fills the computation data in the right way.
I am not still sure that it works PERFECTLY, but it runs and it returns nice plots
When you have time, can you start drafting the widget Numerical Source?
It can work in two ways:
I would prioritize the second, leaving just disabled input for the file.
What do you think?
Please go through the code of the Wofry to Wiser widget a bit, there is a creation of a Dummy source in between.
Very interesting. Apparently Luca created a LibWiser-like DummyElement that subclasses the GaussianSource and has a specific function for evaluating the field. This is very good. However I do not expect it is gonna work: GaussianSource subclasses OpticsAnalytical, whereas here we need an OpticsNumerical. The propagation manager (in LibWiser) behaves in two different ways accprding to the kind of optical element. I guess that just by replacing SourceGaussian with SourceNumerical we can get things (almost) done. Shall we try? M Sidenote: for how Luca's code is done, DummyElement could inherit from any numerical optical element, e.g. a Mirror or tthe detector.
-- Inviato da myMail per Android Venerdì, 25 Giugno 2021, 09:05AM +02:00 da aljosahafner @.*** :
Please go through the code of the Wofry to Wiser widget a bit, there is a creation of a Dummy source in between.
- Wofry -> Wiser: https://github.com/oasys-elettra-kit/OASYS1-Wiser/blob/master/orangecontrib/wiser/widgets/tools/ow_from_wofry_wavefront_1d.py
- Wiser -> Wofry: https://github.com/oasys-elettra-kit/OASYS1-Wiser/blob/master/orangecontrib/wiser/widgets/tools/ow_wise_wavefront_to_wofry.py — You are receiving this because you were assigned. Reply to this email directly, view it on GitHub , or unsubscribe .
So, if we link wofry2wiser---> Wiser detector we get something, but we should understand what.
Comment 1
The behavior of an optical element which is place at "0 distance" from the previous one does not appear to be so well defined in LibWiser
A still different behavior occurs if the positioning method is chosen.
This can not be a problem in the 95% of cases, since there is no need to put a detector at 0 distance from an optical element.
The first case I have encountered is the case of a "numeric source" (or wofry surce), where it comes as spontaneous to put a wiser detector widget downstream wofrywise widget, to see what is going on.
Comment2) How do we want wiser to be have with a layout like this? (probably nothing)
The reason of this (apparently) is simple: to make an effective test of the numerical source we would need the following layout
Source ---->detector ---->save field
load field --->numerical source ----> beamline
and compare it with
Soure --->beamline
(if not clear, I will explain it orally)
I see that there are writers and readers for wavefronts in wofry
Probably this is al what we need.
1. Wiser Numerical source is not tested yet
2. the best way to test it is in oasys: this needs to wire some tools =>
in principle wiser2wofry+wofry_write + wofry read + wofry2wiser should be all that we needs
2b: once the pipeline is ok, we can play with making a gaussian source numerical, then propagate it, and check the differences.
3. In principle it would be nice if we had an "all wiser" numerical source with access from file
=> the advantage is the auto-generation of wiser code (supported at 80%)
BUT
This is not a priority
BUT
Let's keep this in mind.
Field = sqrt(Intensity) * exp(1j*phase)
def get_numerical_source(wofry_wavefront):
Lambda = wofry_wavefront.get_wavelength() % => check the units
L = wofry_wavefront.get_size() # checl
Field = sqrt(wofry_wavefront.get_intensity()) * exkp(1j * wofry_wavefront.get_phase())
# build the Numerical source here
WiserNumericalSource = OpticalElement(
CoreOptics.SourceNumerical
(....
...)
PositioningDirectives( )
# CAUTION!: where to put the numerical source?
Numerical sources are not set at the waist z=0, but a little bit downstream, e.g. z=5 (numerical reasons).
This means that all the distances are offsetted.
CONSEQUENCE => we need to introduce an extra field called "Virtual Offset" or "Offset to real source waist"
(suggestions on naming are welcome) that is then used by all the functions computing the distances
in LibWiser I am doing it now
This also means that we need a new field in the conversion widget. Without this, all the distances would be screwed up.
return Foundation.OpticalElement(Name="Wofry Source",
IsSource=True,
CoreOpticsElement=DummyElement(wofry_wavefront=wofry_wavefront),
PositioningDirectives=Foundation.PositioningDirectives(ReferTo=Foundation.PositioningDirectives.ReferTo.AbsoluteReference,
XYCentre=[0.0, 0.0],
Angle=0.0))
Placeholder for numerical source issue... @maltissimo @capitanevs