# Use the existing connected PyFluent variable solver.
import math

task_directory = r"C:\Users\13977\AppData\Local\FluentAGI\data\runs\20261018-142547-90d0a4"
s = solver.settings

def checked(label, result):
    print(label, result)
    if isinstance(result, dict):
        if result.get("status") in ("error", "failed", "needs_review"):
            raise RuntimeError(str(result))
        if result.get("error") or result.get("errors"):
            raise RuntimeError(str(result))
    return result

def numbers(value):
    if isinstance(value, bool):
        return []
    if isinstance(value, (int, float)):
        return [float(value)]
    if isinstance(value, dict):
        return [number for child in value.values() for number in numbers(child)]
    if isinstance(value, (list, tuple)):
        return [number for child in value for number in numbers(child)]
    return []

def value_of(result, name):
    if isinstance(result, dict):
        if name in result:
            values = numbers(result[name])
            if values and math.isfinite(values[0]):
                return values[0]
        children = result.values()
    elif isinstance(result, (list, tuple)):
        children = result
    else:
        children = []
    for child in children:
        try:
            return value_of(child, name)
        except ValueError:
            pass
    raise ValueError("无法提取报告：" + name + "；返回：" + str(result))

if not s.setup.models.is_active():
    raise RuntimeError("当前网格未激活。")

reports = s.solution.report_definitions
if not reports.compute.is_active():
    raise RuntimeError("当前解报告不可用，停止并保留现有结果。")

print("CURRENT_SOLVER", s.setup.general.solver.get_state())
run = s.solution.run_calculation
if run.iter_count.is_active():
    print("CURRENT_ITERATION", run.iter_count.get_state())
if run.transient_controls.is_active():
    print("TRANSIENT_CONTROLS", run.transient_controls.get_state())

force_names = ["front_wing_drag_interface", "front_wing_lift_interface"]
for name in force_names:
    if name not in reports.force.get_object_names():
        raise RuntimeError("缺少受力报告：" + name)

wing_zones = reports.force[force_names[0]].zones.get_state()
lift_zones = reports.force[force_names[1]].zones.get_state()
if not wing_zones or set(wing_zones) != set(lift_zones):
    raise RuntimeError("升阻力统计区域为空或不一致。")
print("WING_FORCE_ZONES", wing_zones)

force_result = reports.compute(report_defs=force_names)
drag, lift = [value_of(force_result, name) for name in force_names]
reference_area = 0.552
denominator = 0.5 * 1.225 * 30.0**2 * reference_area
print("AERODYNAMIC_READBACK", {
    "drag": drag,
    "lift": lift,
    "downforce": -lift,
    "CD": drag / denominator,
    "CL": lift / denominator,
    "reference_area": reference_area,
})

mass_names = ["fw_inlet_mass", "fw_outlet_mass"]
if all(name in reports.surface.get_object_names() for name in mass_names):
    mass_result = reports.compute(report_defs=mass_names)
    mass_values = [value_of(mass_result, name) for name in mass_names]
    scale = max(max(abs(value) for value in mass_values), 1e-20)
    print("MASS_BALANCE_READBACK", {
        "inlet": mass_values[0],
        "outlet": mass_values[1],
        "relative_imbalance": abs(sum(mass_values)) / scale,
    })

time_reports = reports.time
time_name = "front_wing_actual_flow_time"
if time_name not in time_reports.get_object_names():
    time_reports[time_name] = {}
time_report = time_reports[time_name]
if "report_type" in getattr(time_report, "child_names", []):
    if time_report.report_type.is_active():
        options = time_report.report_type.allowed_values()
        candidates = [
            option for option in options
            if option in ["flow-time", "flow_time", "time-flow-time"]
        ]
        if candidates:
            time_report.report_type = candidates[0]
            print("ACTUAL_FLOW_TIME", reports.compute(report_defs=[time_name]))
        else:
            print("TIME_REPORT_OPTIONS", options)

paths = s.results.graphics.pathline
if not paths.is_active():
    raise RuntimeError("当前原生流线对象不可用。")

path_name = "front_wing_streamlines"
if path_name not in paths.get_object_names():
    paths[path_name] = {}
path = paths[path_name]
if not path.field.is_active():
    raise RuntimeError("流线着色字段未激活。")
if "velocity-magnitude" not in path.field.allowed_values():
    raise RuntimeError("流线速度着色字段不可用。")
path.field = "velocity-magnitude"
path.release_from_surfaces = ["inlet"]
print("STREAMLINE_CONFIGURATION", {
    "field": path.field.get_state(),
    "release_from_surfaces": path.release_from_surfaces.get_state(),
})
for name in ["step", "skip", "options", "accuracy_control"]:
    child = getattr(path, name)
    if child.is_active():
        print("STREAMLINE_CONTROL", name, child.get_state())

views = s.results.graphics.views
views.restore_view(view_name="isometric")
paths.display(object_name=path_name)
views.auto_scale()

picture = s.results.graphics.picture
if "save_picture" not in getattr(picture, "command_names", []):
    raise RuntimeError("原生图片保存命令不可用。")
command = picture.save_picture
if "file_name" not in getattr(command, "argument_names", []):
    raise RuntimeError("图片保存参数不匹配。")
streamline_file = task_directory + r"\front_wing_streamlines.png"
print("STREAMLINE_SAVE_RESULT", command(file_name=streamline_file))
print("STREAMLINE_SAVE_PATH", streamline_file)

checked(
    "WING_SURFACE_EXPORT",
    fluentagi.export_results(
        directory=task_directory,
        fields=["pressure", "velocity-magnitude"],
        surfaces=wing_zones,
    ),
)

s.file.write_case_data(
    file_name=task_directory + r"\front_wing_postprocessed_checkpoint.cas.h5"
)
print("POSTPROCESSING_SCOPE", {
    "initialized": False,
    "advanced_time_steps": 0,
    "streamlines": "instantaneous_velocity_field",
    "all_step_convergence_verified": False,
    "force_stability_verified": False,
    "mesh_independence_verified": False,
})