File size: 3,778 Bytes
bd60587
 
b43904d
bd60587
70226ac
b43904d
bd60587
 
 
 
 
 
 
 
 
 
 
 
70226ac
 
 
 
 
 
bd60587
 
70226ac
bd60587
70226ac
 
bd60587
 
 
 
 
 
 
 
b43904d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4d115e9
 
b43904d
 
bd60587
b43904d
bd60587
70226ac
bd60587
 
 
 
b43904d
 
bd60587
b43904d
 
bd60587
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
"""Precompute the demo's example reservoirs on the Space's GPU, through its /generate endpoint (same model and
sampler as the live demo). Needs a Hugging Face token (huggingface-cli login).
    python make_examples.py NAME     -> examples/NAME.npz"""
import io, json, sys, time
import urllib.request
import numpy as np
from huggingface_hub import get_token
from matplotlib.path import Path

SPACE = 'https://baghishov-resflow-demo.hf.space'
Z = 32
WELL_LOGS = {                                              # as in backend.py: base (z = 0) to top, 1 sand, 0 mud
    'Two sand bodies': [0] * 6 + [1] * 7 + [0] * 7 + [1] * 8 + [0] * 4,
    'Thick sand at the base': [1] * 14 + [0] * 18,
}
HEADERS = {'Authorization': f'Bearer {get_token()}'}


def fetch(url, data=None):
    req = urllib.request.Request(url, data=None if data is None else json.dumps(data).encode(),
                                 headers={**HEADERS, 'Content-Type': 'application/json'})
    return urllib.request.urlopen(req, timeout=900)


def call(api, data):
    """Run a Gradio API endpoint and return its output list."""
    eid = json.load(fetch(f'{SPACE}/gradio_api/call/{api}', {'data': data}))['event_id']
    event = None
    with fetch(f'{SPACE}/gradio_api/call/{api}/{eid}') as r:
        for line in (l.decode().rstrip('\n') for l in r):
            if line.startswith('event:'):
                event = line[6:].strip()
            elif line.startswith('data:') and event in ('complete', 'error'):
                if event == 'error':
                    raise RuntimeError(line)
                return json.loads(line[5:])
    raise RuntimeError('stream ended without a result')


def blob(nx, ny, seed=3):
    """An irregular reservoir outline: a smooth random closed curve."""
    rng = np.random.default_rng(seed)
    t = np.linspace(0, 2 * np.pi, 400)
    r = 0.36 + sum(rng.uniform(0.02, 0.06) * np.cos(k * t + rng.uniform(0, 6.3)) for k in range(2, 6))
    x, y = 0.5 + r * np.cos(t), 0.5 + 0.9 * r * np.sin(t)
    gx, gy = np.meshgrid((np.arange(nx) + .5) / nx, (np.arange(ny) + .5) / ny, indexing='ij')
    return Path(np.c_[x, y]).contains_points(np.c_[gx.ravel(), gy.ravel()]).reshape(nx, ny)


EX = {
    'lobe_outline': dict(title='Deep-water lobes, irregular outline, two wells', label='Lobe (deep-water)', nx=256, ny=256,
                         azimuth=45.0, outline=True,
                         wells=[(96, 120, 'Two sand bodies'), (168, 104, 'Thick sand at the base')]),
    'meander_strip': dict(title='Meander belt along flow', label='Meander (oxbow)', nx=384, ny=128, azimuth=0.0,
                          outline=False, wells=[]),
}
name = sys.argv[1]; e = EX[name]
wells = [(x, y, WELL_LOGS[log]) for x, y, log in e['wells']]
t = time.time()
out = call('generate', [e['label'], e['nx'], e['ny'], json.dumps(wells), 50, 0, json.dumps({'azimuth': e['azimuth']})])
z = np.load(io.BytesIO(fetch(out[0]['url']).read()))
f = z['facies']
params = {k: float(z[k]) for k in z.files if k not in ('facies', 'active', 'environment')}
for x, y, log in wells:                                    # wells must be honoured exactly
    assert (f[x, y] == np.array(log)).all(), f'well ({x}, {y}) not honoured'
active = blob(e['nx'], e['ny']) if e['outline'] else np.ones((e['nx'], e['ny']), bool)
np.savez_compressed(f'examples/{name}.npz', facies=f, active=active,
                    wells=np.array([[x, y] + list(log) for x, y, log in wells], np.int16).reshape(-1, 2 + Z),
                    meta=json.dumps({'title': e['title'], 'label': e['label'], 'nx': e['nx'], 'ny': e['ny'],
                                     'params': params, 'steps': 50, 'seed': 0}))
print(f'{name}: {f.shape}, sand {f[active].mean():.2f}, wells honoured {len(wells)}, {time.time() - t:.0f}s', flush=True)