
import flow360 as fl
from flow360.examples import EVTOL

EVTOL.get_files()

project = fl.Project.from_geometry(EVTOL.geometry, name="sweep_evtol_from_geometry")

geometry = project.geometry
geometry.group_faces_by_tag("faceName")

with fl.SI_unit_system:
    meshing_params = fl.MeshingParams(
        defaults=fl.MeshingDefaults(
            boundary_layer_first_layer_thickness=1e-5, surface_max_edge_length=1
        ),
        volume_zones=[fl.AutomatedFarfield()],
        refinements=[
            fl.SurfaceEdgeRefinement(
                name="leading_edges",
                edges=[geometry["leadingEdge"]],
                method=fl.AngleBasedRefinement(value=2 * fl.u.deg),
            )
        ],
    )

models = [
    fl.Wall(surfaces=[geometry["*"]]),
    fl.Freestream(surfaces=fl.AutomatedFarfield().farfield),
]

with fl.SI_unit_system:
    params = fl.SimulationParams(
        meshing=meshing_params,
        reference_geometry=fl.ReferenceGeometry(
            moment_center=(0, 0, 0), moment_length=1, area=1
        ),
        operating_condition=fl.AerospaceCondition(
            velocity_magnitude=100, alpha=0 * fl.u.deg
        ),
        time_stepping=fl.Steady(max_steps=5000, CFL=fl.AdaptiveCFL()),
        models=[
            *models,
            fl.Fluid(
                navier_stokes_solver=fl.NavierStokesSolver(),
                turbulence_model_solver=fl.SpalartAllmaras(),
            ),
        ],
        outputs=[
            fl.VolumeOutput(
                output_format="tecplot",
                output_fields=[
                    "Mach",
                    "Cp",
                    "mut",
                    "mutRatio",
                    "primitiveVars",
                    "qcriterion",
                ],
            ),
            fl.SurfaceOutput(
                surfaces=[
                    geometry["fuselage"],
                    geometry["*pylon"],
                    geometry["*wing"],
                    geometry["*tail"],
                ],
                output_fields=[
                    "Cp",
                    "yPlus",
                    "Cf",
                    "CfVec",
                    "primitiveVars",
                    "wallDistance",
                ],
                output_format="tecplot",
            ),
        ],
    )

case_list = []

alphas = [-10, -5, 0, 5, 10, 12, 14] * fl.u.deg

for alpha_angle in alphas:
    params.operating_condition.alpha = alpha_angle

    case = project.run_case(params=params, name=f"alpha_{alpha_angle.value}_case")

    print(f"The case ID is: {case.id} with {alpha_angle=} ")
    case_list.append(case)

print("Waiting for cases to complete...")
for case in case_list:
    case.wait()
print("All cases completed.")

from flow360.plugins.report.report_items import Summary, Inputs

rep = fl.report

exclude_surfaces = ["fluid/farfield"]

top_camera = rep.TopCamera(
    pan_target=(3.5, 0, -0.5), dimension=15, dimension_dir="height"
)
bottom_camera = rep.BottomCamera(
    pan_target=(3.5, 0, -0.5), dimension=15, dimension_dir="height"
)
front_camera = rep.FrontCamera(
    pan_target=(3.5, 0, -0.5), dimension=15, dimension_dir="width"
)
rear_camera = rep.RearCamera(
    pan_target=(3.5, 0, -0.5), dimension=15, dimension_dir="width"
)
left_camera = rep.LeftCamera(
    pan_target=(3.5, 0, -0.5), dimension=10, dimension_dir="width"
)
right_camera = rep.Camera(
    pan_target=(3.5, 0, -0.5),
    position=(0.0, -1.0, 0.0),
    look_at=(0.0, 0.0, 0.0),
    up=(0.0, 0.0, 1.0),
    dimension=10,
    dimension_dir="width",
)
front_left_top_camera = rep.FrontLeftTopCamera(
    pan_target=(3.5, 0, -0.5), dimension=15, dimension_dir="width"
)
rear_right_bottom_camera = rep.RearRightBottomCamera(
    pan_target=(3.5, 0, -0.5), dimension=15, dimension_dir="width"
)

geo_cameras = [
    top_camera,
    bottom_camera,
    front_camera,
    rear_camera,
    left_camera,
    right_camera,
    front_left_top_camera,
    rear_right_bottom_camera,
]

geo_camera_names = [
    "top_camera",
    "bottom_camera",
    "front_camera",
    "rear_camera",
    "left_camera",
    "right_camera",
    "front_left_top_camera",
    "rear_right_bottom_camera",
]

avg = rep.Average(fraction=0.1)

force_list = [
    "CD",
    "CL",
    "CFx",
    "CFy",
    "CFz",
    "CMx",
    "CMy",
    "CMz",
]

CD = rep.DataItem(
    data="surface_forces/totalCD", exclude=exclude_surfaces, title="CD", operations=avg
)
CL = rep.DataItem(
    data="surface_forces/totalCL", exclude=exclude_surfaces, title="CL", operations=avg
)
CFX = rep.DataItem(
    data="surface_forces/totalCFx",
    exclude=exclude_surfaces,
    title="CFx",
    operations=avg,
)
CFY = rep.DataItem(
    data="surface_forces/totalCFy",
    exclude=exclude_surfaces,
    title="CFy",
    operations=avg,
)
CFZ = rep.DataItem(
    data="surface_forces/totalCFz",
    exclude=exclude_surfaces,
    title="CFz",
    operations=avg,
)
CMX = rep.DataItem(
    data="surface_forces/totalCMx",
    exclude=exclude_surfaces,
    title="CMx",
    operations=avg,
)
CMY = rep.DataItem(
    data="surface_forces/totalCMy",
    exclude=exclude_surfaces,
    title="CMy",
    operations=avg,
)
CMZ = rep.DataItem(
    data="surface_forces/totalCMz",
    exclude=exclude_surfaces,
    title="CMz",
    operations=avg,
)

table_data = [
    CD,
    CL,
    CFX,
    CFY,
    CFZ,
    CMX,
    CMY,
    CMZ,
]

def generate_report_items(
    params,
    table_data,
    force_list,
    geo_cameras,
    geo_camera_names,
    front_left_top_camera,
    exclude_surfaces,
    include_geometry: bool,
    include_general_tables: bool,
    include_residuals: bool,
    include_cfl: bool,
    include_forces_moments_table: bool,
    include_forces_moments_charts: bool,
    include_forces_moments_alpha_charts: bool,
    include_forces_moments_beta_charts: bool,
    include_cf_vec: bool,
    include_cp: bool,
    include_yplus: bool,
    include_qcriterion: bool,
):
    items = []

    if params.time_stepping.type_name == "Unsteady":
        step_type = "physical_step"
    else:
        step_type = "pseudo_step"

    for model in params.models:
        if model.type == "Fluid":
            turbulence_solver = model.turbulence_model_solver.type_name

    if include_geometry:
        geometry_screenshots = [
            rep.Chart3D(
                section_title="Geometry",
                items_in_row=2,
                force_new_page=True,
                show="boundaries",
                camera=front_left_top_camera,
                exclude=exclude_surfaces,
                fig_name="Geometry_view",
            )
        ]
        items.extend(geometry_screenshots)

    if include_general_tables:
        items.append(Summary())
        items.append(Inputs())

    if include_forces_moments_table:
        table = rep.Table(
            data=table_data,
            section_title="Quantities of interest",
        )
        items.append(table)

    if include_residuals:
        residual_chart = rep.NonlinearResiduals(
            force_new_page=True,
            section_title="Nonlinear residuals",
            fig_name=f"nonlin-res_fig",
        )
        items.append(residual_chart)

    if include_cfl and params.time_stepping.CFL.type == "adaptive":
        cfl_chart = rep.Chart2D(
            x=f"cfl/{step_type}",
            y=["cfl/0_NavierStokes_cfl", f"cfl/1_{turbulence_solver}_cfl"],
            force_new_page=True,
            section_title="CFL",
            fig_name="cfl_fig",
            y_log=True,
        )
        items.append(cfl_chart)

    if include_forces_moments_charts:
        force_charts = [
            rep.Chart2D(
                x=f"surface_forces/{step_type}",
                y=f"surface_forces/total{force}",
                force_new_page=True,
                section_title="Forces/Moments",
                fig_name=f"{force}_fig",
                exclude=exclude_surfaces,
                ylim=rep.SubsetLimit(subset=(0.5, 1), offset=0.25),
            )
            for force in force_list
        ]
        items.extend(force_charts)

    if include_forces_moments_alpha_charts:
        force_alpha_charts = [
            rep.Chart2D(
                x=f"params/operating_condition/alpha",
                y=f"total_forces/averages/{force}",
                force_new_page=True,
                section_title="Averaged Forces/Moments against alpha",
                fig_name=f"{force}_alpha_fig",
            )
            for force in force_list
        ]
        items.extend(force_alpha_charts)

    if include_forces_moments_beta_charts:
        force_beta_charts = [
            rep.Chart2D(
                x=f"params/operating_condition/beta",
                y=f"total_forces/averages/{force}",
                force_new_page=True,
                section_title="Averaged Forces/Moments against beta",
                fig_name=f"{force}_beta_fig",
            )
            for force in force_list
        ]
        items.extend(force_beta_charts)

    if include_yplus:
        y_plus_screenshots = [
            rep.Chart3D(
                caption=rep.PatternCaption(pattern=f"y+_{camera_name}_[case.name]"),
                show="boundaries",
                field="yPlus",
                exclude=exclude_surfaces,
                limits=(0, 5),
                camera=camera,
                fig_name=f"yplus_{camera_name}_fig",
                fig_size=1,
            )
            for camera_name, camera in zip(geo_camera_names, geo_cameras)
        ]
        items.extend(y_plus_screenshots)

    if include_cp:
        cp_screenshots = [
            rep.Chart3D(
                caption=rep.PatternCaption(pattern=f"Cp_{camera_name}_[case.name]"),
                show="boundaries",
                field="Cp",
                exclude=exclude_surfaces,
                limits=(-1, 1),
                camera=camera,
                fig_name=f"cp_{camera_name}_fig",
                fig_size=1,
            )
            for camera_name, camera in zip(geo_camera_names, geo_cameras)
        ]
        items.extend(cp_screenshots)

    if include_cf_vec:
        cfvec_screenshots = [
            rep.Chart3D(
                caption=rep.PatternCaption(pattern=f"Cf_vec_{camera_name}_[case.name]"),
                show="boundaries",
                field="CfVec",
                mode="lic",
                exclude=exclude_surfaces,
                limits=(0, 0.025),
                camera=camera,
                fig_name=f"cfvec_{camera_name}_fig",
                fig_size=1,
            )
            for camera_name, camera in zip(geo_camera_names, geo_cameras)
        ]
        items.extend(cfvec_screenshots)

    if include_qcriterion:
        qcriterion_screenshots = [
            rep.Chart3D(
                caption=rep.PatternCaption(
                    pattern=f"Isosurface_q_criterion_{camera_name}_[case.name]"
                ),
                show="isosurface",
                iso_field="qcriterion",
                exclude=exclude_surfaces,
                limits=(0, 0.8),
                camera=camera,
                fig_name=f"qcriterion_{camera_name}_fig",
                fig_size=1,
            )
            for camera_name, camera in zip(geo_camera_names, geo_cameras)
        ]
        items.extend(qcriterion_screenshots)

    return items

items = generate_report_items(
    params,
    table_data,
    force_list,
    geo_cameras,
    geo_camera_names,
    front_left_top_camera,
    exclude_surfaces,
    include_geometry=True,
    include_general_tables=True,
    include_residuals=True,
    include_cfl=True,
    include_forces_moments_table=True,
    include_forces_moments_charts=True,
    include_forces_moments_alpha_charts=True,
    include_forces_moments_beta_charts=True,
    include_cf_vec=True,
    include_cp=True,
    include_yplus=True,
    include_qcriterion=True,
)

report = rep.ReportTemplate(
    title="Sweep Template Report",
    items=items,
    settings=rep.Settings(dpi=150),
)

report = report.create_in_cloud(
    "sweep-script-report",
    case_list,
)

report.wait()
report.download("report.pdf")
print("Report downloaded as report.pdf")
