Contact us Heritage collections Image license terms
HOME ACL Associates Technology Literature Applications Society Software revisited
Further reading □ FORTRAN graphics on the PDP15Simple complete FORTRAN program using FOGFOG subroutinesFOG errorsInput routines for use with graphics programsLoading and overlaying FOG □ Appendices □ A: Summary of FOG subroutinesB: VT15 instruction setC: 7-bit ASCII character codesD: Display orders generated by FOG routinesE: The structure of FOG display filesF: The VTA handler
ACD C&A INF CCD CISD Archives Contact us Heritage archives Image license terms

Search

   
ACLLiteratureICL 1906A manualsFOG
ACLLiteratureICL 1906A manualsFOG
ACL ACD C&A INF CCD CISD Archives
Further reading

FORTRAN graphics on the PDP15
Simple complete FORTRAN program using FOG
FOG subroutines
FOG errors
Input routines for use with graphics programs
Loading and overlaying FOG
Appendices
A: Summary of FOG subroutines
B: VT15 instruction set
C: 7-bit ASCII character codes
D: Display orders generated by FOG routines
E: The structure of FOG display files
F: The VTA handler

3. FOG SUBROUTINES

3.1 Display File Initialising Routines

(a) Selecting a display file - DCHOOS

The call is:

      CALL DCHOOS (ia,ie) 
or  
      i = DCHOOS (ia,ie) 
where  
   ia is an integer array name
   ie is an integer expression
   i  is an integer variable.

The array element ia(ie) identifies the header word of a display file. On exit, FOG routines always indicate the length of the display file in this location - ia(ie). The number of words occupied by the display file is the value contained, in ia(ie)+1. On return from the subroutine, i contains the maximum length the display file can occupy without overflowing the array or crossing a bank boundary (a bank boundary occurs every 8K of the machine).

Purpose

The purpose of DCHOOS is to select part of a FORTRAN array (the array element ia(ie) onwards) in the user's program in which the display file is to be stored. Subsequent calls to FOG subroutines will extend the selected display file. DCHOOS also sets a maximum address so that neither the array nor the bank is overflowed by the addition of display orders; an error is reported on overflow.

If the first location (ia(ie)) of the specified display file is zero, then DCHOOS sets up the minimum display file of four words as follows:

location   contents
 ia(ie)      3
 ia(ie+1)  Return address
 ia(ie+2)  DNOP
 ia(ie+3)  DJMP* ia(ie+1)

If the first location is non-zero, DCHOOS checks that the existing display file is legal. A display file is illegal if the first location is less than 3 or if the return-jump-order is not in the location indicated by the length of the file. If the display file is legal, DCHOOS leaves it unchanged and selects it for subsequent FOG subroutines to append to. If the display file is illegal, DCHOOS reports an error and does not select the requested file (see section 4.1 for a list of all errors).

Example

C  DECLARE AN INTEGER ARRAY FOR THE DISPLAY FILE
      INTEGER IDF(1000)
C  INITIALISE THE FIRST ARRAY ELEMENT (I=20) IN WHICH DISPLAY ORDERS ARE 
C  TO BE PLACED
      I=20
      IDF (I)=0
C  SELECT THE DISPLAY FILE STARTING AT LOCATION IDF (20) FOR SUBSEQUENT 
C  SUBROUTINES TO PLACE DISPLAY ORDERS
      CALL DCHOOS (IDF,I)

(b) To start executing a display file - DINIT

The call is:

      CALL DINIT (ia,ie)
where  
  ia is an integer array name
  ie is an integer expression

The subroutine DINIT causes an I/O instruction (IOT) to be sent to the VT15 processor which causes the display file to be executed starting at the first display order in the file specified by ia(ie). The call to DINIT can be performed immediately after the initial call to DCHOOS, in which case a blank display file will be executed but subsequent visible lines and text will appear on the screen as they are drawn. The alternative approach is to call DINIT after all the display orders have been added to the display file, in which case the picture will appear at once. The former method is preferable in some cases for debugging purposes.

The display file must either be a legal display file or the first location (ia(ie)) must be zero. If the display file is legal, it can be displayed normally but if the first location is zero, DINIT constructs a minimum display file (like DCHOOS) which can then be executed. (This only occurs if DCHOOS has never been called before.)

The VT15 first executes a standard main block of display orders which:

  1. sets each of the picture parameters to an initial value. Each of these settings apply until otherwise changed by a parameter display order. The initial settings are:
      intensity = 3 
      scale     = 0
      character string escape on altmode 
      edge flag is disabled
      blink, rotate, lightpen sensitivity, offset off 
      all flags cause interrupts except edge flag
      no dashing
    
  2. obeys a sync order to synchronize each cycle of the display file with the mains frequency
  3. obeys a DJMS indirect to the user's display file, ie, the one specified in DINIT.

If the VT15 is already executing, DINIT will turn it off first and then restart it. Note: Calling DINIT in a tight loop will crash the VT15.

Example

C  DECLARE AN INTEGER ARRAY FOR THE DISPLAY FILE
      INTEGER IDF (1000)
C  INITIALISE THE FIRST ARRAY ELEMENT IN WHICH DISPLAY ORDERS ARE TO 
C  BE PLACED
      IDF (1)=0
C  SELECT THE DISPLAY FILE STARTING AT THE FIRST LOCATION OF THE ARRAY 
C  FOR SUBSEQUENT FOG SUBROUTINES TO PLACE DISPLAY ORDERS
      CALL DCHOOS (IDF,1)
      ..........
      Call to FOG subroutines which add display orders
      ..........
C  AT THIS STAGE NO ORDER HAS BEEN SENT TO THE VT15
      CALL DINIT (IDF,1)
C  THE DISPLAY FILE DRAWN BY THE CALLS TO FOG SUBROUTINES WILL BE 
C  EXECUTED STARTING AT THE FIRST DISPLAY ORDER IN THE FILE SPECIFIED 
C  BY IDF (1).

(c) To stop the execution of a display file. - DCLOSE

The call is:

      CALL DCLOSE 

There are no arguments.

When DCLOSE is obeyed, an I/O instruction is sent to the VT15 processor (via the VT handler) to stop executing; the image on the screen disappears as a consequence.

The display files are not altered by DCLOSE. Like DINIT, DCLOSE should not be called in a tight loop.

3.2 Routines Which Append Orders To Display Files

Each routine has a set of compulsory arguments and these may be followed by a pair of optional integer arguments (both must be present or absent), These two optional arguments contain pointers to the display orders generated by the subroutine. These two pointers can be used later to INSERT different display orders in the same locations, or to delete them (see section 3.4).

If one denotes the two integer arguments as IPT1 and IPT2, then the display routine inserts the following information, in them:

Address of first display order IPT1 IPT2 0 8 9 12 13 17 Undefined A class code which is appropriate to the display subroutine called number of display orders required

Note: [ ] means optional arguments in the following descriptions.

The programmer need not normally be concerned with the contents of IPT1 and IPT2, but they should be preserved intact by his program.

(a) To position the beam at an absolute point on the screen - SETPT

The call is:

      CALL SETPT (ix,iy,ivis[,IPT1,IPT2]) 
where  
      ix,iy,ivis are integer expressions and    
      IPT1,IPT2 represent any integer variables.

The subroutine SETPT adds 1 or 2 display orders to the currently selected display file to position the beam at an absolute position (ix,iy) on the 1023 × 1023 grid. If ivis is 0 no visible trace will appear on the screen but if it is 1 then a visible dot will be displayed at (ix,iy).

If ix < 0 then just one display order is generated which positions the beam at iy, the x~position remaining unchanged. Similarly, if iy < 0 only the x-position of the beam is affected. No display orders are generated if both are negative.

Example

The following constructs a display file with orders to display a visible point at the position (IX,IY):

      INTEGER IDF(1000) 
      IDF (1)=0    
      CALL DCHOOS (IDF,1)
C   CALL SETPT TO DRAW A VISIBLE POINT AT POSITION (IX, IY) 
      IX = 100 
      IY = 500
      CALL SETPT(IX,IY,1) 
      CALL DINIT (IDF,1)
      ...........

(b) To draw a line, (both visibly and invisibly) - LINE

The call is:

      CALL LINE (idx,idy,ivis[,IPT1,IPT2]) 
where  
      idx,idy,ivis are integer expressions
      IPT1,IPT2 are integer variables

The subroutine LINE generates display orders which move the beam from the current plotting position by the amount (idx,idy). The line can either be visible (ivis = 1) or invisible (ivis = 0). idx and idy must both be in the range -1023 to 1023. If the line traced out hits the edge of the screen then no visible trace is produced but the current plotting position registers are updated. If idx = idy = 0 no display orders are added to the display file.

The number of display orders generated by subroutine LINE is dependent on the hardware used to generate the vector on the screen, subroutine ALLARB (section 3.7) affects the type of display orders generated which can be used with the two hardware modes. The basic VT15 graphic processor draws lines on the CRT screen in any one of eight possible directions {basic vectors}. An option is present on the ACL PDP15 to allow one to specify vectors in any arbitrary direction. Normally this arbitrary vector option is used for all vectors (ALLARB = .TRUE - the default). However, it is possible to use a combination of both arbitrary vectors and basic vectors (ALLARB = .FALSE) to economise on storage space. In this latter case the subroutine LINE generates display orders, using either arbitrary or basic vector orders which occupy the smallest amount of space in the display file.

Briefly, the number of display orders needed is 1 or 2. See Appendix D for more precise details.

Example

The following code generates display orders to draw an absolute vector on the screen from (IX1,IY1) to (IX2,IY2):

      INTEGER IDF(1000)
      IDF (1) = 0
      CALL DCHOOS (IDF,1)
C  POSITION THE BEAM AT THE BEGINNING OF THE VECTOR
      CALL SETPT (IX1,IY1,0)
C  DRAW A VISIBLE LINE FROM THE CURRENT PLOTTING POINT TO THE END 
C  OF THE VECTOR
      CALL LINE (IX2-IX1,IY2-IY1,1)
      CALL DINIT (IDF,1)

(c) Subroutine to display a symbol - SYMB

The call is:

      CALL SYMB (ichar[,IPT1,IPT2]) 
where  
  ichar is an integer variable containing an ASCII character code
  IPT1, IPT2 are integer variables

Subroutine SYMB adds to the currently-selected display file an order for displaying a single character at the current beam position. The character required is specified by its 7- or 8-bit ASCII code (ichar). A table of ASCII codes is included in Appendix C.

The basic character size (with scale = 0) occupies 10 × 14 (X × Y) raster positions. On return from the subroutine the beam is positioned in x at a point of +14 raster positions from the previous plotting point.

For a single character the advantage over using subroutine TEXT (see later) is that the character is stored in the display file itself instead of in a separate REAL array. SYMB is more economical on display file space for a small number of characters.

Example

The following code draws an X at the centre of the display screen:

      INTEGER IDF(1000)
      IDF (1) = 0
      CALL DCHOOS(IDF,1)
C  POSITION THE BEAM AT THE CENTRE OF THE DISPLAY SCREEN
      CALL SETPT(512,512,0) 
C  DRAW THE SINGLE CHARACTER X
      CALL SYMB (#130)
      CALL DINIT(IDF,1)
      ................

(d) To display a text string - TEXT

The call is:

      CALL TEXT (character string, n [,IPT1,IPT2])
where  
  character string can be stored in either a REAL or DOUBLE-INTEGER 
    variable or array, or it can be a literal
  n is an integer expression 
  IPT1,IPT2 are integer variables

Subroutine TEXT adds to the currently selected display file orders to display a string of characters at the current beam position. The string specified in the argument (either literally, ie 4HAECD or as a REAL or DOUBLE-INTEGER variable or array) should be 5/7 ASCII.

The number of characters to be displayed is n. If n > 0, TEXT inserts an altmode into the (n+1)th character position to allow the VT15 to escape from character mode after n characters. The string in the user's program is changed, not a copy held in the display file. It is therefore important that the (n+1)th character is allocated space when creating the Hollerith string. It is important that this point is noted when using literals.

If n = 0, TEXT leaves the string unchanged; in this case either the string must have an altmode in it already or the VTI5 processor will continue trying to execute character display orders until it by chance finds an altmode character in core store. This is a common way for the display program to fail. The current plotting position will be displaced in the X-axis by +14 raster positions for each character.

Example

The following code generates display orders which draw the string ABCDEFGH starting at position (50,500):

      REAL FIRST
      INTEGER IDF(1000)
      DATA FIRST /4HABCD/
      IDF(1) = 0
      CALL DCHOOS (IDF,1) 
C  POSITION THE BEAM AT (50,500)
      CALL SETPT (50,500,0)
C  DRAW THE FIRST FOUR CHARACTERS OF THE STRING CONTAINED IN THE REAL 
C  VARIABLE FIRST
      CALL TEXT (FIRST,4) 
C  DRAW THE SECOND FOUR CHARACTERS OF THE STRING USING A LITERAL
      CALL TEXT ('EFGH',4)
      CALL DINIT (IDF,1)
      ................

3.3 Routines Which Set Picture Parameters

As well as generating visible images like lines and symbols, a program can call routines which generate display orders that cause changes in picture parameters (such as brightness, scale etc). Each of the picture parameter routines generates a display order which when executed causes a specific VT15 register, corresponding to the specified parameter to be set to the new value. This effect persists until another display order of the same type or a RESTORE order picks up display-register settings from a previous SAVE order. (SAVE and RESTORE orders can be generated by the DRAW routine.)

Each routine can include the two optional, integer variable arguments (IPT1, IPT2) which can be used later for insertion, replacement or deletion.

(a) Blinking - BLINK

The call is:

      CALL BLINK (ioffon[,IPT1,IPT2]) 

Subroutine BLINK turns blinking on (ioffon = 1) or off (ioffon = 0).

(b) Brightness - BRITE

The call is:

      CALL BRITE (ilevel[,IPT1,IPT2])

Subroutine BRITE sets the intensity level of subsequent lines, points and characters. ilevel can be any value in the range 0-7. The VT15 is normally adjusted to make level 0 invisible.

(c) Dashing - DASH

The call is:

      CALL DASH (icode[,IPT1,IPT2])

Subroutine DASH causes subsequent lines tn be broken in a manner which depends on icode:

0  unbroken
1  6 units on / 2 units off 
2  3 units on / 1 unit off 
3  1 unit on / 1 unit  off

(d) Lightpen sensitivity - LPVIS

The call is:

      CALL LPVIS(ioffon[,IPT1,IPT2])

Subroutine LPVIS makes selected portions of the image sensitive to the lightpen. If ioffon = 1 subsequent displayed images will be visible to the lightpen or invisible if ioffon = 0.

For a line to be seen by the lightpen, the image should be sufficiently bright. This threshold brightness depends on the aperture used in the pen and the sensitivity knob situated beside the pushbuttons. In order to actually read the lightpen it is necessary to use a routine such as LTORPB.

(e) Setting the NAME register - NAME

The call is:

CALL NAME (ivalue[,IPT1,IPT2])

Subroutine NAME causes the name register in the VT15 processor to be set to ivalue; the possible range of values is 0-127. The name register can be tested by certain display orders which are not catered for in the current version of FOG or it can be read by a CPU program. The information is only meaningful to the CPU if the display is halted, for example by a lightpen flag. It can be a useful facility when using subroutine LTORPB.

(f) Using the offset region of the display area - OFFST

The call is:

CALL OFFST (ioffon[,IPT1,LPT2])

Subroutine OFFST causes subsequently displayed images to be put into the offset region (ioffon = 1) or in the major display area (ioffon = 0). The first beam moving display order should be a SETPT.

(g) Rotating parts of the image by 90 degrees counter clockwise - ROT

The call is:

CALL ROT (ioffon[,IPT1,IPT2])

Subroutine ROT causes subsequently displayed images to be drawn rotated about the last SETPT by 90 degrees counter clockwise (ioffon = 1) or not rotated at all (ioffon = 0). Relative movements are affected (lines and symbols), absolute movements are not (setpoints). Thus whole pictures and/or test strings can be rotated about any fixed point on the display. Repeated calls do not accumulate.

(h) Changing the scale of the image - SCALE

The call is:

CALL SCALE (ilevel[,IPT1,IPT2])

Subroutine SCALE causes subsequently displayed lines to be drawn (ilevel + 1) times end to end. ilevel must be in the range 0-15. Characters are made up of lines so they are scaled as well.

3.4 Routines Which Insert Display Orders Into Display Files

Each of the append-type subroutines described in Sections 2 and 3 has a counterpart in this section. The name of the equivalent insertion routine is derived from the append-type routine by prefixing the subroutine name with the character I. For example, the insertion routine corresponding to the append-type subroutine SETPT is ISETPT.

There are two main differences between the insert routines and the append routines:

  1. The arguments IPT1 and IPT2, which point to the insertion-location in the display file must both be present.
  2. All insert-type subroutines can be used as LOGICAL FUNCTIONS whose result is the truth value of the statement The display code required has been successfully inserted. Failure is usually due to the space not being big enough.

For example:

Insert                                         Append
      CALL ISETPT (IX,IY,IVIS,IPT1,IPT2)       CALL SETPT (IX,IY,IVIS[,IPT1,IPT2])
or   
      LOGICAL INSERT
      INSERT = ISETPT(IX,IY,IVIS,IPT1,IPT2) 
      IF (INSERT) GO TO 1
      if obey this statement then no display 
      orders have been added
      ...........
 1    CONTINUE
      if obey this statement then the 
      display orders have been successfully 
      inserted

There is an additional insertion routine which has no equivalent append-type routine: subroutine DELETE.

The call is:

      CALL DELETE (IPT1,IPT2) 
or   
      INSERT = DELETE (IPT1,IPT2) 
where IPT1,IPT2 are integer variables
      INSERT is a logical variable

Subroutine DELETE replaces the specified display code, pointed at by the variables IPT1,IPT2 by display orders which have no effect, on the image (DNOP's).

Example of the use of an insertion routine

The following code reads the position (IX,IY) of the stylus on the writing tablet and uses this information to position the bottom left-hand corner of an X at this point on the screen:

      LOGICAL READY
      INTEGER IDF (1000), IA(4)
      EQUIVALENCE (IX,IA(3)),(IY,IA(4)) 
C   INITIALISE THE VT15 AND SET UP THE DISPLAY FILE
      IDF (1) = 0
      CALL DCHOOS (IDF,1)
      CALL DINIT (IDF,1)
C  DRAW AN INITIAL X AT THE CENTRE OF THE SCREEN, SAVING THE POSITION 
C  OF THE SETPOINT IN THE DISPLAY FILE
      CALL SETPT (512,512,0,IP,IQ)
      CALL SYMB(#130) 
C   INITIALISE THE WRITING TABLET
      CALL TINIT (1) 
C  LOOP FOR CONTINUOUSLY READING THE STYLUS POSITION
1     CONTINUE
C  READ THE POSITION OF THE STYLUS
2     READY = TREAD (IA(1),4)
      IF (.NOT. READY) GO TO 2
C  AT THIS POINT THE CURRENT STYLUS POSITION IS IN IX,IY 
C  CHANGE THE POSITION OF THE SETPT TO REFLECT THIS
      CALL ISETPT (IX,IY,0,IP,IQ) 
C  JUMP TO READ THE STYLUS AGAIN
      GO TO 1
      ..........

NB This program is only meant to illustrate ISETPT; there is no termination condition included.

3.5 Routines To Use Subpictures

(a) To draw a separate subpicture - DRAW

The call is:

      CALL DRAW (ioffon,iarray(i)[,IPT1,IPT2])
where  ioffon is an integer expression
       iarray(i) is an integer array element 
       IPT1,IPT2 are integer variables

Subroutine DRAW adds display orders to the currently selected display file which make a subpicture reference (using a DJMS order) to another display file. The VT15 processor executes the currently selected file until the subpicture reference is met, the new display file is then executed and at the end of the sub-file a DJMP order is obeyed to cause the VT15 to continue executing the first file where it left off. iarray(i) specifies the starting location of the subpicture file. The argument ioffon controls whether any SAVE/RESTORE orders will be included in the subpicture reference and return. If ioffon = 0 no save/restore orders are included; if ioffon = 1 they are. The effect of including save/restore orders is that any picture parameter settings changed in the subfile do not continue to have effect in the calling file. Sub-picture references can be nested to any depth, but not recursed.

The subroutine DRAW aids the programmer in drawing multiple images of the same picture, in displaying a precalculated display file or in selective alteration of large pieces of a picture.

Example

The following code draws the string ABCD on the display screen. The character A is drawn by the main display file while the remaining three characters are drawn by three separate sub-files:

      INTEGER IDF (1000),ISUB1(10),ISUB2(10) 
C   INITIALISE AND SELECT THE MAIN DISPLAY FILE
      TDF (1) = 0
      CALL DCHOOS (IDF,1) 
C  APPEND THE CHARACTER A TO THE MAIN DISPLAY FILE AT POSITION (50,500)
      CALL SETPT (50,500,0)
      CALL SYMB (#101) 
C   SELECT SUBFILE 1 AND DRAW THE CHARACTER B IN ARRAY ISUB1
      ISUB1 (1) = 0
      CALL DCHOOS (ISUB1,1)
      CALL SYMB(#102) 
C   SELECT SUBFILE 2 AND DRAW THE CHARACTER 
C IN ARRAY ISUB2
      ISUB2 (1) = 0
      CALL DCHOOS (ISUB2,1)
      CALL SYMB(#103)
C  SELECT SUBFILE 3 AND DRAW THE CHARACTER D IN THE SECOND HALF OF 
C  ARRAY ISUB2
      ISUB2 (6) = 0
      CALL DCHOOS(ISUB2,6)
      CALL SYMB(#104) 
C   SELECT THE MAIN DISPLAY FILE AND DRAW THE SUB-FILES
      CALL DCHOOS (IDF,1)
      CALL DRAW (0,ISUB1(1))
      CALL DRAW (0,ISUB2(1))
      CALL DRAW (0,1SUB2(6)) 
C   START EXECUTION OF THE MAIN DISPLAY FILE
      CALL DINIT (IDF,1)
      ..............

(b) To switch off a specified display file - BLANK

The call is:

      CALL BLANK (iarray (i)) 
where  
      iarray (i) is an integer array element

Subroutine BLANK causes the specified display file to be blanked. iarray(i) specifies the starting location of the display file. A return jump (DJMP) is planted in the specified display file immediately after the entry. Since no display orders are obeyed, BLANK could have a side-effect on the beam-position (and hence on subsequent pictures).

To switch on a specified display file - it undoes the effect of BLANK - UNBLNK

The call is:

CALL UNBLNK (iarray (i))
 where  iarray (i) is an integer array element

Subroutine UNBLNK causes any BLANKED display file to be unblanked. iarray (i) specified the starting location of the display file. The DJMP order previously written by a call to BLANK is overwritten by a DNOP.

3.6 To Save And Recover References To Display Files

A complete reference to a display file consists of the two entries, the starting address and the maximum allowable address. A program can use FOG routines to save a display-file-reference in a numbered cell (which consists of two words) of a FOG internal array. It can later apply recovery routines which are the counterparts of routines including a display file in the argument list (eg DCHOOS, DINIT); the recovery routine simply requires a cell-number. The range of cell numbers is 1 to 16.

These routines will allow different user routines to refer to the display file without forcing the programmer to put the array into COMMON. It is also possible, using these routines, to write graphics library-routines.

(a) SAVE routines

  1. SUBROUTINE SCHOOS (icelln)
    puts into the specified cell (icelln) a reference to the currently open file.
  2. SUBROUTINE SINIT (icelln)
    puts into the specified cell (icelln) a reference to the current main file (the one most recently DINIT'd).

(b) RECOVERY routines

  1. INTEGER FUNCTION RCHOOS (icelln)
    recovers the reference to the display file contained in the specified cell (icelln) and then mimics DCHOOS. The result of the function is as in DCHOOS.
  2. SUBROUTINE RINIT (icelln)
    recovers the reference to the display file contained in the specified cell (icelln) and mimics DINIT.

3.7 Miscellaneous Routines

(a) Subroutine SYNCOP

Every time DINIT is called it ensures that the standard-main-file in FOG contains a wait-for-sync display order; on every cycle of the display files this order is obeyed and so locks the display cycle to the main frequency (50 Hz). If the programmer wishes to override this synchronisation, a call to SYNCOF replaces the wait-for-sync by a DNOP. This routine should be used with care as small files displayed without sync will accelerate phosphor burnout.

(b) Subroutine SYNCON

Subroutine SYNCON restores the sync order.

(c) Subroutine ALLARB (L)

Where L is a logical variable.

The arguemnt L is used to set a switch which is used by the subroutine LINE (32). If L = .TRUE., LINE only generates arbitrary vector orders. If L = .FALSE., LINE produces display orders which occupy the smallest space; that is, a basic vector order will be used if the line required can be drawn in this way.

⇑ Top of page
© Chilton Computing and UKRI Science and Technology Facilities Council webmaster@chilton-computing.org.uk
Our thanks to UKRI Science and Technology Facilities Council for hosting this site