GithubHelp home page GithubHelp logo

dygdug's People

Contributors

brandondube avatar

Stargazers

 avatar

Watchers

 avatar  avatar  avatar

dygdug's Issues

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

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:

  1. how the user provides the forward sensitivity matricies (Jacobians, G)

  2. 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

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

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.

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.

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.

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.

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?

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)

Estimation

Pairwise probing, Kalman filters, etc...

EFC

Epic for electric field conjugation

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:

  1. if EFC gives us a flat vector of actuators, we make it square to make the DM model happy.
  2. 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:

  1. If we have pruned dead actuators (outside the pupil, e.g.) then the reshape trick breaks

  2. if there are multiple DMs, we need a way for EFC to pack all of their actuators into one vector

  3. 1D vs 2D representations

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo 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.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.