Global objects vs. deepcopy

In the above code, update_hilbertspace directly manipulates the two transmon instances via global variables. It is generally considered better programming style to avoid such use of global variables. To facilitate this, update_hilbertspace may be defined with an additional first argument that takes in the ParameterSweep object itself. This way, all HilbertSpace constituents can be accessed via

<ParameterSweep>.hilbertspace[<id_str>]:

[5]:
def update_hilbertspace(param_sweep, flux, ng):  # function that defines how Hilbert space components are updated
    param_sweep.hilbertspace["tmon1"].flux = flux
    param_sweep.hilbertspace["tmon2"].flux = area_ratio * flux
    param_sweep.hilbertspace["tmon2"].ng = ng

This way of updating is of particular interest when using the deepcopy option discussed next.

State after the sweep and using deepcopy

By default, the HilbertSpace object and its constituents will be left by ParameterSweep in a state reached with the last evaluation involved in the sweep. (When multiprocessing, this final state may not be easy to predict.)

Alternatively, the deepcopy option can be used to 1. disconnect all global `HilbertSpace constituents from the sweep,and 2. restore the HilbertSpace object stored internally with the ParameterSweep to the parameters prior to the sweep.

Without use of deepcopy, there is a good chance that, for example, the offset charge of tmon2 is now different than prior to the sweep. For deepcopy=True the global instances are disconnected from the sweep and remain untouched. The HilbertSpace object interior to sweep is restored to its original state, but remains a copy separate from the HilbertSpace object used to initialize ParameterSweep.