Skip to content

Commit 7315168

Browse files
committed
Merge pull request #655 from GalSim-developers/#218
#218 Make everything picklable
2 parents 7fa0391 + eef6d12 commit 7315168

File tree

151 files changed

+6598
-3145
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

151 files changed

+6598
-3145
lines changed

CHANGELOG.md

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,23 +13,44 @@ Installation Changes
1313
API Changes
1414
-----------
1515

16+
- Changed the name of the `bounds.addBorder()` method to `withBorder` to make
17+
it clearer that the method returns a new Bounds object. (#218)
18+
- Removed (from the python layer) Interpolant2d and InterpolantXY, since we
19+
we have only actually implemented 1-d interpolants. (#218)
20+
- Removed the MultipleImage way of constructing an SBInterpolatedImage, since
21+
we do not use it anywhere, nor are there unit tests for it. The C++ layer
22+
still has the implementation of it if we ever find a need for it. (#218)
23+
- Made the default tolerance for all Interpolants equal to 1.e-4. It already
24+
was for Cubic, Quintic, and Lanczos, which are the ones we normally use,
25+
so this just changes the default for the others. (#218)
26+
- Deprecated the __rdiv__ operator from Bandpass and SED, since we realized
27+
that they did not have any clear use cases. If you have one, please open an
28+
issue, and we can add them back. (#218)
29+
- Made all returned matrices consistently use numpy.array, rather than
30+
numpy.matrix. We had been inconsistent with which type different functions
31+
returned, so now all matrices are numpy.arrays. If you rely on the
32+
numpy.matrix behavior, you should recast with numpy.asmatrix(M). (#218)
1633
- Deprecated CorrelatedNoise.calculateCovarianceMatrix, since it is not used
1734
anywhere, and we think no one really has a need for it. (#630)
1835
- Officially deprecated the methods and functions that had been described as
1936
having been removed or changed to a different name. In fact, many of them
2037
had been still valid, but no longer documented. This was intentional to
2138
allow people time to change their code. Now these methods are officially
2239
deprecated and will emit a warning message if used. (#643)
23-
- Made the classes PositionI, PositionD, and GSParams immutable. It was an
24-
oversight that we failed to make them immutable in version 1.1 when we made
25-
most other GalSim classes immutable. Now rather than write to their various
26-
attributes, you should make a new object. e.g. instead of `p.x = 4` and
27-
`p.y = 5`, you now need to do `p = galsim.PositionD(4,5)`. (#643)
40+
- Made the classes PositionI, PositionD, GSParams, and HSMParams immutable.
41+
It was an oversight that we failed to make them immutable in version 1.1 when
42+
we made most other GalSim classes immutable. Now rather than write to their
43+
various attributes, you should make a new object. e.g. instead of `p.x = 4`
44+
and `p.y = 5`, you now need to do `p = galsim.PositionD(4,5)`. (#218, #643)
2845

2946

3047
New Features
3148
------------
3249

50+
- Added ability to set the zeropoint of a bandpass on construction. (Only
51+
a numeric value; more complicated calculations still need to use the method
52+
`bandpass.withZeropoint()`.) (#218)
53+
- Added ability to set the redshift of an SED on construction. (#218)
3354
- Updated CorrelatedNoise to work with images that have a non-trivial WCS. (#501)
3455
- Added new methods of the image class to simulate detector effects:
3556
inter-pixel capacitance (#555) and image quantization (#558).
@@ -65,6 +86,7 @@ New Features
6586
Bug Fixes and Improvements
6687
--------------------------
6788

89+
- Fixed a bug in the normalization of SEDs that use `wave_type='A'`. (#218)
6890
- Switched the sign of the angle returned by `CelestialCoord.angleBetween`.
6991
The sign is now positive when the angle as seen from the ground sweeps in
7092
the counter-clockwise direction, which is a more sensible definition than

examples/demo7.py

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
- obj = galsim.Sersic(n, half_light_radius, trunc)
3838
- psf = galsim.OpticalPSF(..., aberrations=aberrations, ...)
3939
- obj = obj.dilate(scale)
40+
- str(obj)
4041
- image.scale = pixel_scale
4142
- obj.drawImage(image, method='fft')
4243
- obj.drawImage(image, method='phot', max_extra_noise, rng)
@@ -69,6 +70,9 @@ def main(argv):
6970
# To turn off logging:
7071
#logger.propagate = False
7172

73+
# To turn on the debugging messages:
74+
#logger.setLevel(logging.DEBUG)
75+
7276
# Define some parameters we'll use below.
7377

7478
# Make output directory if not already present.
@@ -200,11 +204,23 @@ def main(argv):
200204
for ipsf in range(len(psfs)):
201205
psf = psfs[ipsf]
202206
psf_name = psf_names[ipsf]
207+
logger.info('psf %d: %s',ipsf+1,psf)
208+
# Note that this implicitly calls str(psf). We've made an effort to give all GalSim
209+
# objects an informative but relatively succinct str representation. Some details may
210+
# be missing, but it should look essentially like how you would create the object.
211+
logger.debug('repr = %r',psf)
212+
# The repr() version are a bit more pedantic in form and should be completely informative,
213+
# to the point where two objects that are not identical should never have equal repr
214+
# strings. As such the repr strings may in some cases be somewhat unwieldy. For instance,
215+
# since we set non-default gsparams in these, the repr includes that information, but
216+
# it is omitted from the str for brevity.
203217
for igal in range(len(gals)):
204218
gal = gals[igal]
205219
gal_name = gal_names[igal]
220+
logger.info(' galaxy %d: %s',igal+1,gal)
221+
logger.debug(' repr = %r',gal)
206222
for i in range(4):
207-
logger.debug('Start work on image %d',i)
223+
logger.debug(' Start work on image %d',i)
208224
t1 = time.time()
209225

210226
# Initialize the random number generator we will be using.
@@ -240,7 +256,7 @@ def main(argv):
240256
fft_image = image[galsim.BoundsI(1, nx, 1, ny)]
241257
phot_image = image[galsim.BoundsI(nx+3, 2*nx+2, 1, ny)]
242258

243-
logger.debug(' Read in training sample galaxy and PSF from file')
259+
logger.debug(' Read in training sample galaxy and PSF from file')
244260
t2 = time.time()
245261

246262
# Draw the profile
@@ -252,7 +268,7 @@ def main(argv):
252268
# for illustrative purposes.)
253269
final.drawImage(fft_image, method='fft')
254270

255-
logger.debug(' Drew fft image. Total drawn flux = %f. .flux = %f',
271+
logger.debug(' Drew fft image. Total drawn flux = %f. .flux = %f',
256272
fft_image.array.sum(),final.getFlux())
257273
t3 = time.time()
258274

@@ -285,17 +301,17 @@ def main(argv):
285301
# image, we need to subtract the mean back off when we are done.
286302
phot_image -= sky_level_pixel
287303

288-
logger.debug(' Added Poisson noise. Image fluxes are now %f and %f',
304+
logger.debug(' Added Poisson noise. Image fluxes are now %f and %f',
289305
fft_image.array.sum(), phot_image.array.sum())
290306
t6 = time.time()
291307

292308
# Store that into the list of all images
293309
all_images += [image]
294310

295311
k = k+1
296-
logger.info('%d: %s * %s, flux = %.2e, hlr = %.2f, ellip = (%.2f,%.2f)',
297-
k,gal_name, psf_name, flux, hlr, gal_shape.getE1(), gal_shape.getE2())
298-
logger.debug(' Times: %f, %f, %f, %f, %f',t2-t1, t3-t2, t4-t3, t5-t4, t6-t5)
312+
logger.info(' %d: flux = %.2e, hlr = %.2f, ellip = (%.2f,%.2f)',
313+
k, flux, hlr, gal_shape.getE1(), gal_shape.getE2())
314+
logger.debug(' Times: %f, %f, %f, %f, %f',t2-t1, t3-t2, t4-t3, t5-t4, t6-t5)
299315

300316
psf_times[ipsf] += t6-t1
301317
psf_fft_times[ipsf] += t3-t2

galsim/__init__.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -95,9 +95,11 @@
9595
# To make this seamless with pyfits versions, we add 4 to the astropy version.
9696
from astropy import version as astropy_version
9797
pyfits_version = str( (4 + astropy_version.major) + astropy_version.minor/10.)
98+
pyfits_str = 'astropy.io.fits'
9899
except:
99100
import pyfits
100101
pyfits_version = pyfits.__version__
102+
pyfits_str = 'pyfits'
101103

102104
# Import things from other files we want to be in the galsim namespace
103105

@@ -126,17 +128,18 @@
126128
from real import RealGalaxy, RealGalaxyCatalog, simReal
127129
from optics import OpticalPSF
128130
from shapelet import Shapelet, ShapeletSize, FitShapelet
129-
from interpolatedimage import Interpolant, Interpolant2d, InterpolantXY
131+
from interpolatedimage import Interpolant
130132
from interpolatedimage import Nearest, Linear, Cubic, Quintic, Lanczos, SincInterpolant, Delta
131133
from interpolatedimage import InterpolatedImage
132134
from compound import Add, Sum, Convolve, Convolution, Deconvolve, Deconvolution
133135
from compound import AutoConvolve, AutoConvolution, AutoCorrelate, AutoCorrelation
136+
from transform import Transform, Transformation
134137

135138
# Chromatic
136139
from chromatic import ChromaticObject, ChromaticAtmosphere, Chromatic, ChromaticSum
137140
from chromatic import ChromaticConvolution, ChromaticDeconvolution, ChromaticAutoConvolution
138-
from chromatic import ChromaticAutoCorrelation
139-
from chromatic import ChromaticOpticalPSF, ChromaticAiry
141+
from chromatic import ChromaticAutoCorrelation, ChromaticTransformation
142+
from chromatic import ChromaticOpticalPSF, ChromaticAiry, InterpolatedChromaticObject
140143
from sed import SED
141144
from bandpass import Bandpass
142145

galsim/angle.py

Lines changed: 27 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -43,24 +43,26 @@
4343
"""
4444

4545
def AngleUnit_repr(self):
46-
if self is galsim.radians:
46+
if self == galsim.radians:
4747
return 'galsim.radians'
48-
elif self is galsim.degrees:
48+
elif self == galsim.degrees:
4949
return 'galsim.degrees'
50-
elif self is galsim.hours:
51-
return 'galsim.house'
52-
elif self is galsim.arcmin:
50+
elif self == galsim.hours:
51+
return 'galsim.hours'
52+
elif self == galsim.arcmin:
5353
return 'galsim.arcmin'
54-
elif self is galsim.arcsec:
54+
elif self == galsim.arcsec:
5555
return 'galsim.arcsec'
5656
else:
57-
return 'galsim.AngleUnit(' + str(self.getValue()) + ')'
57+
return 'galsim.AngleUnit(%r)'%self.getValue()
5858
AngleUnit.__repr__ = AngleUnit_repr
59+
AngleUnit.__eq__ = lambda self, other: (
60+
isinstance(other,AngleUnit) and self.getValue() == other.getValue())
61+
AngleUnit.__ne__ = lambda self, other: not self.__eq__(other)
62+
AngleUnit.__hash__ = lambda self: hash(self.getValue())
5963

6064
# Enable pickling
61-
def AngleUnit_getinitargs(self):
62-
return self.getValue()
63-
AngleUnit.__getinitargs__ = AngleUnit_getinitargs
65+
AngleUnit.__getinitargs__ = lambda self: (self.getValue(), )
6466

6567

6668
def get_angle_unit(unit):
@@ -150,6 +152,15 @@ def get_angle_unit(unit):
150152
of the allowed operations on Angles listed above (e.g., addition/subtraction of Angles,
151153
multiplication of an Angle by a float, but not multiplication of Angles together).
152154
155+
There are convenience function for getting the sin, cos, and tan of an angle, along with
156+
one for getting sin and cos together, which should be more efficient than doing sin and
157+
cos separately:
158+
159+
>>> sint = theta.sin() # equivalent to sint = math.sin(theta.rad())
160+
>>> cost = theta.cos() # equivalent to sint = math.cos(theta.rad())
161+
>>> tant = theta.tan() # equivalent to sint = math.tan(theta.rad())
162+
>>> sint, cost = theta.sincos()
163+
153164
Wrapping
154165
--------
155166
@@ -163,16 +174,12 @@ def get_angle_unit(unit):
163174
164175
"""
165176

166-
def __str__(self):
167-
angle_rad = self.rad()
168-
return str(angle_rad)+" radians"
169-
170-
def __repr__(self):
171-
angle_rad = self.rad()
172-
return str(angle_rad)+" * galsim.radians"
173-
174-
def __neg__(self):
175-
return -1. * self
177+
Angle.__str__ = lambda self: str(self.rad()) + ' radians'
178+
Angle.__repr__ = lambda self: 'galsim.Angle(%r, galsim.radians)'%self.rad()
179+
Angle.__eq__ = lambda self, other: isinstance(other,Angle) and self.rad() == other.rad()
180+
Angle.__ne__ = lambda self, other: not self.__eq__(other)
181+
Angle.__neg__ = lambda self: -1. * self
182+
Angle.__hash__ = lambda self: hash(repr(self))
176183

177184
def _make_dms_string(decimal, sep):
178185
if decimal >= 0:
@@ -246,9 +253,6 @@ def dms(self, sep=":"):
246253
d = self.wrap() / galsim.degrees
247254
return _make_dms_string(d,sep)
248255

249-
Angle.__str__ = __str__
250-
Angle.__repr__ = __repr__
251-
Angle.__neg__ = __neg__
252256
Angle.hms = hms
253257
Angle.dms = dms
254258

0 commit comments

Comments
 (0)