Skip to content

Commit

Permalink
Improve state handling when using metastates and add better documenta…
Browse files Browse the repository at this point in the history
…tion and comments
  • Loading branch information
Evan Goetz committed Mar 17, 2023
1 parent b10b53c commit 77d68ed
Show file tree
Hide file tree
Showing 4 changed files with 84 additions and 10 deletions.
19 changes: 14 additions & 5 deletions gwsumm/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -307,21 +307,30 @@ def load_states(self, section='states'):
"""
from .state import (register_state, SummaryState, SummaryMetaState,
ALLSTATE, generate_all_state, get_state)
# parse the [states] section into individual state definitions
# Parse the [states] section into individual state definitions.
# Each state definition is amended to the GWSummConfigParser as a new
# section with name and definition key-value pairs.
try:
states = dict(self.nditems(section))
except configparser.NoSectionError:
self.add_section(section)
states = {}
for state in states:
if not (self.has_section('state-%s' % state) or
self.has_section('state %s' % state)):
section = 'state-%s' % state
if not (self.has_section(f'state-{state}') or
self.has_section(f'state {state}')):
section = f'state-{state}'
self.add_section(section)
self.set(section, 'name', state)
self.set(section, 'definition', states[state])

# parse each state section into a new state
# Parse each state section into a new state.
# Here we reset the states variable to an empty list because the
# previous code block added all of the states section into their own
# sections [state-<state>]. We register those states and metastates,
# appending them also to the states list. Metastates are states that
# use another state definition, where they look for the key name. If
# key is not defined, then name is used instead. The key or name is
# expected to have an 'H1-' or 'L1-' prefix.
states = []
for section in self.sections():
if re.match(r'state[-\s]', section):
Expand Down
17 changes: 15 additions & 2 deletions gwsumm/plot/builtin.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
"""

import os.path
import re
import warnings
from itertools import cycle

Expand Down Expand Up @@ -498,19 +499,31 @@ def _draw(self):
else:
iterator = list(zip(self.channels, plotargs))

# loop over the channels
for chantuple in iterator:
channel = chantuple[0]
channel2 = chantuple[1]
pargs = chantuple[-1]

# get the state or segment
if self.state and not self.all_data:
valid = self.state
else:
valid = SegmentList([self.span])

# If the state is a metastate, then get the corresponding IFO-
# specific state from the global variables list
if isinstance(valid, SummaryMetaState):
valid = globalv.STATES[
f'{channel.ifo}-{valid.uses[0][3:]}'.lower()]
reg = re.compile(channel.ifo)
matching = list(filter(reg.match, valid.uses))
assert len(matching) == 1, (
f"Failed to find a unique state for {valid.name} "
f"metastate. Found {len(matching)} matching states in "
f"{valid.uses} for {channel.ifo}")
try:
valid = globalv.STATES[matching[0].lower()]
except KeyError:
raise

if self.type == 'coherence-spectrum':
data = get_coherence_spectrum(
Expand Down
56 changes: 53 additions & 3 deletions gwsumm/state/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -352,11 +352,43 @@ def __str__(self):


class SummaryMetaState(SummaryState):
"""A meta state where different states may be used"""
"""A meta state where different states may be used when processing a
`~gwsumm.tabs.DataTab`.
def __init__(self, name, known=SegmentList(), active=SegmentList(),
An example use ase is when one wants to plot two different state times on
the same plot. This currently has limitations as it expects the states to
be from different detectors. So when using this metastate, each value in
"uses" needs to be prefixed by "<IFO>"
Parameters
----------
name : `str`
name for this state
uses : `list`
list of strings for which states to use. Ex.: ['H1-quiet', 'L1-quiet']
known : `~gwpy.segments.SegmentList`, optional
list of known segments
active : `~gwpy.segments.SegmentList`, optional
list of active segments
description : `str`, optional
text describing what this state means
definition : `str`, optional
logical combination of flags that define known and active segments
for this state (see :attr:`documentation <SummaryState.definition>`
for details)
hours : `str`, optional
a string of the form "<start>-<end>,<IFO|utc|local>"
key : `str`, optional
registry key for this state, defaults to :attr:`~SummaryState.name`
filename : `str`, optional
path to filename with segments
url : `str`, optional
URL to read the segments
"""

def __init__(self, name, uses, known=SegmentList(), active=SegmentList(),
description=None, definition=None, hours=None, key=None,
filename=None, url=None, uses=[]):
filename=None, url=None):

super(SummaryMetaState, self).__init__(
name=name, known=known, active=active,
Expand All @@ -367,6 +399,21 @@ def __init__(self, name, known=SegmentList(), active=SegmentList(),

@classmethod
def from_ini(cls, config, section):
"""Create a new `SummaryMetaState` from a section in a `ConfigParser`.
Parameters
----------
config : :class:`~gwsumm.config.GWConfigParser`
customised configuration parser containing given section
section : `str`
name of section to parse
Returns
-------
`SummaryMetaState`
a new state, with attributes set from the options in the
configuration
"""
config = GWSummConfigParser.from_configparser(config)
# get parameters
params = dict(config.nditems(section))
Expand All @@ -384,6 +431,9 @@ def fetch(self, config=GWSummConfigParser(),
segmentcache=None, segdb_error='raise',
datacache=None, datafind_error='raise', nproc=1, nds=None,
**kwargs):
"""Finalise this state by fetching the states this metastate uses,
either from global memory, or from the segment database
"""

for idx, state in enumerate(self.uses):
globalv.STATES[state.lower()].fetch(
Expand Down
2 changes: 2 additions & 0 deletions gwsumm/tabs/data.py
Original file line number Diff line number Diff line change
Expand Up @@ -357,6 +357,8 @@ def process(self, config=ConfigParser(), nproc=1, **stateargs):
datafind_error=stateargs.get('datafind_error', 'raise'),
nproc=nproc, nds=stateargs.get('nds', None))
vprint("States finalised [%d total]\n" % len(self.states))

# loop over states for this tab and print out information
for state in self.states:
if isinstance(state, SummaryMetaState):
vprint(
Expand Down

0 comments on commit 77d68ed

Please sign in to comment.