Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion dev-environment.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ dependencies:
- bokeh
- click
- pyyaml
- lume-model>=1.4
- lume-model>=2.0.0
- nose>=1.1.2
- pip:
- p4p
Expand Down
2 changes: 1 addition & 1 deletion environment.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ dependencies:
- bokeh
- click
- pyyaml
- lume-model>=1.4
- lume-model>=2.0.0
- nose>=1.1.2
- pip:
- p4p
84 changes: 0 additions & 84 deletions examples/client.py

This file was deleted.

63 changes: 63 additions & 0 deletions examples/common/p4p_server.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@

import p4p
import threading
import math
import random
import time
import yaml
import argparse
import os
from p4p.nt import NTScalar
from p4p.server import Server
from p4p.server.thread import SharedPV
from typing import Dict
from threading import Thread

class SimpleSimServer():

def __init__(self, config: dict):
"""
Create a new simple simulated server.
This pretty must just serves some PVs and gives them a random value

Configuration dictionary:
{
"mypv": { "value": 1, "range": 3, "type": "d" }
}
"""
self.config = config
self.pvs = {
x: SharedPV(
initial=c['value'],
nt=NTScalar('d' if 'type' not in c else c['value'])
)
for x, c in config.items()
}
self.running = True
self.server = Server([self.pvs])
self.thread = Thread(target=self._thread_proc)
self.thread.start()

def update_env(self):
"""Update the process's environment with config items generated by p4p"""
conf = self.server.conf()
for k, v in conf.items():
os.environ[k] = v

def stop(self):
"""Stop the simulated server"""
self.running = False
self.thread.join()
self.server.stop()

def _thread_proc(self):
while self.running:
for k, v in self.config.items():
range = self.config[k].get('range', 1)
self.pvs[k].post(
random.uniform(
self.config[k]['value'] + range / 2,
self.config[k]['value'] - range / 2,
)
)
time.sleep(0.1)
25 changes: 11 additions & 14 deletions examples/lcls/README.md
Original file line number Diff line number Diff line change
@@ -1,21 +1,18 @@
# LCLS Model + Client

Provided you're connected to the SLAC network via VPN, this demo will monitor LCLS pvs, execute summation of those PV values on value change, serve an output pv, and display the results in a Bokeh-based web app.
This example demonstrates a summation of klystron amplitude PVs and serves the result over PVA.

The example may be run with real PV data from the accelerator, or standalone with dummy simulated values.

Open two terminal windows. Activate a Python environment with an updated `lume-epics` installation. Set the channel access address list in each:
```
$ export EPICS_CA_ADDR_LIST={LCLS_PROD_HOST}:{CA_SERVER_PORT}
To run in standalone mode:
```bash
$ cd examples
$ python3 -m lcls.server --standalone
```

## Server
In the first window, run:
```
python examples/lcls/server.py
```

## Client
In the second window, run:
```
bokeh serve examples/lcls/client.py --show
If you're on the SLAC network, configure the EPICS environment to point to the production gateway, and then run:
```bash
$ source $EPICS_SETUP/envSet_prodOnDev.bash
$ cd examples
$ python3 -m lcls.server
```
64 changes: 0 additions & 64 deletions examples/lcls/client.py

This file was deleted.

19 changes: 18 additions & 1 deletion examples/lcls/server.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
import numpy as np
import yaml
import argparse
from lume_model.base import LUMEBaseModel
from lume_model.utils import variables_from_yaml
from lume_epics.utils import config_from_yaml
from lume_epics.epics_server import Server
from pathlib import Path
from common.p4p_server import SimpleSimServer

from pathlib import Path

class AmplSummationModel(LUMEBaseModel):
def __init__(self):
Expand All @@ -22,6 +25,17 @@ def _evaluate(self, input_dict: dict) -> dict:


if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument('--standalone', action='store_true', help='Spins up an internal EPICS PVA server to simulate the PVs used by this test')
args = parser.parse_args()

# Spin up P4P server if requested
if args.standalone:
with open(Path(__file__).parent / "sim_config.yml") as fp:
config = yaml.safe_load(fp)
sim_server = SimpleSimServer(config)
sim_server.update_env()

# load epics configuration
epics_path = Path(__file__).parent / "epics_config.yml"
epics_config = config_from_yaml(Path(__file__).parent / "epics_config.yml")
Expand All @@ -32,3 +46,6 @@ def _evaluate(self, input_dict: dict) -> dict:
)
# monitor = False does not loop in main thread
server.start(monitor=True)

if sim_server:
sim_server.stop()
19 changes: 19 additions & 0 deletions examples/lcls/sim_config.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
KLYS:LI24:11:AMPL:
value: 51.123
range: 2

KLYS:LI24:21:AMPL:
value: 24.0234
range: 2

KLYS:LI24:31:AMPL:
value: 56.4697
range: 2

KLYS:LI24:41:AMPL:
value: 55.2002
range: 2

KLYS:LI24:51:AMPL:
value: 57.666
range: 2
Loading