Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Tickets/dm 9229 #54

Merged
merged 4 commits into from Apr 3, 2017
Merged

Tickets/dm 9229 #54

merged 4 commits into from Apr 3, 2017

Conversation

yalsayyad
Copy link
Contributor

No description provided.

lenPsfScience = lenMax if self.config.padPsf else lenMin
dimenS = afwGeom.Extent2I(lenPsfScience, lenPsfScience)
if self.config.doAutoPadPsf:
minPsfSize = nextOddInteger(self.kConfig.kernelSize*self.config.autoPadPsfTo)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It may not be necessary, as this function is only called a small number of times, but it is possible to avoid all the overhead of calling a function, and the steps in the function by saying:
minPsfSize = int(np.ceil(self.KConfig.kernelSize*self.config.autoPadPsfTo))|1
This will return the number if it is odd, or the next integer if it is even

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I acknowledge two suggestions here: (1) to take the minPsfSize calculation out of a function and (2) to switch the last bit to 1 to get the next odd integer.
1: This function is not in a loop and only called once. My rationale for putting it in a function was to reduce code duplication with the unit test. If you argue that unit tests should calculate it differently, then I'll take it out of the function.
2: Flipping the last bit to 1 smells clever to me, because it doesn't read like english.

The function plus english-reading % 2 version also appears to be (counterintuitively) faster, but a microsecond (or even 100 milliseconds) won't make a difference in a long task like ModelPsfMatch:

import timeit

setupBitFlip = """
from random import random
import numpy as np
def nextOddInt(x):
    return int(np.ceil(x))|1

def genKRand():
    for i in range(1000):
        yield 10*random()
"""

setupIfMod = """
from random import random
import numpy as np

def genKRand():
    for i in range(1000):
        yield 10*random()

def nextOddInt(x):
    return x if x % 2 == 0 else x + 1
"""

print('%.02f us'% (1000*timeit.timeit('[nextOddInt(y) for y in genKRand()]', setup=setupIfMod, number=10)/10.))
# 0.63 us
print('%.02f us'% (1000*timeit.timeit('[nextOddInt(y) for y in genKRand()]', setup=setupBitFlip, number=10)/10.))
# 1.26 us
print('%.02f us'% (1000*timeit.timeit('[int(np.ceil(y))|1 for y in genKRand()]', setup=setupBitFlip, number=10)/10.))
# 1.07 us

# Single value
print('%.02f us'%(timeit.timeit('nextOddInt(3.4)', setup=setupIfMod, number=1000000)))
# 0.35 us
print('%.02f us'%(timeit.timeit('nextOddInt(3.4)', setup=setupBitFlip, number=1000000)))
# 0.99 us
print('%.02f us'%(timeit.timeit('int(np.ceil(3.4))|1', setup=setupBitFlip, number=1000000)))
# 0.82 us

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The speed difference here comes from setupBitFlip using int(np.ceil( and setupIfMod not, it seems to just be doing the mod on whatever type that x is. Over all I don't have a strong feeling on this and reuse in the unit test is a good enough argument for me.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, whoops. Let me update those last times for posterity:

# # Single value UPDATED
print('%.02f us'%(timeit.timeit('nextOddInt(3.4)', setup=setupIfMod, number=1000000)))
# 1.23 us
print('%.02f us'%(timeit.timeit('nextOddInt(3.4)', setup=setupBitFlip, number=1000000)))
# 1.02 us
print('%.02f us'%(timeit.timeit('int(np.ceil(3.4))|1', setup=setupBitFlip, number=1000000)))
# 0.87 us

sigma2fwhm = 2. * num.sqrt(2. * num.log(2.))


def nextOddInteger(x):
nextInt = int(num.ceil(x))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please change the import to import numpy as np, as it is what the community has settled on, and it will make this file more consistent with the rest of the stack which uses that import.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 (but on a separate commit because it is independent of this ticket)

doAutoPadPsf = pexConfig.Field(
dtype=bool,
doc=("Automatically pad science PSF to minimum dimensions appropriate for the kernel. "
"If the Science Psf is smaller than a the matching kernel + a minimum fraction. "
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove either "a" or "the" and change + to "add" or "pad by" the sentence is a bit confusing on the first read. I read it as "If the Science Psf is smaller than (the matching kernel + a minimum fraction)"

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

paddingPix = max(0, minPsfSize - psfSize)
else:
if self.config.padPsfBy % 2 != 0:
raise ValueError("Config padPsfBy (%i pixels) must be even number." %
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it worth just moving to the next even number rather than throwing an error? Or maybe being explicit is good, like you have it. If the algorithm must have an even to work, perhaps move to the next even number and put out a warning? What you have is fine, these are just some things for you to consider.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I considered that. My reasoning for raising an error is that when setting doAutoPadPsf=False, I presume the user has reasons for turning off the automatic tuning, and thus wants exact manual control over the configs and wants ModelPsfMatchTask to just do exactly what they ask of it or quit. The behavior is consistent: Kernel too big? Raise. Padding inappropriately odd? Raise. I suspect this config option will only be used when users want precise control such as for testing config parameters like you did for the HSC image

@@ -7,6 +7,7 @@
import lsst.ip.diffim as ipDiffim
import lsst.log.utils as logUtils
import lsst.meas.algorithms as measAlg
from lsst.ip.diffim.modelPsfMatch import nextOddInteger
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you changed to the binary operator in the other file, remember to change where the function is used here as well

In modelPsfMatchTask, padPsf controlled whether users
want to either clip or pad the Warped Psf to a standard size.
We should always pad.
@yalsayyad yalsayyad force-pushed the tickets/DM-9229 branch 2 times, most recently from 5a8797d to 63a9b50 Compare April 3, 2017 19:16
Add three config parameters to ModelPsfMatchTask that
enable automatic or manual padding of the science PSF before matching
to a model PSF. By default, doAutoPadPsf is set to True and will
automatically pad the PSF to the minimum size appropriate,
as defined by the config autoPadPsfTo (in units of the kernel size).
If doAutoPadPsf is set to False, science PSFs will be padded by the
padPsfBy number of pixels.
@yalsayyad yalsayyad merged commit edbf328 into master Apr 3, 2017
@ktlim ktlim deleted the tickets/DM-9229 branch August 25, 2018 06:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants