dygdug's People
dygdug's Issues
Error using F77LBFGSB class in optim.py, '_lbfgsb' has no attribute 'types'
Attempting to use the F77LBFGSB class with the VAPPOptimizer. Encountering an error at this line in the class
fint_dtype = _lbfgsb.types.intvar.dtype
This is the error:
AttributeError: module 'scipy.optimize._lbfgsb' has no attribute 'types'
Code to Reproduce Error
from prysm import coordinates, geometry
from prysm.propagation import Wavefront as WF
from prysm.polynomials import noll_to_nm,zernike_nm_sequence
rap = 1.25
x, y = coordinates.make_xy_grid(256, diameter=10)
r, t = coordinates.cart_to_polar(x, y)
dx = x[0,1]-x[0,0]
ap = geometry.circle(rap, r)
ap = ap / np.sqrt(ap.sum())
wvl = 0.551
efl = 100
fno = efl/(2*rap)
lamD = wvl*fno
wf = WF.from_amp_and_phase(ap, None, wvl, dx)
psf = wf.focus(Q=1, efl=efl).intensity
xx, yy = psf.x, psf.y
xx = xx / lamD
yy = yy / lamD
rr, tt = coordinates.cart_to_polar(xx, yy)
dh_mask = (xx > 2) & (rr<16)
nms = list(noll_to_nm(j) for j in range(4, 250))
basis = np.array(list(zernike_nm_sequence(nms, r/rap, t)))
x0 = np.zeros(len(nms))
ap = geometry.circle(rap, r)
# norm = np.sqrt(vapp.I.max())
# ap = ap / norm
vapp = vap.VAPPOptimizer(ap, wvl, basis, dh_mask, dh_target=0)
result = vapp.fg(x0)
opt = F77LBFGSB(vapp.fg, x0, memory=50)
Polychromatic control
As-is, the implementation of EFC is (by design) for a single control wavelength, since it is the simplest case. However, broad-band control is a necessity.
This raises the following points:
-
how the user provides the forward sensitivity matricies (Jacobians, G)
-
how the EFC class passes information about the wavelengths to the coronagraph model
These need to be thought through, and we need to remember that there are other aspects such as spatial weighting, or bandpass weighting, which will interact with the linear algebra within EFC
Use Beta for TIkhonov regularization, instead of rcond
rcond is the language from numpy, but beta permeates the literature and is just log10(rcond)
. We should take beta as a parameter and do the log10 internally
Vortex Coronagraph
I've been after a GPU-compatible vortex coronagraph for a while and know that dygdug's is currently in progress/prysm is GPU compatible. What is the status of dygdug's vortex coronagraph?
Awkward and inefficient actuator array juggling
As-is, within dygdug and prysm we have:
# prysm DM, update
dm.actuators[:] = actuators[:]
dm.render()
This interface predominantly stems from wanting the DM to be like something in real life and "own" the actuator array. The [:]
syntax is just a way for copying elements without changing the actual array itself, which allows the DM object to keep ownership of "its" array, although this seems to be a very pedantic point and not one that really matters.
Then we need a mechanism for the outside user to update the DM(s) in a coronagraph model, and we have:
# dygdug SingleDMLyotCoronagraph
def update_dm(self, actuators):
self.dm.actuators[:] = actuators.reshape(self.dm.actuators.shape)[:]
self.dm_wfe = fttools.pad2d(self.dm.render(wfe=True), out_shape=self.Nmodel)
return
This serves two purposes:
- if EFC gives us a flat vector of actuators, we make it square to make the DM model happy.
- the DM model does not have to be prysm
As a side effect we also embed the necessary pad or crop to get to the same array size as the rest of the model. Maybe that should get pushed inside prysm's DM type; it seems reasonable to do so.
EFC uses this as:
y = self.Gstar.dot(Ew)
self.act_cmds -= self.loop_gain * y
old_wfe = self.c.dm_wfe
self.c.update_dm(self.act_cmds)
So we basically have three types, all having their own concept of an array or interface for the DM.
In merging them we have to deal with the following issues:
-
If we have pruned dead actuators (outside the pupil, e.g.) then the reshape trick breaks
-
if there are multiple DMs, we need a way for EFC to pack all of their actuators into one vector
-
1D vs 2D representations
Too many simultaneously provided input parameters
The definition for the simple Lyot coronagraph is:
class LyotCoronagraphSingleDM:
def __init__(self, Nmodel, Npup, Nlyot, Nfpm, Nimg, Dpup, fpm_oversampling, image_oversampling, rFPM, wvl0, fno, data_root, ifn_fn, iwa, owa, start_az, end_az):
which is 16 or so parameters given at once. This is too many for users to not fry their brains. Without thinking too hard, this can be divided in 3 or 4 by breaking up the specification for the pupil, FPM, lyot stop, and final image. Then the definition of a Lyot coronagraph might look like:
class LyotCoronagraphSingleDM:
def __init__(self, input_pupil, fpm, lyot_stop, final_image):
This seems much simpler, and the various chunks are like legos that can be reused in other coronagraph models
Point designs are great for facilitating discussion, but let's discuss more thoroughly before "finishing" any particular implementation
Model idioms
Standard "idioms" for models
EFC
Epic for electric field conjugation
Single DM Lyot Coronagraph
This is the simplest possible coronagraph model and serves as a testbed for experimenting with designs before implementing shaped pupil, etc
Overly rigid
As-is, the user has to specify "beta" (or 10**beta, anyway) up-front and can't change it. That means they have to make a new EFC class, which may have some overhead. For example, we could store Vt and U and not compute them again, it is just a different S_inv = ...
.
Something ~=
class EFC:
def update_beta(self, b):
pass
would be nice to have
As well, the selection of pixels for the dark hole happens during the jacobian calculation step. Building that matrix is very costly (comparatively), so we should keep all of the pixels and move the dark hole mask into EFC or other controllers, and allow the user to change it later.
The same goes for the G -> G2
nonsense; the user shouldn't have to do it; it should go inside the EFC class' inner workings.
Multiple DMs
For broad-band and/or two-sided ("full" or "round" dark hole) control, two DMs are required. The single DM Lyot Coronagraph model only has one. To support multiple DMs, both the Jacobian routines, and EFC need to know how to access multiple DMs.
Estimation
Pairwise probing, Kalman filters, etc...
EFC governors / control strategies
In more general theory, sometimes you might see the term "governor" for something that regulates a control or optimization process. "Control strategies" is also somewhat common terminology to describe the process of "kicking" beta once in a while. The interface now is last_wfe, last_field = e.step()
where last_wfe is the DM map (this will necessarily change when there are multiple DMs) and last_field is the intensity of the E-field at the beginning of the step.
This interface is already somewhat awkward, since after a step happens you have information about the input state to the step, but there is not so much that can be done about it; step() doesn't know about the field that comes next.
Anyway, if you want to do beta kicking, you have to write code something like this:
for i in tqdm(range(50)):
if (i != 0 and ((i % 5) == 0)):
efc.beta = -5
efc.regularize_control_matrix()
just_kicked = True
else:
if just_kicked:
efc.beta = -2.5
efc.regularize_control_matrix()
just_kicked = False
wfe, fld = efc.step()
This is error prone, for example missing the i!=0
clause will kick beta on iter 0. We should make governors for common cases, so that user can just do something like b = BetaKicker(every=5); b.run(e)
to kick beta every 5 iterations, or some other set of initializers e.g., b = BetaKicker(on_iter=[5,10,20,40,80]
.
This hypothetical beta kicker should know about the EFC interface.
Central Differences Jacobian
As-is, dygdug just has the forward difference method of calculating a derivative,
dydx = (f(x0 + Delta) - f(x0)) / Delta
We should also implement the central differences
dydx = (f(x0 + Delta) - (fx0 - Delta) / (2*Delta)
Loggers
Related to #12
Logging information, and/or live updates should also be made easy to do. Maybe betakicker takes a callback to push state to on every iteration; that callback can do all sorts of stuff; save to memory, to disk, update a plot, and so on. We could define a suite of standard callbacks, too (this should be a standard issue). That opens us to make standard dashboards, too, but that seems like it's probably doable. Maybe we could make a fancy web GUI that way N people could watch EFC progress at the same time.
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. ๐๐๐
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google โค๏ธ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.