from ansys.dpf import core as dpf
from ansys.dpf.core import operators as ops
import numpy as np

# --- Inputs ---
# - path to results file
# - named selections names
# - data for postprocessing the bolts reactions (forces and moments)
path = r'C:/00 RD Projects/LearningProjects/PyAnsys/BoltedBracket_files/dp0/SYS/MECH/file.rst'
ns_name = 'M24_NODETOP'
#ns_name = 'M24_NODEBOT'

# --- Getting model information ---
# Import the model:
model = dpf.Model(path)
# Fetching metadata from the model:
model_metadata = model.metadata

# --- Manage data sources ---
# Creating data source from model
data_src = model.metadata.data_sources

# --- Select the nodes in named selection ---
ns_op = ops.scoping.on_named_selection()
ns_op.inputs.data_sources.connect(data_src)
ns_op.inputs.named_selection_name.connect(ns_name)
ns_op.inputs.requested_location.connect(dpf.locations.nodal)
ns_nodes = ns_op.outputs.mesh_scoping()

# Finding last load step and scoping time on all load steps.
last_ls = model_metadata.time_freq_support.n_sets
time_scope = dpf.time_freq_scoping_factory.scoping_on_all_time_freqs(model)


# --- Extracting nodal forces and nodal moments
# There is no nodal_force() nor nodal_moment() result in *.rst (mapdl) file.
# On the other hand there is element_nodal_forces() and force_summation() operators.
# These can be used to get nodal force/moments from elemental_nodal records.
# (see: https://github.com/ansys/pydpf-core/issues/2088)
# Nodal Force Summation (Forces and Moments)
force_op = ops.averaging.force_summation()
force_op.inputs.time_scoping.connect(time_scope)
force_op.inputs.data_sources.connect(data_src)
force_op.inputs.nodal_scoping(ns_nodes)
force_op.inputs.force_type.connect(1)

# --- Evaluating ---
# Forces
force_fc = force_op.outputs.forces_on_nodes()
force_array = np.empty((0, 3))
for ls in range(0, last_ls):
    force_field = force_fc[ls]
    force_array = np.vstack([force_array, force_field.data])
# Moments
moments_fc = force_op.outputs.moments_on_nodes()
moments_array = np.empty((0, 3))
for ls in range(0, last_ls):
    moments_field = moments_fc[ls]
    moments_array = np.vstack([moments_array, moments_field.data])

# Coordinates of Nodes where Force Summation was read:
result_nodes_ids = np.array(force_fc[0].scoping.ids)
nodes_array = np.empty((0, 1))
for node in result_nodes_ids:
    nodes_array = np.vstack([nodes_array, node])
nodes_coord = np.empty((0, 3))
for node in result_nodes_ids:
    ns_field = model.metadata.meshed_region.nodes[node]
    nodes_coord = np.vstack([nodes_coord, ns_field.coordinates])

# Load steps for sorting:
ls_array = np.empty((0, 1))
for ls in range(0, last_ls):
    for node in ns_nodes:
        ls_temp = ls+1
        ls_array = np.vstack([ls_array, ls_temp])

# Full stack of nodes numbers through all load steps
full_nodes_array = np.empty((0, 1))
xy_coord_array = np.empty((0, 3))
for ls in range(0, last_ls):
    full_nodes_array = np.vstack([full_nodes_array, nodes_array])
    xy_coord_array = np.vstack([xy_coord_array, nodes_coord])

# Stacked arrays for exporting to csv:
results_array = np.hstack([full_nodes_array, ls_array, xy_coord_array, force_array, moments_array])

print(f"\nNodes numbers: \n{nodes_array} "
      f"\nNodes coordinates: \n{nodes_coord} "
      f"\nForces on nodes: \n{force_array} "
      f"\nMoments on nodes: \n{moments_array} "
      f"\n=== Full Results Set === \n{results_array}")





"""
import inspect
methods_ops = inspect.getmembers(ops)
print([name for name, func in methods_ops])
ops_child_meth = inspect.getmembers(ops.averaging)
print([name for name, func in ops_child_meth])
"""

"""
# --- Alternative way to get node coordinates ---
# Attention, these are not linked to the forces/moments results!!! 
nodes_field = np.empty((0, 1))
for node in ns_nodes:
    nodes_field = np.vstack([nodes_field, node])
print(nodes_field)
ncoord_f = model.metadata.meshed_region.nodes.coordinates_field
ncoord_field = np.empty((0, 3))
for node in ns_nodes:
    ncoord_field = np.vstack([ncoord_field, ncoord_f.data[node]])
print(ncoord_field)
"""