|
HOPS
HOPS class reference
|
Classes | |
| class | _ConditionBuilder |
| class | Config |
Config - accumulates fringe-fitter control statements.
Methods on :class:`Config` are generated at construction time from the JSON
format dictionary supplied by ``MHO_PyControlEvaluator`` (the C++ side passes
the canonical ``control_format`` dict loaded from the installed ``.json`` files).
This keeps the control format defintion in one place (the .json format files), so
we don't need to update C++ and python-code to match each other. All new control
format definitions should go into:
'<hops>/source/cpp_src/Control/format/control_extensions'
Control statements are grouped into *conditional blocks* that mirror the
fourfit control DSL structure. Calls made outside any ``with cfg.IF()`` block
go into the implicit ``if true`` block. Calls inside a ``with`` block go into
a conditional block whose ``value`` array matches the DSL token
sequence (e.g. ``["station", "G"]``). Passing this information is crucial for
downstream operator configuration.
Boolean conditions are built with a 'fluent builder' object returned
by ``cfg.IF()``. That way the builder mirrors the DSL token grammar
directly, likewise: ``AND()``, ``OR()``, and ``NOT()`` inject boolean
operators, and the predicate methods (``station()``, ``baseline()``, etc.)
inject the corresponding operand for subsequent evaluation.
All this results in a syntax which is quite clunky, but the fourfit control
file DSL is very restrictive (and cannot support a full python-like grammar).
Futhermore, we also need to preserve the boolean conditionals that evaluate
to 'True' because parameters like 'station E' have to be passed to downstream
operations for later configuration, for example in order to identify if a
station-based operation should be applied to the referecne or remote station.
Example synatx:
def configure(p, cfg):
cfg.ref_freq(215000.0) # goes into the implicit if-true block
# DSL: if station G
with cfg.IF().station("G"):
cfg.sampler_delay_x([-140, 180, 180, 180])
# DSL: if baseline GE
with cfg.IF().baseline("GE"):
cfg.ion_npts(11)
# DSL: if source 3C279 and f_group X
with cfg.IF().source("3C279").AND().fgroup("X"):
cfg.ref_freq(86000.0)
# DSL: if station E and scan > 100-1200
with cfg.IF().station("E").AND().scan_after("100-1200"):
cfg.pc_amp_hcode(0.0001)
# DSL: if station E or station G
with cfg.IF().station("E").OR().station("G"):
cfg.weak_channel(0.05)
Convenience shortcuts (``cfg.if_station()``, ``cfg.if_baseline()``, etc.) are
also provided for the common single-predicate case and are equivalent to the
fluent form, for example:
with cfg.IF().station("E"):
cfg.weak_channel(0.05)
is equivalient to:
with cfg.if_station("E")
cfg.weak_channel(0.05);
Note! Conditional blocks may not be nested. If multiple predicates are needed,
combine them in one chain with ``AND()``, ``OR()``, and ``NOT()`` rather
than nesting multiple ``with cfg.IF()`` blocks. Nested blocks will raise and exception.