---
# System prepended metadata

title: Theta ADSP Allocation
tags: [theta, adsp, allocation, quota, general]

---

# Theta ADSP Allocation

###### tags: `general` `theta` `adsp` `allocation` `quota` 

## Quotas

Storage directory (Lustre): `/grand/neutrino_osc_ADSP/`.

To list disk quota:

```bash=0
myquota
Name                           Type     Filesystem        GB_Used       GB_Quota          Grace
===============================================================================================
deltutto                       User     mira-home         0.00        100.00             none      
```

```bash=0
myprojectquotas

Lustre : Current Project Quota information for projects you re a member of:

Name                           Type     Filesystem          Used          Quota           Grace
===============================================================================================
neutrino_osc_ADSP           Project     grand                 4k           240T               -
```


To list the project allocation quota:

```bash=0
sbank-list-allocations -p neutrino_osc_ADSP
 Allocation  Suballocation  Start       End         Resource  Project            Jobs  Charged  Available Balance 
 ----------  -------------  ----------  ----------  --------  -----------------  ----  -------  ----------------- 
 7141        7009           2021-05-01  2022-05-01  thetagpu  neutrino_osc_ADSP     0      0.0            2,000.0 
 7142        7010           2021-05-01  2022-05-01  theta     neutrino_osc_ADSP     0      0.0           72,000.0 
```




# :memo: LArSoft

Lustre is basically parallel IO, each file gets chunked and written to a bunch of different high performance drives. The idea is that when everyone is reading and writing, the actual work isn’t bottlenecked and everyone gets good performance. In reality, there is a metadata server that knows where the files actually live (file A chunked on drives 1, 2 ….50…). Sometimes that server gets overwhelmed, but `/grand` is a brand new system with more servers I think. The number of servers that files get written to is called the `stripe count`.

```bash=0
cd /grand/neutrino_osc_ADSP
mkdir sbndcode
chmod g+w sbndcode/
# Set number of severs files in sbndcode are written to
lfs setstripe -c 40 sbndcode/
# Pull products
./pullProducts ./sbndcode/ slf7 sbnd-v09_24_02 e20 prof
```

## Singularity

Corey built a singularity image from a docker image made by [FNAL](https://hub.docker.com/r/fermilab/fnal-wn-sl7/): `singularity build fnal-wn-sl7.sing docker://fermilab/fnal-wn-sl7:latest`.

Then we run (from `/grand/neutrino_osc_ADSP`):

```bash=0
singularity exec -B /grand fnal-wn-sl7.sing bash
Singularity> source sbndcode/setup
Singularity> setup sbndcode v09_24_02 -q e20:prof
Singularity> 
Singularity> lar -c prodsingle_mu_bnblike.fcl -n 10
```

## Balsam - Get Started

Balsam instructions: https://balsam.readthedocs.io/en/latest/index.html

To test that we can run some simple test job, create a balsam site and submit a couple of test jobs. This is taken from the Balsam tutorial itself, with some modifications.

```bash=0
balsam site init balsam_testsite
[Select the default configuration for Theta-KNL]
cd balsam_testsite/
balsam site start
```

Balsam login doesn't work, but Misha can generate a token. I had to put the following block in `~/.balsam/client.yml`:
```
api_root: https://balsam-dev.alcf.anl.gov
client_class: balsam.client.BasicAuthRequestsClient
connect_timeout: 6.2
read_timeout: 120.0
retry_count: 3
token: eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOjE1LCJleHAiOjE2MjcyNDE3MDgsInVzZXJuYW1lIjoiZGVsdHV0dG8ifQ.3eyACjKc_6hwStfWLuZjyraNQDxSba4iB8g9QPaDU50
token_expiry: '2021-07-25T19:35:08.727143'
username: deltutto
```

Then, need to uncomment this line in the `job-template.sh` script:
```
# export https_proxy=http://theta-proxy.tmi.alcf.anl.gov:3128
```
This is needed because the jobs are living in that external database and we can interact with them on the login nodes since login nodes since they have outbound network access. But compute nodes don’t have this network access, and the server (which used to be internal to ALCF and is now public) is unreachable. This export tunnels outbound traffic through a proxy server to let compute nodes reach the bigger world.

Now the Balsam site is running, and we can create a couple of test jobs:
```bash=0
balsam app create
> Application Name (of the form MODULE.CLASS): test.Hello
> Application Template [e.g. 'echo Hello {{ name }}!']: echo hello {{ name }} && sleep {{ sleeptime }} && echo goodbye
balsam job create --app test.Hello --workdir test/1 --param name="world" --param sleeptime=2
balsam job create --app test.Hello --workdir test/2 --param name="balsam" --param sleeptime=1
balsam queue submit -q debug-cache-quad -A neutrino_osc_ADSP -n 1 -t 10 -j mpi
```

Can be monitored with:
```bash=0
watch "qstat -u $USER && balsam queue ls"
```
and can be seen here: https://status.alcf.anl.gov/theta/activity.

The output is placed in the `data/` directory.

## LArSoft Test Job with Balsam

Create a new app in the Balsam site that will run a prodsingle LArSoft job:

```bash=0
balsam app create
> Application Name (of the form MODULE.CLASS): prodtest.ProdSingle
> Application Template [e.g. 'echo Hello {{ name }}!']: to_be_written
```

Then open the file `apps/prodtest.py` and modify the `command_template` attribute to:
```python=0
    command_template = '''
singularity run -B /lus/grand/projects/neutrino_osc_ADSP:/lus/grand/projects/neutrino_osc_ADSP:rw /lus/grand/projects/neutrino_osc_ADSP/fnal-wn-sl7.sing <<EOF
	#setup SBNDCODE:
	source /lus/grand/projects/neutrino_osc_ADSP/sbndcode/setup
	setup sbndcode v09_24_02 -q e20:prof
	lar -c prodsingle_mu_bnblike.fcl
        ls
EOF
echo "\nJob finished in: $(pwd)"
echo "Available files:"
ls
'''
```

Save it and run `balsam sync app` to sync the newly modified app.
Create a new job:
```bash=
balsam job create --app prodtest.ProdSingle --workdir prodtest_single/0
```
And check that the job has been created with:
```bash=
balsam job ls
```

Now let's run it:
```bash=
balsam queue submit -q debug-cache-quad -A neutrino_osc_ADSP -n 1 -t 10 -j mpi
watch "qstat -u $USER && balsam queue ls"
```

If it is successful, the output files will be in `data/prodtest_single/0`.

## LArSoft Production Workflow

### Introduction

Up to now we’ve been running jobs in `mpi` mode, in which balsam runs on the `mom` node.  This mode runs the balsam executable and launches a bunch of `aprun` calls (which is the Theta version of `mpirun`) and those go onto the compute nodes.

In serial mode, it’s a bit inverted: balsam runs on each compute node (via `aprun`) and does POpen calls without `aprun` involved.  So this is a direct fork of the process onto compute nodes. The advantage here is that we can use a portion of the compute node, per balsam-job, instead of granularity of one node or higher.

With 64 cores, we have been running the larsoft jobs with 64 lar calls per node, and scaling out onto hundreds of nodes


For this, we end up packing in a ton of larsoft jobs, launching a big balsam job, and they all run together. We want to have several stages, though, which requires a workflow. When `serial` mode (or `mpi` mode, too) is asking the database for jobs, it uses the list of jobs that are `PREPROCESSED`.  Jobs can have parents and children too, which will prevent them from running right away
Check out the diagram down the page here: https://balsam.readthedocs.io/en/master/userguide/app.html


We can have a job (say, prodsingle) that is a parent to a geant job, which is a parent to a detsim job, etc. We can break societal norms too: jobs can have unlimited numbers of parents or children

One optimization that was found helps is to do something like:
- Job 1: `lar -c prodsingle.fcl -n 25`
- Jobs 2-26: `lar -c g4.fcl -n 1 -nskip {JOB_INDEX} -i singles.root`, each has Job 1 as a parent
- Job 27-52: `lar -c detsim.fcl -n 1 -i singles_g4_JOB_INDEX.root`, each has exactly 1 parent from the previous step
- Job 53: `lar -c merge.fcl -i {all detsim outputs}`, this job has every job from 27 to 52 as it’s parent

This gives a graph of jobs that balsam will take, and dynamically run every job with it’s parents finished and keep going until no more jobs
You can also slice between workflows with `tags`, so one could be `sbnd:g4` and one could be `uboone:prodsingle` and one could be `sbnd:detsim` and you can select only `sbnd`, only `detsim`, only whatever.

### Creating a Workflow


The following shows an example on how we can create a prodsingle job, followed by several geant4 jobs which have the prodsingle one as the parent.

First, we need to make two apps, one for prodsingle, and one for Geant4. This is done similarly to the example above, but now we need to pass some arguments. For prodsingle, the `command_template` should look something like:
```python=
    command_template = '''
singularity run -B /lus/grand/projects/neutrino_osc_ADSP:/lus/grand/projects/neutrino_osc_ADSP:rw /lus/grand/projects/neutrino_osc_ADSP/fnal-wn-sl7.sing <<EOF
    #setup SBNDCODE:
    source /lus/grand/projects/neutrino_osc_ADSP/sbndcode/setup
    setup sbndcode v09_24_02 -q e20:prof
    lar -c prodsingle_mu_bnblike.fcl --nevts {{nevts}} --output {{output}}
    ls
EOF
echo "\nJob finished in: $(pwd)"
echo "Available files:"
ls
'''
```
While for Geant4:
```python=
    command_template = '''
singularity run -B /lus/grand/projects/neutrino_osc_ADSP:/lus/grand/projects/neutrino_osc_ADSP:rw /lus/grand/projects/neutrino_osc_ADSP/fnal-wn-sl7.sing <<EOF
    #setup SBNDCODE:
    source /lus/grand/projects/neutrino_osc_ADSP/sbndcode/setup
    setup sbndcode v09_24_02 -q e20:prof
    lar -c standard_g4_sbnd.fcl --nevts {{nevts}} --nskip {{nskip}} --output {{output}} --source {{source}}
    ls
EOF
echo "\nJob finished in: $(pwd)"
echo "Available files:"
ls
'''
```

This python script created the jobs:

```python=
from balsam.api import Job, App, site_config

n_events = 5
node_packing_count=5

#
# ProdSingle
#
prodsingle_app = App.objects.get(site_id=site_config.site_id, class_path="production.ProdSingle")
prodsingle_jobs = []

for i in range(1):
    job = Job(
        workdir=f"prod_prodsingle/{i}",
        app_id=prodsingle_app.id,
        tags={'sbnd':'prodsingle'},
        parameters={
            "nevts": f"{n_events}",
            "output": f"prodsingle_sbnd_{i}.root"},
        node_packing_count=node_packing_count,
        num_nodes=1,
        parent_ids=(),
    )
    print(job)
    job.save()
    prodsingle_jobs.append(job)



#
# Geant4
#
geant4_app = App.objects.get(site_id=site_config.site_id, class_path="production.Geant4")
geant4_jobs = []

for i in range(n_events):
    job = Job(
        workdir=f"prod_geant4/{i}",
        app_id=geant4_app.id,
        tags={'sbnd':'geant4'},
        parameters={
            "nevts": "1",
            "nskip": f"{i}",
            "output": f"prodsingle_geant4_sbnd_{i}.root",
            "source": f"{prodsingle_jobs[0].parameters['output']}"},
        node_packing_count=node_packing_count,
        num_nodes=1,
        parent_ids={prodsingle_jobs[0].id},
    )
    print(job)
    job.save()
    geant4_jobs.append(job)
```

Running this should create the following:
```bash=
$> balsam job ls
ID      Site                           App                     Workdir             State              Tags                    
67191   thetalogin6:balsam_testsite2   production.Geant4       prod_geant4/4       AWAITING_PARENTS   {'sbnd': 'geant4'}      
67187   thetalogin6:balsam_testsite2   production.Geant4       prod_geant4/0       AWAITING_PARENTS   {'sbnd': 'geant4'}      
67190   thetalogin6:balsam_testsite2   production.Geant4       prod_geant4/3       AWAITING_PARENTS   {'sbnd': 'geant4'}      
67189   thetalogin6:balsam_testsite2   production.Geant4       prod_geant4/2       AWAITING_PARENTS   {'sbnd': 'geant4'}      
67186   thetalogin6:balsam_testsite2   production.ProdSingle   prod_prodsingle/0   STAGED_IN          {'sbnd': 'prodsingle'}  
67188   thetalogin6:balsam_testsite2   production.Geant4       prod_geant4/1       AWAITING_PARENTS   {'sbnd': 'geant4'} 
```

TO BE CONTINUED



## Flux Files

### SBND Fluxes
SBND flux files in neutrino mode are in `/cvmfs/sbnd.osgstorage.org/pnfs/fnal.gov/usr/sbnd/persistent/stash/fluxFiles/bnb/BooNEtoGSimple/configH-v1/march2021/neutrinoMode/`. They have been copyied to Theta at this location:
```bash=
/grand/neutrino_osc_ADSP/files/flux/sbnd/neutrino_mode/
```
In total, they take 69 GB of disk space.

### ICARUS Fluxes
### MicroBooNE Fluxes

# Table of Contents
[ToC]


