syned 1.0.47__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. syned/__init__.py +0 -0
  2. syned/__test/__init__.py +46 -0
  3. syned/__test/test.py +28 -0
  4. syned/beamline/__init__.py +1 -0
  5. syned/beamline/beamline.py +155 -0
  6. syned/beamline/beamline_element.py +76 -0
  7. syned/beamline/element_coordinates.py +199 -0
  8. syned/beamline/optical_element.py +47 -0
  9. syned/beamline/optical_element_with_surface_shape.py +126 -0
  10. syned/beamline/optical_elements/__init__.py +1 -0
  11. syned/beamline/optical_elements/absorbers/__init__.py +0 -0
  12. syned/beamline/optical_elements/absorbers/absorber.py +21 -0
  13. syned/beamline/optical_elements/absorbers/beam_stopper.py +64 -0
  14. syned/beamline/optical_elements/absorbers/filter.py +61 -0
  15. syned/beamline/optical_elements/absorbers/holed_filter.py +67 -0
  16. syned/beamline/optical_elements/absorbers/slit.py +81 -0
  17. syned/beamline/optical_elements/crystals/__init__.py +1 -0
  18. syned/beamline/optical_elements/crystals/crystal.py +70 -0
  19. syned/beamline/optical_elements/gratings/__init__.py +1 -0
  20. syned/beamline/optical_elements/gratings/grating.py +279 -0
  21. syned/beamline/optical_elements/ideal_elements/__init__.py +1 -0
  22. syned/beamline/optical_elements/ideal_elements/ideal_element.py +16 -0
  23. syned/beamline/optical_elements/ideal_elements/ideal_fzp.py +183 -0
  24. syned/beamline/optical_elements/ideal_elements/ideal_lens.py +54 -0
  25. syned/beamline/optical_elements/ideal_elements/screen.py +16 -0
  26. syned/beamline/optical_elements/mirrors/__init__.py +1 -0
  27. syned/beamline/optical_elements/mirrors/mirror.py +39 -0
  28. syned/beamline/optical_elements/multilayers/__init__.py +46 -0
  29. syned/beamline/optical_elements/multilayers/multilayer.py +45 -0
  30. syned/beamline/optical_elements/refractors/__init__.py +1 -0
  31. syned/beamline/optical_elements/refractors/crl.py +79 -0
  32. syned/beamline/optical_elements/refractors/interface.py +61 -0
  33. syned/beamline/optical_elements/refractors/lens.py +105 -0
  34. syned/beamline/shape.py +2803 -0
  35. syned/storage_ring/__init__.py +1 -0
  36. syned/storage_ring/electron_beam.py +804 -0
  37. syned/storage_ring/empty_light_source.py +40 -0
  38. syned/storage_ring/light_source.py +90 -0
  39. syned/storage_ring/magnetic_structure.py +8 -0
  40. syned/storage_ring/magnetic_structures/__init__.py +1 -0
  41. syned/storage_ring/magnetic_structures/bending_magnet.py +329 -0
  42. syned/storage_ring/magnetic_structures/insertion_device.py +169 -0
  43. syned/storage_ring/magnetic_structures/undulator.py +413 -0
  44. syned/storage_ring/magnetic_structures/wiggler.py +27 -0
  45. syned/syned_object.py +264 -0
  46. syned/util/__init__.py +22 -0
  47. syned/util/json_tools.py +198 -0
  48. syned/widget/__init__.py +0 -0
  49. syned/widget/widget_decorator.py +67 -0
  50. syned-1.0.47.dist-info/METADATA +88 -0
  51. syned-1.0.47.dist-info/RECORD +54 -0
  52. syned-1.0.47.dist-info/WHEEL +5 -0
  53. syned-1.0.47.dist-info/licenses/LICENSE +20 -0
  54. syned-1.0.47.dist-info/top_level.txt +1 -0
@@ -0,0 +1,413 @@
1
+ """
2
+ Implement an undulator with vertical and horizontal magnetic fields.
3
+ """
4
+ import numpy
5
+ import scipy.constants as codata
6
+
7
+ cte = codata.e/(2*numpy.pi*codata.electron_mass*codata.c)
8
+
9
+ from syned.storage_ring.magnetic_structures.insertion_device import InsertionDevice
10
+
11
+ class Undulator(InsertionDevice):
12
+ """
13
+ Constructor.
14
+
15
+ Parameters
16
+ ----------
17
+ K_vertical : float, optional
18
+ The deflection K parameter corresponding to magnetic field in the vertical direction.
19
+ K_horizontal : float, optional
20
+ The deflection K parameter corresponding to magnetic field in the horizontal direction.
21
+ period_length : float, optional
22
+ The ID period in m.
23
+ number_of_periods : float, optional
24
+ The number of periods. It may be a float, considering that number_of_periods = ID_length / period_length.
25
+
26
+ """
27
+
28
+ def __init__(self,
29
+ K_vertical = 0.0,
30
+ K_horizontal = 0.0,
31
+ period_length = 0.0,
32
+ number_of_periods = 1.0):
33
+ InsertionDevice.__init__(self, K_vertical, K_horizontal, period_length, number_of_periods)
34
+
35
+ def resonance_wavelength(self, gamma, theta_x=0.0, theta_z=0.0, harmonic=1.0):
36
+ """
37
+ Returns the resonant wavelength in m.
38
+
39
+ Parameters
40
+ ----------
41
+ gamma : float
42
+ The gamma or Lorentz factor of the electron beam.
43
+ theta_x : float, optional
44
+ The angle along the horizontal direction in rad.
45
+ theta_z : float, optional
46
+ The angle along the vertical direction in rad.
47
+ harmonic : float, optional
48
+ The harmonic number (1,2,3...) to be considered.
49
+
50
+ Returns
51
+ -------
52
+ float
53
+
54
+
55
+ """
56
+ wavelength = (self.period_length() / (2.0 * gamma **2)) * \
57
+ (1 + self.K_vertical()**2 / 2.0 + self.K_horizontal()**2 / 2.0 + \
58
+ gamma**2 * (theta_x**2 + theta_z**2))
59
+
60
+ return wavelength / harmonic
61
+
62
+ def resonance_frequency(self, gamma, theta_x=0.0, theta_z=0.0, harmonic=1.0):
63
+ """
64
+ Returns the resonant frequency in Hz.
65
+
66
+ Parameters
67
+ ----------
68
+ gamma : float
69
+ The gamma or Lorentz factor of the electron beam.
70
+ theta_x : float, optional
71
+ The angle along the horizontal direction in rad.
72
+ theta_z : float, optional
73
+ The angle along the vertical direction in rad.
74
+ harmonic : float, optional
75
+ The harmonic number (1,2,3...) to be considered.
76
+
77
+ Returns
78
+ -------
79
+ float
80
+
81
+
82
+ """
83
+ frequency = codata.c / self.resonance_wavelength(gamma, theta_x, theta_z)
84
+
85
+ return frequency * harmonic
86
+
87
+ def resonance_energy(self, gamma, theta_x=0.0, theta_z=0.0, harmonic=1.0):
88
+ """
89
+ Returns the resonant energy in eV.
90
+
91
+ Parameters
92
+ ----------
93
+ gamma : float
94
+ The gamma or Lorentz factor of the electron beam.
95
+ theta_x : float, optional
96
+ The angle along the horizontal direction in rad.
97
+ theta_z : float, optional
98
+ The angle along the vertical direction in rad.
99
+ harmonic : float, optional
100
+ The harmonic number (1,2,3...) to be considered.
101
+
102
+ Returns
103
+ -------
104
+ float
105
+
106
+
107
+ """
108
+ energy_in_ev = codata.h * self.resonance_frequency(gamma, theta_x, theta_z) / codata.e
109
+
110
+ return energy_in_ev*harmonic
111
+
112
+ def gaussian_central_cone_aperture(self, gamma, n=1.0):
113
+ """
114
+ Returns the approximated angular width (sigma) in rad of the central cone.
115
+
116
+ Parameters
117
+ ----------
118
+ gamma : float
119
+ The gamma or Lorentz factor of the electron beam.
120
+ n : float, optional
121
+ The harmonic number (1,2,3...) to be considered.
122
+
123
+ Returns
124
+ -------
125
+ float
126
+
127
+ References
128
+ ----------
129
+ Eq. 15 in https://xdb.lbl.gov/Section2/Sec_2-1.html
130
+
131
+ """
132
+ return (1/gamma)*numpy.sqrt((1.0/(2.0*n*self.number_of_periods())) * (1.0 + self.K_horizontal()**2/2.0 + self.K_vertical()**2/2.0))
133
+
134
+ @classmethod
135
+ def initialize_as_vertical_undulator(cls, K = 0.0, period_length = 0.0, periods_number = 1.0, **params):
136
+ """
137
+ Create an undulator with vertical magnetic field.
138
+
139
+ Parameters
140
+ ----------
141
+ K : float, optional
142
+ The deflection K parameter corresponding to magnetic field in the vertical direction.
143
+ period_length : float, optional
144
+ The ID period in m.
145
+ periods_number : float, optional
146
+ The number of periods. It may be a float, considering that number_of_periods = ID_length / period_length.
147
+ params : other parameters accepted by Undulator.
148
+
149
+ Returns
150
+ -------
151
+ instance of Undulator
152
+
153
+ """
154
+ return cls(K_vertical=K,
155
+ K_horizontal=0.0,
156
+ period_length=period_length,
157
+ number_of_periods=periods_number, **params)
158
+ #
159
+ #
160
+ #
161
+
162
+ def get_sigmas_radiation(self, gamma, harmonic=1.0):
163
+ """
164
+ Returns the approximated radiation sigmas (size and divergence).
165
+
166
+ Parameters
167
+ ----------
168
+ gamma : float
169
+ The gamma or Lorentz factor of the electron beam.
170
+ harmonic : float, optional
171
+ The harmonic number (1,2,3...) to be considered.
172
+
173
+ Returns
174
+ -------
175
+ tuple
176
+ (sigma_in_real_space [m], sigma_in_divergence_space [rad])
177
+
178
+ References
179
+ ----------
180
+
181
+ See formulas 25 & 30 in Elleaume (Onuki & Elleaume) for the calculated sizes of the photon undulator beam.
182
+ Onuki & Elleaume "Undulators, Wigglers and Their Applications" (2002) CRC Press.
183
+
184
+
185
+ """
186
+ # calculate sizes of the photon undulator beam
187
+ # see formulas 25 & 30 in Elleaume (Onuki & Elleaume)
188
+ photon_energy = self.resonance_energy(gamma,harmonic=harmonic)
189
+ lambdan = 1e-10 * codata.h * codata.c / codata.e * 1e10 / photon_energy # in m
190
+ sigma_r = 2.740 / 4 / numpy.pi * numpy.sqrt(lambdan * self.number_of_periods() * self.period_length())
191
+ sigma_r_prime = 0.69 * numpy.sqrt(lambdan / (self.length()))
192
+ return sigma_r, sigma_r_prime
193
+
194
+ def get_resonance_ring(self, gamma, harmonic=1.0, ring_order=1):
195
+ """
196
+ Return the angular position of the rings at resonance.
197
+
198
+ Parameters
199
+ ----------
200
+ gamma : float
201
+ The gamma or Lorentz factor of the electron beam.
202
+ harmonic : float, optional
203
+ The harmonic number (1,2,3...) to be considered.
204
+ ring_order : int, optional
205
+ The ring order (1,2,3...)
206
+
207
+ Returns
208
+ -------
209
+ float
210
+ The angular position in rad.
211
+
212
+ """
213
+ K_value = numpy.sqrt( self.K_vertical()**2 + self.K_horizontal()**2)
214
+ return 1.0 / gamma * numpy.sqrt( ring_order / harmonic * (1 + 0.5 * K_value**2) )
215
+
216
+
217
+ def undulator_full_emitted_power(self, gamma, ring_current):
218
+ """
219
+ Returns the total emitted power by an undulator.
220
+
221
+ Parameters
222
+ ----------
223
+ gamma : float
224
+ The gamma or Lorentz factor of the electron beam.
225
+ ring_current : float
226
+ The current of the electron beam in A.
227
+
228
+ Returns
229
+ -------
230
+ float
231
+ The power in W.
232
+
233
+ References
234
+ ----------
235
+ Eq. 18 in https://xdb.lbl.gov/Section2/Sec_2-1.html
236
+
237
+ """
238
+ ptot = (self.number_of_periods() / 6) * codata.value('characteristic impedance of vacuum') * \
239
+ ring_current * codata.e * 2 * numpy.pi * codata.c * gamma**2 * \
240
+ (self.K_vertical()**2 + self.K_horizontal()**2) / self.period_length()
241
+ return ptot
242
+
243
+ def get_photon_sizes_and_divergences(self, syned_electron_beam, harmonic=1):
244
+ """
245
+ Return the photon beam sizes and divergences.
246
+
247
+ They are calculates as a convolution of the radiation sigmas (get_sigmas_radiation()) and
248
+ the electron beam sizes.
249
+
250
+ Parameters
251
+ ----------
252
+ syned_electron_beam : instance of ElectronBeam
253
+ The electron bean used to get the electron beam sizes and electron energy.
254
+ harmonic : int
255
+ The harmonic number (1,2,3...).
256
+
257
+ Returns
258
+ -------
259
+ tuple
260
+ (Sx [m], Sz [m], Sxp [rad], Szp [rad])
261
+
262
+ """
263
+ sr,srp = self.get_sigmas_radiation(syned_electron_beam.gamma(), harmonic=harmonic)
264
+ sx,sxp,sz,szp = syned_electron_beam.get_sigmas_all()
265
+
266
+ Sx = numpy.sqrt( sx**2 + sr**2)
267
+ Sz = numpy.sqrt( sz**2 + sr**2)
268
+ Sxp = numpy.sqrt( sxp**2 + srp**2)
269
+ Szp = numpy.sqrt( szp**2 + srp**2)
270
+
271
+ return Sx,Sz,Sxp,Szp
272
+
273
+ def get_K_from_photon_energy(self, photon_energy, gamma, harmonic=1):
274
+ """
275
+ Calculate K for a given resonance energy.
276
+
277
+ Parameters
278
+ ----------
279
+ photon_energy : float
280
+ The photon energy in eV.
281
+ gamma : float
282
+ The electron gamma (Lorentz factor).
283
+ harmonic : int
284
+ The harmonic number.
285
+
286
+ Returns
287
+ -------
288
+ float
289
+
290
+ """
291
+ m2ev = codata.c * codata.h / codata.e
292
+ wavelength = harmonic * m2ev / photon_energy
293
+ return numpy.sqrt(2 * (((wavelength * 2 * gamma**2) / self.period_length()) - 1))
294
+
295
+ def approximated_coherent_fraction_horizontal(self, syned_electron_beam, harmonic=1):
296
+ """
297
+ Gets the approximated coherent fraction at resonance in the horizontal direction.
298
+
299
+ It is calculated as the ratio of the phase space of the coherent emission (zero emittance) over
300
+ the actual emission (finite emittance).
301
+
302
+ Parameters
303
+ ----------
304
+ syned_electron_beam : instance of ElectronBeam
305
+ The electron bean used to get the electron beam sizes and electron energy.
306
+ harmonic : int
307
+ The harmonic number (1,2,3...).
308
+
309
+ Returns
310
+ -------
311
+ float
312
+
313
+ """
314
+ Sx,Sy,Sxp,Syp = self.get_photon_sizes_and_divergences(syned_electron_beam, harmonic=harmonic)
315
+ srad,sradp = self.get_sigmas_radiation(syned_electron_beam.gamma(), harmonic=harmonic)
316
+ return srad * sradp / ( Sx * Sxp)
317
+
318
+ def approximated_coherent_fraction_vertical(self, syned_electron_beam,harmonic=1):
319
+ """
320
+ Gets the approximated coherent fraction at resonance in the vertical direction.
321
+
322
+ It is calculated as the ratio of the phase space of the coherent emission (zero emittance) over
323
+ the actual emission (finite emittance).
324
+
325
+ Parameters
326
+ ----------
327
+ syned_electron_beam : instance of ElectronBeam
328
+ The electron bean used to get the electron beam sizes and electron energy.
329
+ harmonic : int
330
+ The harmonic number (1,2,3...).
331
+
332
+ Returns
333
+ -------
334
+ float
335
+
336
+ """
337
+ Sx,Sy,Sxp,Syp = self.get_photon_sizes_and_divergences(syned_electron_beam, harmonic=harmonic)
338
+ srad,sradp = self.get_sigmas_radiation(syned_electron_beam.gamma(), harmonic=harmonic)
339
+ return srad * sradp / ( Sy * Syp)
340
+
341
+ def approximated_coherent_fraction(self, syned_electron_beam, harmonic=1):
342
+ """
343
+ Gets the approximated coherent fraction at resonance.
344
+
345
+ It is calculated as the product of the horizontal and vertical coherent fractions.
346
+
347
+ Parameters
348
+ ----------
349
+ syned_electron_beam : instance of ElectronBeam
350
+ The electron bean used to get the electron beam sizes and electron energy.
351
+ harmonic : int
352
+ The harmonic number (1,2,3...).
353
+
354
+ Returns
355
+ -------
356
+ float
357
+
358
+ """
359
+ return self.approximated_coherent_fraction_horizontal(syned_electron_beam, harmonic=harmonic) * \
360
+ self.approximated_coherent_fraction_vertical(syned_electron_beam, harmonic=harmonic)
361
+
362
+
363
+ if __name__ == "__main__":
364
+
365
+ a = Undulator(number_of_periods=61.5, period_length=0.057)
366
+ a.set_K_vertical_from_magnetic_field(0.187782)
367
+
368
+ print(a._K_vertical)
369
+
370
+ print (a.resonance_energy(gamma=5870.8540997356595))
371
+
372
+ fd = a.to_full_dictionary()
373
+ dict = a.to_dictionary()
374
+
375
+ print(dict)
376
+
377
+ for key in fd:
378
+ print(key,fd[key][0])
379
+
380
+ for key in fd:
381
+ print(key,dict[key])
382
+
383
+ print(a.keys())
384
+ print(a.info())
385
+
386
+
387
+ print("####### derived quantities ##########")
388
+
389
+ from syned.storage_ring.electron_beam import ElectronBeam
390
+ ebeam = ElectronBeam.initialize_as_pencil_beam(energy_in_GeV=2.0,energy_spread=0.0,current=0.5)
391
+
392
+ sigmas_radiation = a.get_sigmas_radiation(ebeam.gamma(),harmonic=1.0)
393
+ print("sigmas radiation [m rad]:",sigmas_radiation)
394
+
395
+
396
+ ring = a.get_resonance_ring(ebeam.gamma(), harmonic=1.0, ring_order=1)
397
+ print("first ring at [rad]:",ring)
398
+
399
+ pow = a.undulator_full_emitted_power(ebeam.gamma(), ebeam.current())
400
+ print("Total emission [W]",pow)
401
+
402
+ sizes = a.get_photon_sizes_and_divergences(ebeam,harmonic=1)
403
+ print("Sizes: ",sizes)
404
+
405
+ print("Resonance: ",a.resonance_energy(ebeam.gamma()))
406
+
407
+ print("K at 444 eV",a.get_K_from_photon_energy(444.0,ebeam.gamma()))
408
+ print("K at 200 eV", a.get_K_from_photon_energy(200.0, ebeam.gamma()))
409
+
410
+ print("CF H V HV: ",
411
+ a.approximated_coherent_fraction_horizontal(ebeam,harmonic=1),
412
+ a.approximated_coherent_fraction_vertical(ebeam, harmonic=1),
413
+ a.approximated_coherent_fraction(ebeam, harmonic=1),)
@@ -0,0 +1,27 @@
1
+ from syned.storage_ring.magnetic_structures.insertion_device import InsertionDevice
2
+
3
+ class Wiggler(InsertionDevice):
4
+ """
5
+ Constructor.
6
+
7
+ Parameters
8
+ ----------
9
+ K_vertical : float, optional
10
+ The deflection K parameter corresponding to magnetic field in the vertical direction.
11
+ K_horizontal : float, optional
12
+ The deflection K parameter corresponding to magnetic field in the horizontal direction.
13
+ period_length : float, optional
14
+ The ID period in m.
15
+ number_of_periods : float, optional
16
+ The number of periods. It may be a float, considering that number_of_periods = ID_length / period_length.
17
+
18
+ """
19
+
20
+ def __init__(self, K_vertical = 0.0, K_horizontal = 0.0,period_length = 0.0, number_of_periods = 1):
21
+ InsertionDevice.__init__(self,
22
+ K_vertical=K_vertical,
23
+ K_horizontal=K_horizontal,
24
+ period_length=period_length,
25
+ number_of_periods=number_of_periods)
26
+
27
+
syned/syned_object.py ADDED
@@ -0,0 +1,264 @@
1
+ import copy
2
+ from collections import OrderedDict
3
+ try:
4
+ import json_tricks as json # to save numpy arrays
5
+ except:
6
+ import json
7
+
8
+ # TODO: although basic functionality is implemented, the use of exec should be replace by introspection tools
9
+ class SynedObject(object):
10
+
11
+ # ---------------------------------------------------------------------------------------------------------
12
+ # This override is necessary to avoid TypeError: cannot pickle '_thread.lock' object while duplicating
13
+ # that occurs while enabling/disabling connectors
14
+ #
15
+ # When an attribute is an object that contains non pickable attributes, we make a shallow copy of it
16
+ # ---------------------------------------------------------------------------------------------------------
17
+
18
+ def __deepcopy__(self, memodict={}):
19
+ cls = self.__class__
20
+ result = cls.__new__(cls)
21
+ memodict[id(self)] = result
22
+ for k, v in self.__dict__.items():
23
+ try: setattr(result, k, copy.deepcopy(v, memodict))
24
+ except TypeError: setattr(result, k, copy.copy(v))
25
+ return result
26
+
27
+ """
28
+ This is the base object for SYNED.
29
+
30
+ It includes the methods of the common interface to allow json file input/output and info mechanism
31
+
32
+ These standard methods are:
33
+ * keys()
34
+ * to_dictionary()
35
+ * to_full_dictionary()
36
+ * to_json()
37
+ * info()
38
+ * set_value_from_key_name()
39
+ * get_value_from_key_name()
40
+
41
+ """
42
+
43
+ def _set_support_text(self, text):
44
+ ordered_support_dict = OrderedDict()
45
+ for e in text:
46
+ ordered_support_dict[e[0]] = (e[1], e[2])
47
+ self._support_dictionary = ordered_support_dict
48
+
49
+ def _add_support_text(self, text):
50
+ try:
51
+ for e in text:
52
+ self._support_dictionary[e[0]] = (e[1], e[2])
53
+ except:
54
+ self._set_support_text(text)
55
+
56
+ #
57
+ # this is the common interface to allow json file input/output and info mechanism
58
+ #
59
+ # standard methods are:
60
+ # keys
61
+ # to_dictionary
62
+ # to_full_dictionary
63
+ # to_json
64
+ # info
65
+ # set_value_from_key_name
66
+ # get_value_from_key_name
67
+ #
68
+ def keys(self):
69
+ """
70
+ Returns the keys of the supporting doctionary.
71
+ Returns
72
+ -------
73
+ list
74
+ A list of keys.
75
+
76
+ """
77
+ try:
78
+ return self._support_dictionary.keys()
79
+ except:
80
+ return None
81
+
82
+ def to_dictionary(self):
83
+ """
84
+ Returns a dictionary with the object fields.
85
+
86
+ Some dictionary keys may contain SYNED instances. Use to_full_dictionary to recurrently expand these objects
87
+ in their basic ingredients.
88
+
89
+ Returns
90
+ -------
91
+ dict
92
+ A dictionary with the data.
93
+
94
+ """
95
+ dict_to_save = OrderedDict()
96
+ dict_to_save.update({"CLASS_NAME":self.__class__.__name__})
97
+
98
+ try:
99
+ if self.keys() is not None:
100
+ for key in self.keys():
101
+ tmp1 = eval("self._%s" % (key) )
102
+ if isinstance(tmp1,SynedObject):
103
+ dict_to_save[key] = tmp1.to_dictionary()
104
+ else:
105
+ dict_to_save[key] = tmp1
106
+ except:
107
+ pass
108
+
109
+ return dict_to_save
110
+
111
+ def to_full_dictionary(self):
112
+ """
113
+ Returns a dictionary with the object fields, including other syned objects embedded or list of elements.
114
+
115
+ The "full" means that the SYNED instances found are recurrently expanded in their basic ingredients.
116
+
117
+ Returns
118
+ -------
119
+ dict
120
+
121
+ """
122
+ dict_to_save = OrderedDict()
123
+ dict_to_save.update({"CLASS_NAME":self.__class__.__name__})
124
+ try:
125
+ if self.keys() is not None:
126
+ for key in self.keys():
127
+ tmp1 = eval("self._%s" % (key) )
128
+ if isinstance(tmp1, SynedObject):
129
+ dict_to_save[key] = tmp1.to_full_dictionary()
130
+ else:
131
+ mylist = []
132
+ mylist.append(tmp1)
133
+ mylist.append(self._support_dictionary[key])
134
+ dict_to_save[key] = mylist # [tmp1,self._support_dictionary[key]]
135
+ except:
136
+ print("** Warning: failed to load/write one or multiple items in ", self.keys())
137
+
138
+ return dict_to_save
139
+
140
+ def to_json(self, file_name=None):
141
+ """
142
+ Writes a json file with the SYNED object data.
143
+
144
+ Parameters
145
+ ----------
146
+ file_name : str
147
+ The file name
148
+
149
+ Returns
150
+ -------
151
+ str
152
+ JSON formatted str. The result of json.dumps()
153
+
154
+ """
155
+ dict1 = OrderedDict()
156
+ dict1.update(self.to_dictionary())
157
+
158
+ jsn1 = json.dumps(dict1, indent=4, separators=(',', ': '))
159
+ if file_name != None:
160
+ f = open(file_name,'w')
161
+ f.write(jsn1)
162
+ f.close()
163
+ print("File written to disk: %s"%(file_name))
164
+ return jsn1
165
+
166
+ def info_recurrent(self, fd, prefix=" "):
167
+ """
168
+ Get text info of recurrent SYNED objects.
169
+
170
+ Parameters
171
+ ----------
172
+ fd : dict
173
+ The dictionary with SYNED data.
174
+ prefix : str, optional
175
+ Prefix to indent recursive items.
176
+
177
+ Returns
178
+ -------
179
+ str
180
+
181
+ """
182
+ text = ""
183
+ prefix1 = prefix
184
+ for key in fd.keys():
185
+ if isinstance(fd[key],OrderedDict):
186
+ text += prefix1 + self.info_recurrent(fd[key], prefix=prefix1)
187
+ elif isinstance(fd[key],str):
188
+ text += prefix1 + "-------%s---------\n"%fd[key]
189
+ elif isinstance(fd[key],list):
190
+ if isinstance(fd[key][0],OrderedDict):
191
+ for element in fd[key]:
192
+ text += self.info_recurrent(element, prefix=prefix1)
193
+ elif isinstance(fd[key][0],list):
194
+ for i,element in enumerate(fd[key][0]):
195
+ try:
196
+ # text += "****\n"
197
+ text += prefix1 + element.info()
198
+ except:
199
+ text += ("%s%s[%d]: %s\n" %(prefix1, key, i, repr(element))) # used for conic coefficients
200
+ else:
201
+ text += prefix1 + prefix1 + '%s: %s %s # %s\n' %(key, repr(fd[key][0]), fd[key][1][1], fd[key][1][0])
202
+ else:
203
+ pass
204
+ return text
205
+
206
+ def info(self):
207
+ """
208
+ Get text info of recurrent SYNED objects.
209
+
210
+ Returns
211
+ -------
212
+ str
213
+
214
+ """
215
+ return self.info_recurrent( self.to_full_dictionary() )
216
+
217
+ def set_value_from_key_name(self,key,value):
218
+ """
219
+ Sets a value using its key value.
220
+
221
+ Parameters
222
+ ----------
223
+ key : str
224
+ The key for the value to modify.
225
+ value
226
+ The new value
227
+
228
+ """
229
+ if key in self.keys():
230
+ try:
231
+ exec("self._%s = value" % (key))
232
+ # print("Set variable %s to value: "%key + repr(value))
233
+ except:
234
+ raise ValueError("Cannot set variable %s to value: "%key + repr(value) )
235
+ else:
236
+ raise ValueError("Key %s not accepted by class %s"%(key,self.__class__.__name__))
237
+
238
+ def get_value_from_key_name(self, key):
239
+ """
240
+ Gets a value using its key value.
241
+
242
+ Parameters
243
+ ----------
244
+ key : str
245
+ The key for the value to retrieve.
246
+
247
+ """
248
+ try:
249
+ value = eval("self._%s" % (key))
250
+ return value
251
+ except:
252
+ raise ValueError("Cannot get variable %s: "%key)
253
+
254
+ def duplicate(self):
255
+ """
256
+ Returns a copy of the SYNED object instance.
257
+
258
+ Returns
259
+ -------
260
+ SynedObject instance
261
+ A copy of the object instance.
262
+
263
+ """
264
+ return copy.deepcopy(self)