638 lines
19 KiB
Python
638 lines
19 KiB
Python
"""
|
||
地震体 API 模拟服务器
|
||
|
||
用于模拟地震体相关的 API 接口,用于测试 DDMS 合规性验证软件。
|
||
"""
|
||
|
||
import json
|
||
import logging
|
||
import uuid
|
||
import time
|
||
import random
|
||
from typing import Dict, Any, List, Optional, Tuple
|
||
from flask import Flask, request, jsonify, Response, send_file
|
||
import io
|
||
import numpy as np
|
||
|
||
# 配置日志
|
||
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
|
||
logger = logging.getLogger(__name__)
|
||
|
||
app = Flask(__name__)
|
||
|
||
# 内存数据存储
|
||
seismic_files = {} # 存储地震体文件信息
|
||
export_tasks = {} # 存储导出任务信息
|
||
import_tasks = {} # 存储导入任务信息
|
||
seismic_data = {} # 存储地震体数据
|
||
|
||
# 生成唯一ID
|
||
def generate_id():
|
||
current_time = int(time.time() * 1000)
|
||
return f"{current_time}_{random.randint(1, 10)}"
|
||
|
||
# 初始化一些样例数据
|
||
def init_sample_data():
|
||
# 添加一个样例地震体
|
||
sample_seismic_id = "20221113181927_1"
|
||
seismic_files[sample_seismic_id] = {
|
||
"projectId": "testPrj1",
|
||
"surveyId": "20230117135924_2",
|
||
"seismicName": "Sample_Seismic",
|
||
"dsType": 1,
|
||
"dimensions": [
|
||
{
|
||
"dimensionNo": 1,
|
||
"dimensionName": "inline",
|
||
"serviceMin": 1,
|
||
"serviceMax": 100,
|
||
"serviceSpan": 1
|
||
},
|
||
{
|
||
"dimensionNo": 2,
|
||
"dimensionName": "xline",
|
||
"serviceMin": 1,
|
||
"serviceMax": 100,
|
||
"serviceSpan": 1
|
||
},
|
||
{
|
||
"dimensionNo": 3,
|
||
"dimensionName": "slice",
|
||
"serviceMin": 3500,
|
||
"serviceMax": 3600,
|
||
"serviceSpan": 4
|
||
}
|
||
]
|
||
}
|
||
|
||
# 初始化地震体数据 (简单的随机数据)
|
||
seismic_data[sample_seismic_id] = {
|
||
"traces": {}, # 存储道数据 {(inline, xline): values}
|
||
"h3200": b"Sample 3200 Header Data",
|
||
"h400": b"Sample 400 Header Data",
|
||
"h240": {1: b"Sample 240 Header Data for trace 1"},
|
||
"keywords": {
|
||
"h400": [{"name": "Sample H400 Keyword", "value": "Sample Value"}],
|
||
"h240": [{"name": "Sample H240 Keyword", "value": "Sample Value"}],
|
||
"gather": [{"name": "Sample Gather Keyword", "value": "Sample Value"}]
|
||
},
|
||
"coordinates": {
|
||
# 坐标映射 {(x, y): (inline, xline)}
|
||
(606406.1281141682, 6082083.338731234): (440, 333),
|
||
(609767.8725899048, 6080336.549935018): (366, 465),
|
||
(615271.9052119441, 6082017.422172886): (427, 686),
|
||
(612173.8269695987, 6084291.543435885): (521, 566)
|
||
}
|
||
}
|
||
|
||
# 5.1.1 新建地震体文件
|
||
@app.route('/api/gsc/appmodel/api/v1/seismic/file/add', methods=['POST'])
|
||
def add_seismic_file():
|
||
try:
|
||
data = request.json
|
||
seismic_id = generate_id()
|
||
|
||
# 存储地震体信息
|
||
seismic_files[seismic_id] = data
|
||
|
||
# 初始化地震体数据
|
||
seismic_data[seismic_id] = {
|
||
"traces": {},
|
||
"h3200": b"Default 3200 Header Data",
|
||
"h400": b"Default 400 Header Data",
|
||
"h240": {},
|
||
"keywords": {
|
||
"h400": [],
|
||
"h240": [],
|
||
"gather": []
|
||
},
|
||
"coordinates": {}
|
||
}
|
||
|
||
return jsonify({
|
||
"code": "0",
|
||
"msg": "",
|
||
"flag": True,
|
||
"result": seismic_id
|
||
})
|
||
except Exception as e:
|
||
logger.error(f"Error adding seismic file: {e}")
|
||
return jsonify({
|
||
"code": "1",
|
||
"msg": str(e),
|
||
"flag": False,
|
||
"result": None
|
||
}), 500
|
||
|
||
# 5.1.2 Inline 写入三维地震体文件
|
||
@app.route('/api/gsc/appmodel/api/v1/seismic/3d/inline/writer/array', methods=['POST'])
|
||
def write_inline_array():
|
||
try:
|
||
data = request.json
|
||
seismic_id = data.get('seismicId')
|
||
inline_no = data.get('inlineNo')
|
||
values = data.get('values', [])
|
||
|
||
if seismic_id not in seismic_data:
|
||
return jsonify({
|
||
"msg": "Seismic file not found",
|
||
"code": 1,
|
||
"result": ""
|
||
}), 404
|
||
|
||
# 存储道数据
|
||
for xline_idx, trace_values in enumerate(values[0]):
|
||
xline_no = seismic_files[seismic_id]['dimensions'][1]['serviceMin'] + xline_idx
|
||
seismic_data[seismic_id]["traces"][(inline_no, xline_no)] = trace_values
|
||
|
||
return jsonify({
|
||
"msg": "success",
|
||
"code": 0,
|
||
"result": ""
|
||
})
|
||
except Exception as e:
|
||
logger.error(f"Error writing inline array: {e}")
|
||
return jsonify({
|
||
"msg": str(e),
|
||
"code": 1,
|
||
"result": ""
|
||
}), 500
|
||
|
||
# 5.1.3 3D 任意道写入三维地震体文件
|
||
@app.route('/api/gsc/appmodel/api/v1/seismic/3d/writer/any/array', methods=['POST'])
|
||
def write_any_array():
|
||
try:
|
||
data = request.json
|
||
seismic_id = data.get('seismicId')
|
||
traces = data.get('traces', [])
|
||
|
||
if seismic_id not in seismic_data:
|
||
return jsonify({
|
||
"msg": "Seismic file not found",
|
||
"code": 1,
|
||
"result": ""
|
||
}), 404
|
||
|
||
# 存储道数据
|
||
for trace in traces:
|
||
inline_no = trace.get('inlineNo')
|
||
xline_no = trace.get('xlineNo')
|
||
values = trace.get('values', [])
|
||
seismic_data[seismic_id]["traces"][(inline_no, xline_no)] = values
|
||
|
||
return jsonify({
|
||
"msg": "success",
|
||
"code": 0,
|
||
"result": ""
|
||
})
|
||
except Exception as e:
|
||
logger.error(f"Error writing any array: {e}")
|
||
return jsonify({
|
||
"msg": str(e),
|
||
"code": 1,
|
||
"result": ""
|
||
}), 500
|
||
|
||
# 5.1.4 导出地震体—提交任务
|
||
@app.route('/api/gsc/appmodel/api/v1/seismic/export/submit', methods=['POST'])
|
||
def submit_export():
|
||
try:
|
||
data = request.json
|
||
seismic_id = data.get('seismicId')
|
||
|
||
if seismic_id not in seismic_data:
|
||
return jsonify({
|
||
"code": "1",
|
||
"msg": "Seismic file not found",
|
||
"flag": False,
|
||
"result": None
|
||
}), 404
|
||
|
||
# 创建导出任务
|
||
task_id = f"export_{generate_id()}"
|
||
export_tasks[task_id] = {
|
||
"seismicId": seismic_id,
|
||
"status": "submitted",
|
||
"progress": 0,
|
||
"saveDir": data.get('saveDir', f"/export/{seismic_id}.sgy")
|
||
}
|
||
|
||
# 模拟任务开始处理
|
||
def process_task():
|
||
for i in range(1, 11):
|
||
export_tasks[task_id]["progress"] = i * 10
|
||
time.sleep(0.5) # 模拟处理时间
|
||
export_tasks[task_id]["status"] = "completed"
|
||
|
||
# 启动后台线程处理任务
|
||
import threading
|
||
thread = threading.Thread(target=process_task)
|
||
thread.daemon = True
|
||
thread.start()
|
||
|
||
return jsonify({
|
||
"code": "0",
|
||
"msg": "操作成功!",
|
||
"flag": True,
|
||
"result": {
|
||
"taskId": task_id,
|
||
"status": "submitted",
|
||
"progress": 0
|
||
}
|
||
})
|
||
except Exception as e:
|
||
logger.error(f"Error submitting export task: {e}")
|
||
return jsonify({
|
||
"code": "1",
|
||
"msg": str(e),
|
||
"flag": False,
|
||
"result": None
|
||
}), 500
|
||
|
||
# 5.1.5 导出地震体—查询进度
|
||
@app.route('/api/gsc/appmodel/api/v1/seismic/export/progress', methods=['GET'])
|
||
def query_export_progress():
|
||
try:
|
||
task_id = request.args.get('taskId')
|
||
|
||
if task_id not in export_tasks:
|
||
return jsonify({
|
||
"code": "1",
|
||
"msg": "Task not found",
|
||
"flag": False,
|
||
"result": None
|
||
}), 404
|
||
|
||
task = export_tasks[task_id]
|
||
|
||
return jsonify({
|
||
"code": "0",
|
||
"msg": "操作成功!",
|
||
"flag": True,
|
||
"result": {
|
||
"taskId": task_id,
|
||
"status": task["status"],
|
||
"progress": task["progress"]
|
||
}
|
||
})
|
||
except Exception as e:
|
||
logger.error(f"Error querying export progress: {e}")
|
||
return jsonify({
|
||
"code": "1",
|
||
"msg": str(e),
|
||
"flag": False,
|
||
"result": None
|
||
}), 500
|
||
|
||
# 5.1.6 导出地震体—下载
|
||
@app.route('/api/gsc/appmodel/api/v1/seismic/export/download', methods=['GET'])
|
||
def download_export():
|
||
try:
|
||
task_id = request.args.get('taskId')
|
||
|
||
if task_id not in export_tasks:
|
||
return jsonify({
|
||
"code": "1",
|
||
"msg": "Task not found",
|
||
"flag": False,
|
||
"result": None
|
||
}), 404
|
||
|
||
task = export_tasks[task_id]
|
||
|
||
if task["status"] != "completed":
|
||
return jsonify({
|
||
"code": "1",
|
||
"msg": "Task not completed",
|
||
"flag": False,
|
||
"result": None
|
||
}), 400
|
||
|
||
# 创建一个模拟的SEG-Y文件
|
||
dummy_segy = io.BytesIO()
|
||
# 添加一些随机二进制数据
|
||
dummy_segy.write(b"FAKE SEGY FILE CONTENT")
|
||
dummy_segy.seek(0)
|
||
|
||
# 如果 delFile 参数设置为 true,删除任务
|
||
if request.args.get('delFile') == '1':
|
||
export_tasks.pop(task_id, None)
|
||
|
||
return send_file(
|
||
dummy_segy,
|
||
mimetype='application/octet-stream',
|
||
as_attachment=True,
|
||
download_name=f"seismic_{task['seismicId']}.sgy"
|
||
)
|
||
except Exception as e:
|
||
logger.error(f"Error downloading export: {e}")
|
||
return jsonify({
|
||
"code": "1",
|
||
"msg": str(e),
|
||
"flag": False,
|
||
"result": None
|
||
}), 500
|
||
|
||
# 5.1.7 查询地震体 3200 头
|
||
@app.route('/api/gsc/appmodel/api/v1/seismic/head/h3200', methods=['POST'])
|
||
def get_h3200():
|
||
try:
|
||
data = request.json
|
||
seismic_id = data.get('seismicId')
|
||
|
||
if seismic_id not in seismic_data:
|
||
return jsonify({
|
||
"code": "1",
|
||
"msg": "Seismic file not found",
|
||
"flag": False,
|
||
"result": None
|
||
}), 404
|
||
|
||
# 返回二进制数据
|
||
return Response(
|
||
seismic_data[seismic_id]["h3200"],
|
||
mimetype='application/octet-stream'
|
||
)
|
||
except Exception as e:
|
||
logger.error(f"Error getting h3200: {e}")
|
||
return jsonify({
|
||
"code": "1",
|
||
"msg": str(e),
|
||
"flag": False,
|
||
"result": None
|
||
}), 500
|
||
|
||
# 5.1.8 查询地震体 400 头
|
||
@app.route('/api/gsc/appmodel/api/v1/seismic/head/h400', methods=['POST'])
|
||
def get_h400():
|
||
try:
|
||
data = request.json
|
||
seismic_id = data.get('seismicId')
|
||
|
||
if seismic_id not in seismic_data:
|
||
return jsonify({
|
||
"code": "1",
|
||
"msg": "Seismic file not found",
|
||
"flag": False,
|
||
"result": None
|
||
}), 404
|
||
|
||
# 返回二进制数据
|
||
return Response(
|
||
seismic_data[seismic_id]["h400"],
|
||
mimetype='application/octet-stream'
|
||
)
|
||
except Exception as e:
|
||
logger.error(f"Error getting h400: {e}")
|
||
return jsonify({
|
||
"code": "1",
|
||
"msg": str(e),
|
||
"flag": False,
|
||
"result": None
|
||
}), 500
|
||
|
||
# 5.1.9 查询地震体总道数
|
||
@app.route('/api/gsc/appmodel/api/v1/seismic/traces/count', methods=['POST'])
|
||
def get_traces_count():
|
||
try:
|
||
data = request.json
|
||
seismic_id = data.get('seismicId')
|
||
|
||
if seismic_id not in seismic_data:
|
||
return jsonify({
|
||
"code": "1",
|
||
"msg": "Seismic file not found",
|
||
"flag": False,
|
||
"result": None
|
||
}), 404
|
||
|
||
# 获取道数
|
||
trace_count = len(seismic_data[seismic_id]["traces"])
|
||
|
||
return jsonify({
|
||
"msg": "success",
|
||
"code": 0,
|
||
"result": str(trace_count)
|
||
})
|
||
except Exception as e:
|
||
logger.error(f"Error getting traces count: {e}")
|
||
return jsonify({
|
||
"msg": str(e),
|
||
"code": 1,
|
||
"result": ""
|
||
}), 500
|
||
|
||
# 5.1.10 查询地震体 240 头
|
||
@app.route('/api/gsc/appmodel/api/v1/seismic/head/h240', methods=['POST'])
|
||
def get_h240():
|
||
try:
|
||
data = request.json
|
||
seismic_id = data.get('seismicId')
|
||
trace_index = data.get('traceIndex')
|
||
|
||
if seismic_id not in seismic_data:
|
||
return jsonify({
|
||
"code": "1",
|
||
"msg": "Seismic file not found",
|
||
"flag": False,
|
||
"result": None
|
||
}), 404
|
||
|
||
# 获取道头数据
|
||
if trace_index not in seismic_data[seismic_id]["h240"]:
|
||
# 如果不存在,生成一个随机的道头数据
|
||
seismic_data[seismic_id]["h240"][trace_index] = f"Sample 240 Header Data for trace {trace_index}".encode()
|
||
|
||
# 返回二进制数据
|
||
return Response(
|
||
seismic_data[seismic_id]["h240"][trace_index],
|
||
mimetype='application/octet-stream'
|
||
)
|
||
except Exception as e:
|
||
logger.error(f"Error getting h240: {e}")
|
||
return jsonify({
|
||
"code": "1",
|
||
"msg": str(e),
|
||
"flag": False,
|
||
"result": None
|
||
}), 500
|
||
|
||
# 5.1.11 查询地震体卷头关键字信息
|
||
@app.route('/api/gsc/appmodel/api/v1/seismic/h400/keyword/list', methods=['POST'])
|
||
def get_h400_keywords():
|
||
try:
|
||
data = request.json
|
||
seismic_id = data.get('seismicId')
|
||
|
||
if seismic_id not in seismic_data:
|
||
return jsonify({
|
||
"code": "1",
|
||
"msg": "Seismic file not found",
|
||
"flag": False,
|
||
"result": None
|
||
}), 404
|
||
|
||
return jsonify({
|
||
"flag": True,
|
||
"msg": "success",
|
||
"code": 0,
|
||
"result": seismic_data[seismic_id]["keywords"]["h400"]
|
||
})
|
||
except Exception as e:
|
||
logger.error(f"Error getting h400 keywords: {e}")
|
||
return jsonify({
|
||
"flag": False,
|
||
"msg": str(e),
|
||
"code": 1,
|
||
"result": None
|
||
}), 500
|
||
|
||
# 5.1.12 查询地震体道头关键字信息
|
||
@app.route('/api/gsc/appmodel/api/v1/seismic/h240/keyword/list', methods=['POST'])
|
||
def get_h240_keywords():
|
||
try:
|
||
data = request.json
|
||
seismic_id = data.get('seismicId')
|
||
|
||
if seismic_id not in seismic_data:
|
||
return jsonify({
|
||
"code": "1",
|
||
"msg": "Seismic file not found",
|
||
"flag": False,
|
||
"result": None
|
||
}), 404
|
||
|
||
return jsonify({
|
||
"flag": True,
|
||
"msg": "success",
|
||
"code": 0,
|
||
"result": seismic_data[seismic_id]["keywords"]["h240"]
|
||
})
|
||
except Exception as e:
|
||
logger.error(f"Error getting h240 keywords: {e}")
|
||
return jsonify({
|
||
"flag": False,
|
||
"msg": str(e),
|
||
"code": 1,
|
||
"result": None
|
||
}), 500
|
||
|
||
# 5.1.13 查询地震体道集关键字信息
|
||
@app.route('/api/gsc/appmodel/api/v1/seismic/gather/keyword/list', methods=['POST'])
|
||
def get_gather_keywords():
|
||
try:
|
||
data = request.json
|
||
seismic_id = data.get('seismicId')
|
||
|
||
if seismic_id not in seismic_data:
|
||
return jsonify({
|
||
"code": "1",
|
||
"msg": "Seismic file not found",
|
||
"flag": False,
|
||
"result": None
|
||
}), 404
|
||
|
||
return jsonify({
|
||
"flag": True,
|
||
"msg": "success",
|
||
"code": 0,
|
||
"result": seismic_data[seismic_id]["keywords"]["gather"]
|
||
})
|
||
except Exception as e:
|
||
logger.error(f"Error getting gather keywords: {e}")
|
||
return jsonify({
|
||
"flag": False,
|
||
"msg": str(e),
|
||
"code": 1,
|
||
"result": None
|
||
}), 500
|
||
|
||
# 5.1.14 导入地震体—查询进度
|
||
@app.route('/api/gsc/appmodel/api/v1/seismic/import/progress', methods=['POST'])
|
||
def query_import_progress():
|
||
try:
|
||
data = request.json
|
||
seismic_id = data.get('seismicId')
|
||
|
||
if seismic_id not in seismic_data:
|
||
return jsonify({
|
||
"code": "1",
|
||
"msg": "Seismic file not found",
|
||
"flag": False,
|
||
"result": None
|
||
}), 404
|
||
|
||
# 检查是否存在导入任务
|
||
task_id = f"import_{seismic_id}"
|
||
if task_id not in import_tasks:
|
||
# 创建一个模拟的导入任务
|
||
import_tasks[task_id] = {
|
||
"seismicId": seismic_id,
|
||
"status": "completed",
|
||
"progress": 100
|
||
}
|
||
|
||
task = import_tasks[task_id]
|
||
|
||
return jsonify({
|
||
"msg": "success",
|
||
"code": 0,
|
||
"result": {
|
||
"taskId": task_id,
|
||
"status": task["status"],
|
||
"progress": task["progress"]
|
||
}
|
||
})
|
||
except Exception as e:
|
||
logger.error(f"Error querying import progress: {e}")
|
||
return jsonify({
|
||
"msg": str(e),
|
||
"code": 1,
|
||
"result": None
|
||
}), 500
|
||
|
||
# 5.1.15 查询地震体点线坐标
|
||
@app.route('/api/gsc/appmodel/api/v1/seismic/coordinate/geodetic/toline', methods=['POST'])
|
||
def convert_coordinates():
|
||
try:
|
||
data = request.json
|
||
seismic_id = data.get('seismicId')
|
||
points = data.get('points', [])
|
||
|
||
if seismic_id not in seismic_data:
|
||
return jsonify({
|
||
"code": "1",
|
||
"msg": "Seismic file not found",
|
||
"flag": False,
|
||
"result": None
|
||
}), 404
|
||
|
||
# 转换坐标
|
||
result = []
|
||
for point in points:
|
||
x, y = point
|
||
# 查找最接近的已知坐标点
|
||
if (x, y) in seismic_data[seismic_id]["coordinates"]:
|
||
result.append(list(seismic_data[seismic_id]["coordinates"][(x, y)]))
|
||
else:
|
||
# 如果找不到精确匹配,返回模拟数据
|
||
result.append([random.randint(1, 100), random.randint(1, 100)])
|
||
|
||
return jsonify({
|
||
"msg": "success",
|
||
"code": 0,
|
||
"result": result
|
||
})
|
||
except Exception as e:
|
||
logger.error(f"Error converting coordinates: {e}")
|
||
return jsonify({
|
||
"msg": str(e),
|
||
"code": 1,
|
||
"result": None
|
||
}), 500
|
||
|
||
# 初始化样例数据
|
||
init_sample_data()
|
||
|
||
if __name__ == '__main__':
|
||
app.run(host='0.0.0.0', port=5001, debug=True) |