Skip to content

Commit e2d606c

Browse files
committed
Merge branch 'dev'
2 parents e250f56 + d555b18 commit e2d606c

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+3826
-113
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,3 +175,4 @@ cython_debug/
175175
*.log
176176
*.sqlite
177177

178+
.aider*

dapi/client.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -311,8 +311,8 @@ def generate_request(
311311
self,
312312
app_id: str,
313313
input_dir_uri: str,
314-
script_filename: str,
315314
# --- Optional Overrides ---
315+
script_filename: Optional[str] = None,
316316
app_version: Optional[str] = None,
317317
job_name: Optional[str] = None,
318318
description: Optional[str] = None,
@@ -344,7 +344,8 @@ def generate_request(
344344
Args:
345345
app_id (str): The ID of the Tapis application to use for the job.
346346
input_dir_uri (str): Tapis URI to the input directory containing job files.
347-
script_filename (str): Name of the main script file to execute.
347+
script_filename (str, optional): Name of the main script file to execute.
348+
If None, no script parameter is added (suitable for apps like OpenFOAM).
348349
app_version (str, optional): Specific app version. If None, uses latest.
349350
job_name (str, optional): Custom job name. If None, auto-generates one.
350351
description (str, optional): Job description. If None, uses app description.

dapi/jobs.py

Lines changed: 285 additions & 79 deletions
Large diffs are not rendered by default.

docs/api/client.md

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,36 @@ The main client interface for all DAPI functionality. DSClient provides organize
44

55
::: dapi.client.DSClient
66

7+
## Accessing the Raw Tapis Client
8+
9+
For advanced use cases or accessing Tapis APIs not wrapped by dapi, you can get the underlying Tapis client:
10+
11+
```python
12+
from dapi import DSClient
13+
14+
# Initialize DSClient
15+
ds = DSClient()
16+
17+
# Access the raw Tapis client
18+
tapis_client = ds.tapis
19+
20+
# Use raw Tapis APIs directly
21+
raw_apps = tapis_client.apps.getApps(search="*opensees*")
22+
systems = tapis_client.systems.getSystems()
23+
jobs = tapis_client.jobs.getJobList()
24+
```
25+
26+
### When to Use the Raw Tapis Client
27+
28+
- Access Tapis APIs not yet wrapped by dapi
29+
- Use advanced search parameters not exposed by dapi
30+
- Implement custom functionality
31+
- Debug or troubleshoot API calls
32+
- Access experimental or new Tapis features
33+
34+
!!! warning
35+
When using the raw Tapis client, you'll need to handle errors and data formatting yourself. The dapi wrapper provides error handling and user-friendly formatting.
36+
737
## Service Interfaces
838

939
The DSClient provides access to different DesignSafe services through specialized interface classes:

docs/authentication.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -307,6 +307,27 @@ print(f"NGL database has {df.iloc[0, 0]} sites")
307307
print("✅ All authentication successful!")
308308
```
309309

310+
## 🔧 Troubleshooting
311+
312+
### JWT Token Expiration
313+
314+
If you encounter JWT token expiration errors during long-running sessions, you'll see an error like:
315+
316+
```
317+
UnauthorizedError: message: b'TAPIS_SECURITY_JWT_EXPIRED Exception message: JWT expired at 2025-06-09T08:51:38Z. Current time: 2025-06-09T12:06:54Z, a difference of 11716617 milliseconds. Allowed clock skew: 0 milliseconds. Claims: iss: https://designsafe.tapis.io/v3/tokens sub: username@designsafe tapis/tenant_id: designsafe tapis/username: username tapis/account_type: user'
318+
```
319+
320+
**Solution:** Simply reinitialize your DSClient to refresh the authentication tokens:
321+
322+
```python
323+
# Reinitialize the client to refresh tokens
324+
ds = DSClient()
325+
```
326+
327+
This will automatically handle token refresh and you can continue with your work.
328+
329+
**Why this happens:** Tapis authentication tokens have a limited lifespan for security purposes. Long-running Jupyter notebooks or scripts may encounter this after several hours of use.
330+
310331
## ➡️ Next Steps
311332

312333
After setting up authentication:

docs/examples.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ Welcome to the DAPI examples collection! These comprehensive tutorials demonstra
88
Choose an example above and click "Try on DesignSafe" to begin your computational research journey!
99

1010
Each example is self-contained and includes:
11+
1112
- ✅ Complete, runnable code
1213
- ✅ Step-by-step explanations
1314
- ✅ Real-world applications

docs/examples/apps.md

Lines changed: 225 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,225 @@
1+
# App Discovery and Management
2+
3+
This guide demonstrates how to discover and examine Tapis applications available on DesignSafe using the dapi library.
4+
5+
## Basic Setup
6+
7+
```python
8+
from dapi import DSClient
9+
10+
# Initialize the client (will prompt for credentials if needed)
11+
ds = DSClient()
12+
```
13+
14+
## Finding Applications
15+
16+
### Find All Available Apps
17+
18+
```python
19+
# Get a list of all available applications
20+
all_apps = ds.apps.find("", verbose=False)
21+
print(f"Found {len(all_apps)} total apps.")
22+
```
23+
24+
### Search for Specific Apps
25+
26+
```python
27+
# Search for applications containing "mpm" in the name
28+
mpm_apps = ds.apps.find("mpm", verbose=True)
29+
```
30+
31+
The `verbose=True` option will display a formatted list of matching applications with their versions and owners.
32+
33+
### Search for Other Common Applications
34+
35+
```python
36+
# Find MATLAB apps
37+
matlab_apps = ds.apps.find("matlab", verbose=True)
38+
39+
# Find OpenSees apps
40+
opensees_apps = ds.apps.find("opensees", verbose=True)
41+
42+
# Find ADCIRC apps
43+
adcirc_apps = ds.apps.find("adcirc", verbose=True)
44+
45+
# Find OpenFOAM apps
46+
openfoam_apps = ds.apps.find("openfoam", verbose=True)
47+
```
48+
49+
## Getting Application Details
50+
51+
### Basic App Information
52+
53+
```python
54+
# Get detailed information for a specific application
55+
app_id = "opensees-express"
56+
app_details = ds.apps.get_details(app_id, verbose=True)
57+
58+
if app_details:
59+
print(f"App ID: {app_details.id}")
60+
print(f"Version: {app_details.version}")
61+
print(f"Description: {app_details.description}")
62+
print(f"Owner: {app_details.owner}")
63+
print(f"Execution System: {app_details.jobAttributes.execSystemId}")
64+
else:
65+
print(f"App '{app_id}' not found")
66+
```
67+
68+
### Understanding App Parameters
69+
70+
Applications define their input requirements through parameters. Here's how to examine them:
71+
72+
```python
73+
app_details = ds.apps.get_details("opensees-express")
74+
job_attrs = app_details.jobAttributes
75+
param_set = job_attrs.parameterSet
76+
77+
# Check file inputs
78+
print("File Inputs:")
79+
for file_input in job_attrs.fileInputs:
80+
print(f" - {file_input.name}: {file_input.description}")
81+
82+
# Check app arguments
83+
print("\nApp Arguments:")
84+
for arg in param_set.appArgs:
85+
print(f" - {arg.name}: {arg.description}")
86+
87+
# Check environment variables
88+
print("\nEnvironment Variables:")
89+
for env_var in param_set.envVariables:
90+
print(f" - {env_var.key}: {env_var.description}")
91+
if hasattr(env_var, 'enum_values') and env_var.enum_values:
92+
print(f" Options: {list(env_var.enum_values.keys())}")
93+
```
94+
95+
### Resource Requirements
96+
97+
```python
98+
# Check default resource requirements
99+
job_attrs = app_details.jobAttributes
100+
print(f"Default node count: {job_attrs.nodeCount}")
101+
print(f"Default cores per node: {job_attrs.coresPerNode}")
102+
print(f"Default memory (MB): {job_attrs.memoryMB}")
103+
print(f"Default max minutes: {job_attrs.maxMinutes}")
104+
print(f"Default queue: {job_attrs.execSystemLogicalQueue}")
105+
```
106+
107+
## Working with App Data as DataFrames
108+
109+
For analysis and comparison, you can convert app data to pandas DataFrames:
110+
111+
```python
112+
import pandas as pd
113+
114+
# Get all apps and convert to DataFrame
115+
all_apps = ds.apps.find("", verbose=False)
116+
117+
# Extract basic app information
118+
app_data = []
119+
for app in all_apps:
120+
app_data.append({
121+
'id': app.id,
122+
'version': app.version,
123+
'owner': app.owner,
124+
'description': app.description,
125+
'enabled': app.enabled,
126+
'execution_system': getattr(app.jobAttributes, 'execSystemId', 'N/A'),
127+
'max_minutes': getattr(app.jobAttributes, 'maxMinutes', 'N/A'),
128+
'node_count': getattr(app.jobAttributes, 'nodeCount', 'N/A'),
129+
'cores_per_node': getattr(app.jobAttributes, 'coresPerNode', 'N/A'),
130+
})
131+
132+
apps_df = pd.DataFrame(app_data)
133+
print(apps_df.head())
134+
135+
# Filter for specific types of applications
136+
simulation_apps = apps_df[apps_df['description'].str.contains('simulation', case=False, na=False)]
137+
print(f"\nFound {len(simulation_apps)} simulation apps")
138+
```
139+
140+
## Advanced: Accessing the Raw Tapis Client
141+
142+
If you need to access Tapis APIs that aren't wrapped by dapi, you can get the underlying Tapis client:
143+
144+
```python
145+
# Get the raw Tapis client for advanced operations
146+
tapis_client = ds.tapis
147+
148+
# Example: Get raw app details using Tapis client directly
149+
raw_app_details = tapis_client.apps.getApp(appId="opensees-express")
150+
print(f"Raw app data: {raw_app_details}")
151+
152+
# Example: List apps with custom parameters
153+
raw_apps = tapis_client.apps.getApps(search="*mpm*", listType="ALL")
154+
print(f"Found {len(raw_apps)} raw apps")
155+
156+
# Example: Access other Tapis services
157+
systems = tapis_client.systems.getSystems()
158+
print(f"Available systems: {len(systems)}")
159+
```
160+
161+
### When to Use the Raw Tapis Client
162+
163+
Use `ds.tapis` when you need to:
164+
165+
- Access Tapis APIs not yet wrapped by dapi
166+
- Use advanced search parameters not exposed by dapi
167+
- Implement custom functionality
168+
- Debug or troubleshoot API calls
169+
- Access experimental or new Tapis features
170+
171+
!!! warning "Using Raw Tapis Client"
172+
When using the raw Tapis client, you'll need to handle errors and data formatting yourself. The dapi wrapper provides error handling and user-friendly formatting that you'll lose with direct Tapis calls.
173+
174+
## Common App Categories
175+
176+
Here are some common application categories available on DesignSafe:
177+
178+
```python
179+
# Structural analysis applications
180+
structural_keywords = ["opensees", "abaqus", "ansys", "ls-dyna"]
181+
182+
# Fluid dynamics applications
183+
fluid_keywords = ["openfoam", "adcirc", "swan"]
184+
185+
# Geotechnical applications
186+
geo_keywords = ["mpm", "plaxis", "flac"]
187+
188+
# Materials applications
189+
materials_keywords = ["lammps", "matlab"]
190+
191+
# Search for each category
192+
for category, keywords in [
193+
("Structural", structural_keywords),
194+
("Fluid Dynamics", fluid_keywords),
195+
("Geotechnical", geo_keywords),
196+
("Materials", materials_keywords)
197+
]:
198+
print(f"\n{category} Applications:")
199+
for keyword in keywords:
200+
apps = ds.apps.find(keyword, verbose=False)
201+
if apps:
202+
print(f" {keyword}: {len(apps)} apps found")
203+
```
204+
205+
## Next Steps
206+
207+
After discovering applications, you can:
208+
209+
1. **[Submit jobs](../jobs.md)** using the discovered applications
210+
2. **[Explore job examples](mpm.md)** for specific workflows
211+
3. **[Check system resources](../api/systems.md)** for execution requirements
212+
4. **[Manage files](../api/files.md)** for job inputs and outputs
213+
214+
## Troubleshooting
215+
216+
### App Not Found
217+
If an application isn't found, it might be:
218+
- Disabled temporarily
219+
- Only available to specific users
220+
- Spelled differently than expected
221+
222+
Try broader searches or contact DesignSafe support.
223+
224+
### Access Issues
225+
Some applications might require special permissions or allocations. Check with your project team or DesignSafe support if you can't access expected applications.

docs/examples/mpm.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@ This comprehensive example demonstrates how to submit and monitor a Material Poi
44

55
[![Try on DesignSafe](https://raw.githubusercontent.com/DesignSafe-CI/dapi/main/DesignSafe-Badge.svg)](https://jupyter.designsafe-ci.org/hub/user-redirect/lab/tree/CommunityData/dapi/mpm/mpm-minimal.ipynb)
66

7+
> More detailed example
8+
[![Try on DesignSafe](https://raw.githubusercontent.com/DesignSafe-CI/dapi/main/DesignSafe-Badge.svg)](https://jupyter.designsafe-ci.org/hub/user-redirect/lab/tree/CommunityData/dapi/mpm/mpm.ipynb)
9+
10+
711
## 🎯 Overview
812

913
This example covers:

0 commit comments

Comments
 (0)