#! /usr/bin/env python
"""Rectangle compression workflow

Requires the following ``SConscript(..., exports=[])``

* ``env`` - The SCons construction environment with the following required keys

  * ``abaqus_source_abspath`` - String absolute path to the EABM's Abaqus journal files
  * ``python_source_abspath`` - String absolute path to the EABM's Python 3 files
  * ``datacheck_alias`` - String for the alias collecting the datacheck workflow targets
  * ``archive_prefix`` - String prefix for archive target(s) containing identifying project and version information
  * ``project_configuration`` - String absolute path to the project SCons configuration file
  * ``unconditional_build`` - Boolean flag to force building of conditionally ignored targets
  * ``abaqus`` - String path for the Abaqus executable
"""

import pathlib

import waves

from eabm_package.python.rectangle_compression_cartesian_product import parameter_schema

# Inherit the parent construction environment
Import('env')

# Comment used in tutorial code snippets: marker-1

# Set project-wide paths with os-agnostic path separators
python_source_abspath = pathlib.Path(env["python_source_abspath"])

# Simulation variables
build_directory = pathlib.Path(Dir('.').abspath)
workflow_name = build_directory.name
output_file_type = "h5"
parameter_study_file = build_directory / f"parameter_study.{output_file_type}"
previous_parameter_study = str(parameter_study_file) if parameter_study_file.exists() else None
model = "rectangle"
geometry_configuration = f"{model}_geometry_partition.scons"
simulation_configuration = f"{model}_mesh_solverprep_solve_extract.scons"
workflow_configuration = [env["project_configuration"], workflow_name,
                          geometry_configuration, simulation_configuration]

# Collect the target nodes to build a concise alias for all targets
workflow = []
datacheck = []

# Comment used in tutorial code snippets: marker-2

# Parameter Study with Cartesian Product
parameter_generator = waves.parameter_generators.CartesianProduct(
    parameter_schema,
    output_file=parameter_study_file,
    output_file_type=output_file_type,
    previous_parameter_study=previous_parameter_study)
parameter_generator.write()

# Comment used in tutorial code snippets: marker-3

# Parameterized targets must live inside current simulation_variables for loop
for set_name, parameters in parameter_generator.parameter_study_to_dict().items():
    set_name = pathlib.Path(set_name)
    simulation_variables = parameters

    # Comment used in tutorial code snippets: marker-4

    # Geometry, Partition
    workflow, datacheck = env.SConscript(
        geometry_configuration,
        variant_dir=set_name.name,
        exports=["env", "simulation_variables", "workflow", "datacheck"],
        duplicate=False
    )

    # Mesh, SolverPrep, Abaqus Solve, Extract Abaqus
    workflow, datacheck = env.SConscript(
        simulation_configuration,
        variant_dir=set_name.name,
        exports=["env", "simulation_variables", "workflow", "datacheck"],
        duplicate=False
    )

# Comment used in tutorial code snippets: marker-5

# Comment used in tutorial code snippets: marker-6

# Post-processing
job_name = "rectangle_compression"
plot_name = "stress_strain_comparison"
regression_file = python_source_abspath / "rectangle_compression_cartesian_product.csv"
post_processing_source = [f"{pathlib.Path(set_name) / job_name}_datasets.h5" for set_name in
                          parameter_generator.parameter_study.parameter_sets.values]
script_options = "--input-file ${SOURCES[3:].abspath}"
script_options += " --output-file ${TARGET.file} --x-units 'mm/mm' --y-units 'MPa'"
script_options += " --parameter-study-file ${SOURCES[1].abspath}"
script_options += " --csv-regression-file ${SOURCES[2].abspath}"
workflow.extend(env.PythonScript(
    target=[f"{plot_name}.pdf", f"{plot_name}.csv"],
    source=[f"{python_source_abspath}/post_processing.py", parameter_study_file.name, str(regression_file)] + post_processing_source,
    script_options=script_options))

# Data archival
archive_name = f"{env['archive_prefix']}-{workflow_name}"
archive_target = env.Tar(
    target=archive_name,
    source=workflow + workflow_configuration)

# Collector alias based on parent directory name
env.Alias(workflow_name, workflow)
env.Alias(f"{workflow_name}_datacheck", datacheck)
env.Alias(env['datacheck_alias'], datacheck)
env.Alias(f"{workflow_name}_archive", archive_target)

if not env['unconditional_build'] and not env['abaqus']:
    print(f"Program 'abaqus' was not found in construction environment. Ignoring '{workflow_name}' target(s)")
    Ignore(['.', workflow_name], workflow)
    Ignore(['.', workflow_name], datacheck)
