# 5. Configuration files¶

## 5.1. Overview¶

Pyfusion uses simple text files to store information such as data acquisition settings, diagnostic coordinates, SQL database configurations, etc. A pyfusion configuration file looks something like this:

# Some comments are indented below to show the actual options better
# Indentation of comments is only allowed in version 0.6 onwards

[global]
# this section is a pyfusion feature to hold values that are universal
# These values have to be specifically queried.
database = sqlite:///:memory:
tmpdir = /tmp

[DEFAULT]
# This section is a standard configparser feature, and supplies
#  options to all sections.  The main use is to define substitutions
H1fetcher = pyfusion.acquisition.H1.fetch.H1DataFetcher
# The presence of these options or "keys" in all other sections can be
# annoying, and future versions may use ExtendedInterpolation to
# separate interpolations, thereby reducing key 'pollution'.

[Device:H1]
dev_class = pyfusion.devices.H1.device.H1
acq_name = MDS_h1

[Acquisition:MDS_h1]
acq_class = pyfusion.acquisition.MDSPlus.acq.MDSPlusAcquisition
server = h1data.anu.edu.au

[CoordTransform:H1_mirnov]
magnetic = pyfusion.devices.H1.coords.MirnovKhMagneticCoordTransform

[Diagnostic:H1_mirnov_array_1_coil_1]
data_fetcher = pyfusion.acquisition.H1.fetch.H1DataFetcher
mds_path = \h1data::top.operations.mirnov:a14_14:input_1
coords_cylindrical = 1.114, 0.7732, 0.355
coord_transform = H1_mirnov

[Diagnostic:H1_mirnov_array_1_coil_2]
# example using interpolation or substitution instead of literal
data_fetcher = $(H1_fetcher)s mds_path = \h1data::top.operations.mirnov:a14_14:input_2 coords_cylindrical = 1.185, 0.7732, 0.289 coord_transform = H1_mirnov [Diagnostic:H1_mirnov_array_1_coil_3] data_fetcher = pyfusion.acquisition.H1.fetch.H1DataFetcher mds_path = \h1data::top.operations.mirnov:a14_14:input_3 coords_cylindrical = 1.216, 0.7732, 0.227 coord_transform = H1_mirnov [Diagnostic:H1_mirnov_array_1] data_fetcher = pyfusion.acquisition.base.MultiChannelFetcher channel_1 = H1_mirnov_array_1_coil_1 channel_2 = H1_mirnov_array_1_coil_2 # This next line corrects a phase flip error # better to do this in the multi-channel diag - more flexible and # works well with local data in *npz files. channel_3 = -H1_mirnov_array_1_coil_3  There are two types of sections in this file: there are two special sections (global, DEFAULT) and several component sections (e.g. Device:H1, Acquisition:MDS_h1, CoordTransform:H1_mirnov, etc.) See Configparser basics which includes some syntax rules. The sections in the configuration (except for [variabletypes]) file have the syntax [Component:name], where Component is one of: Acquisition, Device, Diagnostic. When instantiating a class, such as Device, Acquisition, Diagnostic, etc. which looks in the configuration file for settings, individual settings can be overridden using the corresponding keyword arguments. For example, Device('my_device') will use settings in the [Device:my_device] configuration section, and Device('my_device', database='sqlite://') will override the database configuration setting with sqlite:// (a temporary in-memory database). The pyfusion configuration parser pyfusion.conf.PyfusionConfigParser is a simple subclass of the standard python configparser, for example, to see the configuration sections, type: pyfusion.config.sections()  ## 5.2. Valid Shots¶ A new feature allows configuration to change for different shot ranges. Initially the shots work back from the latest config. If for a particular diagnostic, the shot is outside the valid_shots, then alternate diag names such as W7XM1_L53_LP02_I are checked for in the config file. If found, and the shot range matches, we are finished. Otherwise an error is generated. A second modification (M2) builds on the first (M1), so the effect is cumulative. If a diagnostic is missing on a day, it will have to be restored on the previous day. Diagnostics can be suppressed for now by setting DMD=0, so all the other charactersitics remain, so it can be easily restored. 1/ If a single channel diagnostic has no ‘valid_shots’, the value of its .acq valid_shots is used. 2/ If a shot is requested outside the valid range, a series of modifier diagnostic entries Mn, where n is an integer are searched for until one with a valid_shot range which includes that shot. An extract from pyfusion.cfg as an example: [Acquisition:W7X] acq_class = pyfusion.acquisition.W7X.acq.W7XAcquisition domain = ipp-hgw.mpg.de # Look for this string in the list of name servers for domain - if not found, # then the URL is probably not accessible through this connection. # Avoids an unnecessary (long) wait to see error messages. lookfor = sv valid_shots = L53_LP_from=20160122,L53_LP_to=20160310,L57_LP_from=20160122,L57_LP_to=20160310 ----- further down in the file ---- [Diagnostic:W7X_L53_LP05_I] valid_shots = L53_LP_from=20160223,L53_LP_to=20160310 coords_w7_x_koord = 1.72390, -5.41380, 0.21680 area = 0.963e-06 sweepv = W7X_L53_LP01_U gain = %(1Ohm)s data_fetcher = %(W7Xfetcher)s params = CDS=82,DMD=190,ch=0 [Diagnostic:W7XM1_L53_LP05_I] #The first modification says for the shots from 1/22 to 2/18, use a different DMD (digitiser box address) valid_shotss = L53_LP_from=20160122,L53_LP_to=20160218 params = CDS=82,DMD=184,ch=0  So in this example shots on 20160224 would get the parameters from the main entry (W7X_L53_LP05_I) but a shot on the 18th Feb or earlier would get the main entry, but with the new params line, including DMD=184 The effect is cumulative, so there is no need to repeat the unchanged parameters. The LHS of the shot (e.g. L53_LP) restricts the application to diagnostics matching the letters before ‘_from’ and ‘_to’ . This is pretty crude, but is needed so that inheritance form .acq will work. Otherwise there has to be a valid_shot in every entry. (which may be a good thing in the long term, but to much work for now. - only the diagnostics that change need valid shots for now.) Another reason for a ‘selective’ shot range, one that applies to a select range of diagnostics, is that %() substitution can be used to simplfy edits. This ‘working backwards’ seems a natural fit to the way the changes were made, and fits well with Soren’s excel, but it would need modification if a new configuration was used at a later date. Some M1’s would need to be edited into M2’s etc. Messy. I can’t easily see how to make a scheme working forward in time, but we don’t need that until W7-X Op1.2! ## 5.3. Loading config files¶ When pyfusion is imported, it will load the default configuration file provided in the source code (that is in the pyfusion directory) followed by your custom configuration file, in $HOME/.pyfusion/pyfusion.cfg, if it exists. and finally files pointed to by the environment variable PYFUSION_CONFIG_FILE if they exist. This allows temporarily overriding config variables.

### 5.10.3. Syntax¶

This way only one edit needs to be made to change all diagnostics, if the definition is fetchr is in the special [DEFAULT] section.

(From the 2.7 docs: 3 is a little different and cleaner)

The configuration file consists of sections, led by a [section] header and followed by name: value entries, with continuations in the style of RFC 822 (see section 3.1.1, “LONG HEADER FIELDS”); name=value is also accepted. Note that leading whitespace is removed from values. The optional values can contain format strings which refer to other values in the same section, or values in a special DEFAULT section. Additional defaults can be provided on initialization and retrieval. Lines beginning with ‘#’ or ‘;’ are ignored and may be used to provide comments. Inline comments are should be avoided, and are not accepted in the pyfusion python 3 version.

### 5.10.4. Testing config file behaviour¶

Importing pyfusion automatically reads several files, so the way to test is to start by clearing, then reading:: >>> cd pyfusion/test >>> pyfusion.conf.utils.clear_config() >>> pyfusion.read_config([“test1.cfg”]) # files ending in e should produce errors # this one has a substitution referencing an option defined in global >>> pyfusion.read_config([“test1e.cfg”])

>>> pyfusion.conf.utils.clear_config()
# the substitution in test2a (bar2a) overrides the initial one

>>> pyfusion.conf.utils.get_config_as_dict('Diagnostic','H1_multi')
{'channel_1': 'H1MP',
'channel_2': '-H1MP',
'data_fetcher': 'pyfusion.acquisition.base.MultiChannelFetcher',
'foo': 'bar2a',
'other_attr': 'other',
'some_attr': 'bar2a'}


### 5.10.5. User Defined Sections¶

Under test is a section [Plots] containing things like

FT_Axis = [0, 0.08, 0, 300000]

to provide defaults for the Frequency-Time axis etc

Note that such settings are highly dependent on the fusion experiment and although they will be recognised in the code, they usually should not be given values in code distributions.

The user could put their own items in there or other sections to avoid