#!/usr/bin/env python3

import argparse
import itertools
import os
import re

import ninja

def _parse_args():
    parser = argparse.ArgumentParser()
    parser.add_argument('input_file', help='input ninja file')
    parser.add_argument('--encoding', default='utf-8',
                        help='ninja file encoding')
    parser.add_argument('--ninja-deps', help='.ninja_deps file')

    return parser.parse_args()

def main():
    args = _parse_args()

    system_out_pattern = re.compile('out/target/product/[^/]+/system/')
    vendor_src_pattern = re.compile('(?:vendor)|(?:device)/')

    manifest = ninja.Parser().parse(
        args.input_file, args.encoding, args.ninja_deps)

    # Build lookup map
    outs = {}
    for build in manifest.builds:
        for path in build.explicit_outs:
            outs[path] = build
        for path in build.implicit_outs:
            outs[path] = build

    # Compute transitive input files
    outs_from_vendor_cache = {}

    def _are_inputs_from_vendor(build):
        # Check whether the input files are matched by vendor_src_pattern first.
        gen_paths = []
        paths = itertools.chain(
            build.explicit_ins, build.implicit_ins, build.depfile_implicit_ins)
        for path in paths:
            if vendor_src_pattern.match(path):
                return True
            if path.startswith('out/'):
                gen_paths.append(path)

        # Check whether the input files transitively depend on
        # vendor_src_pattern.
        for path in gen_paths:
            if is_from_vendor(path):
                return True

        return False

    def is_from_vendor(out_path):
        matched = outs_from_vendor_cache.get(out_path, None)
        if matched is not None:
            return matched

        build = outs.get(out_path)
        if build:
            matched = _are_inputs_from_vendor(build)
        else:
            matched = bool(vendor_src_pattern.match(path))
        outs_from_vendor_cache[out_path] = matched
        return matched

    bad_paths = [
        path for path in outs
        if is_from_vendor(path) and system_out_pattern.match(path)]

    bad_paths.sort()

    for path in bad_paths:
        print(path)

if __name__ == '__main__':
    main()


import re
from urllib.request import Request, urlopen
import pandas as pd
from bs4 import BeautifulSoup

def get_data(url,queryParams):
    pattern = re.compile(('<([ㄱ-ㅣ가-힣]+)>'))

    request_url = Request(url + queryParams)
    data_dic = {}
    request_url.get_method = lambda: 'GET'
    response_body = urlopen(request_url).read()
    soup = BeautifulSoup(response_body, 'lxml-xml')
    header_code = soup.find('resultCode').get_text()
    item_contents = soup.findAll('item')
    print(soup.find('header'))
    for content in item_contents:
        for i in range(len(content)):
            data = content.contents[i]
            tag = re.match(pattern,str(data)).group()
            replace_tag = re.sub(pattern,'\\1',tag)
            if replace_tag not in data_dic.keys():
                data_dic[replace_tag] = [data.get_text().strip()]
            else:
                data_dic[replace_tag] += [data.get_text().strip()]
    if len(data_dic) != 0 and header_code == '00':
        df = pd.DataFrame.from_dict(data_dic,orient='index')
    else:
        df = header_code
    return df


import argparse
import os
import sys
from os.path import dirname, abspath

from envs.common_envs_utils.env_makers import make_CarRacing_fixed_vector_features, \
    make_CarRacing_fixed_combined_features

sys.path.append(dirname(dirname(abspath(__file__))))

from agents.actor_critic_agents.Soft_A3C import Soft_A3C
from utilities.data_structures.Config import Config

import chainerrl
import tensorflow as tf
from envs.common_envs_utils.extended_env_wrappers import ExtendedMaxAndSkipEnv, FrameCompressor, OriginalStateKeeper, \
    ImageWithVectorCombiner, ChannelSwapper, TorchTensorCaster
from envs.gym_car_intersect_fixed import CarRacingHackatonContinuousFixed

def create_config(args):
    config = Config()
    config.seed = 1
    config.environment = None
    if args.mode == 'both':
        config.environment = make_CarRacing_fixed_combined_features(args.env_settings)()
    elif args.mode == 'vector':
        config.environment = make_CarRacing_fixed_vector_features(args.env_settings)()
    else:
        raise NotImplemented
    config.env_settings = args.env_settings

    config.num_episodes_to_run = 15000
    config.file_to_save_data_results = 'result_cars'
    config.file_to_save_results_graph = 'graph_cars'
    config.show_solution_score = True
    config.visualise_individual_results = False
    config.visualise_overall_agent_results = True
    config.standard_deviation_results = 1.0
    config.runs_per_agent = 1
    config.device = args.device
    config.overwrite_existing_results_file = False
    config.randomise_random_seed = True
    config.save_model = True
    config.max_episode_steps = 300
    config.random_replay_prefill_ration = args.start_buffer_random_ratio

    config.hyperparameters = {
        "Actor_Critic_Agents": {
            "Actor": {
                "learning_rate": 3e-4,
                "linear_hidden_units": [20, 20],
                "final_layer_activation": None,
                "batch_norm": False,
                "tau": 0.005,
                "gradient_clipping_norm": 5,
                "initialiser": "Xavier"
            },
            "Critic": {
                "learning_rate": 3e-4,
                "linear_hidden_units": [20, 20],
                "final_layer_activation": None,
                "batch_norm": False,
                "buffer_size": 100000,
                "tau": 0.005,
                "gradient_clipping_norm": 5,
                "initialiser": "Xavier"
            },

            "learning_rate": 3e-4,
            "gradient_clipping_norm": 5.0,
            "epsilon_decay_rate_denominator": 1.0,
            "normalise_rewards": False,
            "exploration_worker_difference": 2.0,

            "save_frequency_episode": 500,
            "min_steps_before_learning": 50000,
            "batch_size": 128,
            "discount_rate": 0.99,
            "mu": 0.0,  # for O-H noise
            "theta": 0.15,  # for O-H noise
            "sigma": 0.25,  # for O-H noise
            "action_noise_std": 0.2,  # for TD3
            "action_noise_clipping_range": 0.5,  # for TD3
            "update_every_n_steps": 20,
            "learning_updates_per_learning_session": 10,
            "automatically_tune_entropy_hyperparameter": True,
            "entropy_term_weight": None,
            "add_extra_noise": True,
            "do_evaluation_iterations": False,
            "clip_rewards": False,

            # "mode_to_use": "normal",
            # "rlkit_mode_parameters": {
            #     "explanation_steps_per_step": 1000,
            #     "update_steps_per_step": 1000,
            # }
        }
    }
    return config

def main(args):
    agent_title = args.name
    if not os.path.exists(os.path.join('logs', agent_title)):
        os.makedirs(os.path.join('logs', agent_title))
    tf_writer = tf.summary.create_file_writer(os.path.join('logs', agent_title))
    agent_config = create_config(args)
    agent_config.name = agent_title

    # random.randint(0, 2 ** 32 - 2)
    agent_config.seed = 42

    agent_config.hyperparameters = agent_config.hyperparameters['Actor_Critic_Agents']
    print("AGENT NAME: {}".format('SAC'))

    agent = Soft_A3C(agent_config, name=args.name)

    if args.load != 'none':
        agent.load(args.load)

    print(agent.hyperparameters)

    print("RANDOM SEED ", agent_config.seed)

    game_scores, rolling_scores, time_taken = agent.run_n_episodes(tf_saver=tf_writer, visualize=True)
    print("Time taken: {}".format(time_taken), flush=True)

if __name__ == "__main__":
    parser = argparse.ArgumentParser()
    parser.add_argument('--name', type=str, default='test', help='name for experiment')
    parser.add_argument('--mode', type=str, default='both', help='image only, vector only, or their combination')
    parser.add_argument('--env-settings', type=str, default='test', help='path to CarRacing env settings')
    parser.add_argument('--device', type=str, default='cpu', help='path to CarRacing env settings')
    parser.add_argument('--load', type=str, default='none', help='path to load model')
    parser.add_argument('--start-buffer-random-ratio', type=float, default=1.0,
                        help='ratio of random action for replay buffer pre-fill, useful for loaded agents'
                        )
    args = parser.parse_args()

    if args.mode not in ['image', 'vector', 'both']:
        raise ValueError("mode should be one of 'image', 'vector', 'both'")
    main(args)


from __future__ import print_function, absolute_import, division # makes KratosMultiphysics backward compatible with python 2.6 and 2.7

import MainDEM_for_coupling as DEM
import MainFEM_for_coupling as FEM
import FEMDEMParticleCreatorDestructor as PCD
import KratosMultiphysics
import KratosMultiphysics.FemToDemApplication as KratosFemDem
import KratosMultiphysics.MeshingApplication as MeshingApplication
import KratosMultiphysics.SolidMechanicsApplication as Solid
import math
import os
import mmg_process as MMG

def Wait():
    input("Press Something")

# Main script of the coupled FEM-DEM Application 2D
class FEMDEM_Solution:
#============================================================================================================================
    def __init__(self, Model):

        # Initialize solutions
        self.FEM_Solution = FEM.FEM_for_coupling_Solution(Model)
        self.DEM_Solution = DEM.DEM_for_coupling_Solution(Model)

        # Initialize Remeshing files
        self.DoRemeshing = self.FEM_Solution.ProjectParameters["AMR_data"]["activate_AMR"].GetBool()
        if self.DoRemeshing:
            self.mmg_parameter_file = open("MMGParameters.json",'r')
            self.mmg_parameters = KratosMultiphysics.Parameters(self.mmg_parameter_file.read())
            self.RemeshingProcessMMG = MMG.MmgProcess(Model, self.mmg_parameters)

        self.InitializePlotsFiles()

#============================================================================================================================
    def Run(self):

        self.Initialize()
        self.RunMainTemporalLoop()
        self.Finalize()

#============================================================================================================================
    def Initialize(self):
        self.number_of_nodes_element = 3
        self.FEM_Solution.Initialize()
        self.DEM_Solution.Initialize()

        # Initialize the "flag" IS_DEM in all the nodes
        KratosMultiphysics.VariableUtils().SetNonHistoricalVariable(KratosFemDem.IS_DEM, False, self.FEM_Solution.main_model_part.Nodes)
        # Initialize the "flag" NODAL_FORCE_APPLIED in all the nodes
        KratosMultiphysics.VariableUtils().SetNonHistoricalVariable(KratosFemDem.NODAL_FORCE_APPLIED, False, self.FEM_Solution.main_model_part.Nodes)
        # Initialize the "flag" RADIUS in all the nodes
        KratosMultiphysics.VariableUtils().SetNonHistoricalVariable(KratosMultiphysics.RADIUS, False, self.FEM_Solution.main_model_part.Nodes)

        # Initialize IP variables to zero
        self.InitializeIntegrationPointsVariables()

        self.SpheresModelPart = self.DEM_Solution.spheres_model_part
        self.DEMParameters = self.DEM_Solution.DEM_parameters
        self.DEMProperties = self.SpheresModelPart.GetProperties()[1]
        self.ParticleCreatorDestructor = PCD.FemDemParticleCreatorDestructor(self.SpheresModelPart,
                                                                           self.DEMProperties,
                                                                           self.DEMParameters)
        if self.DoRemeshing:
            self.InitializeMMGvariables()
            self.RemeshingProcessMMG.ExecuteInitialize()

        self.pressure_load = False #hard coded
        if self.pressure_load:
            KratosFemDem.AssignPressureIdProcess(self.FEM_Solution.main_model_part).Execute()

        # for the dem contact forces coupling
        self.InitializeDummyNodalForces()

        KratosMultiphysics.Logger.PrintInfo(" /$$$$$$$$ /$$$$$$$$ /$$      /$$  /$$$$$$  /$$$$$$$  /$$$$$$$$ /$$      /$$")
        KratosMultiphysics.Logger.PrintInfo("| $$_____/| $$_____/| $$$    /$$$ /$$__  $$| $$__  $$| $$_____/| $$$    /$$$")
        KratosMultiphysics.Logger.PrintInfo("| $$      | $$      | $$$$  /$$$$|__/  \ $$| $$  \ $$| $$      | $$$$  /$$$$")
        KratosMultiphysics.Logger.PrintInfo("| $$$$$   | $$$$$   | $$ $$/$$ $$  /$$$$$$/| $$  | $$| $$$$$   | $$ $$/$$ $$")
        KratosMultiphysics.Logger.PrintInfo("| $$__/   | $$__/   | $$  $$$| $$ /$$____/ | $$  | $$| $$__/   | $$  $$$| $$")
        KratosMultiphysics.Logger.PrintInfo("| $$      | $$      | $$\  $ | $$| $$      | $$  | $$| $$      | $$\  $ | $$")
        KratosMultiphysics.Logger.PrintInfo("| $$      | $$$$$$$$| $$ \/  | $$| $$$$$$$$| $$$$$$$/| $$$$$$$$| $$ \/  | $$")
        KratosMultiphysics.Logger.PrintInfo("|__/      |________/|__/     |__/|________/|_______/ |________/|__/     |__/ 2D Application")

#============================================================================================================================
    def RunMainTemporalLoop(self):

        # Solving the problem (time integration)
        self.DEM_Solution.step           = 0
        self.DEM_Solution.time           = 0.0
        self.DEM_Solution.time_old_print = 0.0

        if self.DoRemeshing:
            self.RemeshingProcessMMG.ExecuteBeforeSolutionLoop()

        while(self.FEM_Solution.time <= self.FEM_Solution.end_time):
            self.InitializeSolutionStep()
            self.SolveSolutionStep()
            self.FinalizeSolutionStep()

#============================================================================================================================
    def InitializeSolutionStep(self):

        # modified for the remeshing
        self.FEM_Solution.delta_time = self.FEM_Solution.main_model_part.ProcessInfo[KratosMultiphysics.DELTA_TIME]
        self.FEM_Solution.time = self.FEM_Solution.time + self.FEM_Solution.delta_time
        self.FEM_Solution.main_model_part.CloneTimeStep(self.FEM_Solution.time)
        self.FEM_Solution.step = self.FEM_Solution.step + 1
        self.FEM_Solution.main_model_part.ProcessInfo[KratosMultiphysics.STEP] = self.FEM_Solution.step

        neighbour_elemental_finder =  KratosMultiphysics.FindElementalNeighboursProcess(self.FEM_Solution.main_model_part, 2, 5)
        neighbour_elemental_finder.Execute()

        if self.DoRemeshing:
            is_remeshing = self.CheckIfHasRemeshed()

            if is_remeshing:
                # Extrapolate the VonMises normalized stress to nodes (remeshing)
                # KratosFemDem.StressToNodesProcess(self.FEM_Solution.main_model_part, 2).Execute()
                KratosFemDem.ComputeNormalizedFreeEnergyOnNodesProcess(self.FEM_Solution.main_model_part, 2).Execute()

                # we eliminate the nodal DEM forces
                self.RemoveDummyNodalForces()

            # Perform remeshing
            self.RemeshingProcessMMG.ExecuteInitializeSolutionStep()

            if is_remeshing:
                self.InitializeSolutionAfterRemeshing()
                neighbour_elemental_finder =  KratosMultiphysics.FindElementalNeighboursProcess(self.FEM_Solution.main_model_part, 2, 5)
                neighbour_elemental_finder.ClearNeighbours()
                neighbour_elemental_finder.Execute()

        self.FEM_Solution.InitializeSolutionStep()

        # Create initial skin of DEM's
        self.create_initial_dem_skin = False  # Hard Coded TODO
        if self.create_initial_dem_skin and self.FEM_Solution.step == 1:
            self.CreateInitialSkinDEM()

#============================================================================================================================
    def SolveSolutionStep(self): # Function to perform the coupling FEM <-> DEM

        self.FEM_Solution.clock_time = self.FEM_Solution.StartTimeMeasuring()

        #### SOLVE FEM #########################################
        self.FEM_Solution.solver.Solve()
        ########################################################

        if self.pressure_load:
            # we reconstruct the pressure load
            self.FEM_Solution.main_model_part.ProcessInfo[KratosFemDem.ITER] = 1
            while self.FEM_Solution.main_model_part.ProcessInfo[KratosFemDem.ITER] > 0:
                KratosFemDem.ExtendPressureConditionProcess2D(self.FEM_Solution.main_model_part,).Execute()

        # we create the new DEM of this time step
        self.GenerateDEM()
        self.SpheresModelPart = self.ParticleCreatorDestructor.GetSpheresModelPart()
        self.CheckForPossibleIndentations()

        # We update coordinates, displ and velocities of the DEM according to FEM
        self.UpdateDEMVariables()

        self.DEM_Solution.InitializeTimeStep()
        self.DEM_Solution.time = self.FEM_Solution.time
        self.DEM_Solution.step = self.FEM_Solution.step
        self.DEM_Solution.DEMFEMProcedures.UpdateTimeInModelParts(self.DEM_Solution.all_model_parts,
                                                                   self.DEM_Solution.time,
                                                                   self.DEM_Solution.solver.dt,
                                                                   self.DEM_Solution.step,
                                                                   self.DEM_Solution.IsTimeToPrintPostProcess())
        self.DEM_Solution._BeforeSolveOperations(self.DEM_Solution.time)

        #### SOLVE DEM #########################################
        self.DEM_Solution.solver.Solve()
        ########################################################

        self.DEM_Solution.AfterSolveOperations()
        self.DEM_Solution.solver._MoveAllMeshes(self.DEM_Solution.time, self.DEM_Solution.solver.dt)

        # to print DEM with the FEM coordinates
        self.UpdateDEMVariables()

        # DEM GiD print output
        self.PrintDEMResults()

        self.DEM_Solution.FinalizeTimeStep(self.DEM_Solution.time)

        # Transfer the contact forces of the DEM to the FEM nodes
        self.TransferNodalForcesToFEM()

        self.FEM_Solution.StopTimeMeasuring(self.FEM_Solution.clock_time,"Solving", False)

        # Update Coupled Postprocess file for Gid (post.lst)
        self.WritePostListFile()

        # Print required info
        self.PrintPlotsFiles()

#============================================================================================================================
    def FinalizeSolutionStep(self):

        # MODIFIED FOR THE REMESHING
        self.FEM_Solution.GraphicalOutputExecuteFinalizeSolutionStep()

        # processes to be executed at the end of the solution step
        self.FEM_Solution.model_processes.ExecuteFinalizeSolutionStep()

        # processes to be executed before witting the output
        self.FEM_Solution.model_processes.ExecuteBeforeOutputStep()

        # write output results GiD: (frequency writing is controlled internally)
        self.FEM_Solution.GraphicalOutputPrintOutput()

        # processes to be executed after writting the output
        self.FEM_Solution.model_processes.ExecuteAfterOutputStep()

        if self.DoRemeshing:
             self.RemeshingProcessMMG.ExecuteFinalizeSolutionStep()

        # Remove the submodel to be recomputed at each dt
        if self.FEM_Solution.main_model_part.HasSubModelPart("SkinDEMModelPart"):
            for cond in self.FEM_Solution.main_model_part.GetSubModelPart("SkinDEMModelPart").Conditions:
                cond.Set(KratosMultiphysics.TO_ERASE)

        self.FEM_Solution.main_model_part.RemoveConditionsFromAllLevels(KratosMultiphysics.TO_ERASE)
        self.FEM_Solution.main_model_part.RemoveSubModelPart("SkinDEMModelPart")

#============================================================================================================================
    def Finalize(self):

        self.FEM_Solution.Finalize()
        self.DEM_Solution.Finalize()
        self.DEM_Solution.CleanUpOperations()

        if self.DoRemeshing:
            self.RemeshingProcessMMG.ExecuteFinalize()

#============================================================================================================================
    def GenerateDEM(self): # This method creates the DEM elements and remove the damaged FEM, Additionally remove the isolated elements

        FEM_elements = self.FEM_Solution.main_model_part.Elements

        # Loop Over Elements to find the INACTIVE ones and generate the DEM only once
        for Element in FEM_elements:
            is_active     = True
            DEM_Generated = Element.GetValue(KratosFemDem.DEM_GENERATED)

            if Element.IsDefined(KratosMultiphysics.ACTIVE):
                is_active = Element.Is(KratosMultiphysics.ACTIVE)

                NumberOfDEM = 0         # Number of nodes with DEM Associated
                for node in range(0, self.number_of_nodes_element): # Loop over nodes of the FE
                    Node = Element.GetNodes()[node]
                    if Node.GetValue(KratosFemDem.IS_DEM) == True:
                        NumberOfDEM += 1

                if is_active == False and DEM_Generated == False: # Let's generate the remaining DEM of this FE
                    # print("elemento borrado: ", Element.Id)

                    # --------------------- 1ST SCENARIO -----------------------------
                    if NumberOfDEM == 0: # we must create 3 DEM

                        dist01  = self.CalculateDistanceBetweenNodes(Element.GetNodes()[0], Element.GetNodes()[1])
                        dist02  = self.CalculateDistanceBetweenNodes(Element.GetNodes()[0], Element.GetNodes()[2])
                        dist12  = self.CalculateDistanceBetweenNodes(Element.GetNodes()[1], Element.GetNodes()[2])

                        # look to the node 1 --------------
                        Radius1 = self.GetMinimumValue(dist01, dist02) * 0.5
                        Coordinates1 = self.GetNodeCoordinates(Element.GetNodes()[0])
                        Id1 = Element.GetNodes()[0].Id

                        self.ParticleCreatorDestructor.FEMDEM_CreateSphericParticle(Coordinates1, Radius1, Id1)
                        Element.GetNodes()[0].SetValue(KratosFemDem.IS_DEM, True)        # Has an asociated DEM now
                        Element.GetNodes()[0].SetValue(KratosMultiphysics.RADIUS, Radius1)

                        # look to the node 2 --------------
                        # Radius2 = self.GetMinimumValue(dist01-Radius1, dist12*0.5)
                        Radius2 = dist01-Radius1
                        Coordinates2 = self.GetNodeCoordinates(Element.GetNodes()[1])
                        Id2 = Element.GetNodes()[1].Id

                        self.ParticleCreatorDestructor.FEMDEM_CreateSphericParticle(Coordinates2, Radius2, Id2)
                        Element.GetNodes()[1].SetValue(KratosFemDem.IS_DEM, True)        # Has an asociated DEM now
                        Element.GetNodes()[1].SetValue(KratosMultiphysics.RADIUS, Radius2)

                        # look to the node 3 --------------
                        Radius3 = self.GetMinimumValue(dist02-Radius1, dist12-Radius2)
                        Coordinates3 = self.GetNodeCoordinates(Element.GetNodes()[2])
                        Id3 = Element.GetNodes()[2].Id

                        self.ParticleCreatorDestructor.FEMDEM_CreateSphericParticle(Coordinates3, Radius3, Id3)
                        Element.GetNodes()[2].SetValue(KratosFemDem.IS_DEM, True)        # Has an asociated DEM now
                        Element.GetNodes()[2].SetValue(KratosMultiphysics.RADIUS, Radius3)

                        # DEM generated for this Element
                        Element.SetValue(KratosFemDem.DEM_GENERATED, True)
                        Element.Set(KratosMultiphysics.TO_ERASE, True)

                    # --------------------- 2ND SCENARIO -----------------------------
                    elif NumberOfDEM == 2: # we must create 1 DEM

                        dist01  = self.CalculateDistanceBetweenNodes(Element.GetNodes()[0], Element.GetNodes()[1])
                        dist02  = self.CalculateDistanceBetweenNodes(Element.GetNodes()[0], Element.GetNodes()[2])
                        dist12  = self.CalculateDistanceBetweenNodes(Element.GetNodes()[1], Element.GetNodes()[2])

                        localId = 0 # Local Id of the node without DEM
                        for index in range(0,3):
                            if Element.GetNodes()[index].GetValue(KratosFemDem.IS_DEM) == False:
                                localId = index
                                break

                        Coordinates = self.GetNodeCoordinates(Element.GetNodes()[localId])
                        Id = Element.GetNodes()[localId].Id

                        if localId == 0:
                            R1 = Element.GetNodes()[1].GetValue(KratosMultiphysics.RADIUS)
                            R2 = Element.GetNodes()[2].GetValue(KratosMultiphysics.RADIUS)
                            R0 = self.GetMinimumValue(dist01-R1, dist02-R2)
                            self.ParticleCreatorDestructor.FEMDEM_CreateSphericParticle(Coordinates, R0, Id)
                            Element.GetNodes()[index].SetValue(KratosFemDem.IS_DEM, True)        # Has an asociated DEM now
                            Element.GetNodes()[index].SetValue(KratosMultiphysics.RADIUS, R0)

                        elif localId == 1:
                            R0 = Element.GetNodes()[0].GetValue(KratosMultiphysics.RADIUS)
                            R2 = Element.GetNodes()[2].GetValue(KratosMultiphysics.RADIUS)
                            R1 = self.GetMinimumValue(dist01-R0, dist12-R2)
                            self.ParticleCreatorDestructor.FEMDEM_CreateSphericParticle(Coordinates, R1, Id)
                            Element.GetNodes()[index].SetValue(KratosFemDem.IS_DEM, True)        # Has an asociated DEM now
                            Element.GetNodes()[index].SetValue(KratosMultiphysics.RADIUS, R1)

                        elif localId == 2:
                            R1 = Element.GetNodes()[1].GetValue(KratosMultiphysics.RADIUS)
                            R0 = Element.GetNodes()[0].GetValue(KratosMultiphysics.RADIUS)
                            R2 = self.GetMinimumValue(dist02-R0, dist12-R1)
                            self.ParticleCreatorDestructor.FEMDEM_CreateSphericParticle(Coordinates, R2, Id)
                            Element.GetNodes()[index].SetValue(KratosFemDem.IS_DEM, True)        # Has an asociated DEM now
                            Element.GetNodes()[index].SetValue(KratosMultiphysics.RADIUS, R2)

                        # DEM generated for this Element
                        Element.SetValue(KratosFemDem.DEM_GENERATED, True)
                        Element.Set(KratosMultiphysics.TO_ERASE, True)

                    # --------------------- 3RD SCENARIO -----------------------------
                    elif NumberOfDEM == 1: # we must create 2 DEM

                        dist01  = self.CalculateDistanceBetweenNodes(Element.GetNodes()[0], Element.GetNodes()[1])
                        dist02  = self.CalculateDistanceBetweenNodes(Element.GetNodes()[0], Element.GetNodes()[2])
                        dist12  = self.CalculateDistanceBetweenNodes(Element.GetNodes()[1], Element.GetNodes()[2])

                        localId = 0 # Local Id of the node with DEM
                        for index in range(0,3):
                            if Element.GetNodes()[index].GetValue(KratosFemDem.IS_DEM) == True:
                                localId = index
                                break

                        RadiusOfDem = Element.GetNodes()[localId].GetValue(KratosMultiphysics.RADIUS)

                        # --------------
                        if localId == 0:

                            # R1 = self.GetMinimumValue(dist01-RadiusOfDem, dist12*0.5)
                            R1 = dist01-RadiusOfDem
                            R2 = self.GetMinimumValue(dist02-RadiusOfDem, dist12-R1)

                            Coordinates1 = self.GetNodeCoordinates(Element.GetNodes()[1])
                            Id1 = Element.GetNodes()[1].Id
                            Coordinates2 = self.GetNodeCoordinates(Element.GetNodes()[2])
                            Id2 = Element.GetNodes()[2].Id

                            self.ParticleCreatorDestructor.FEMDEM_CreateSphericParticle(Coordinates1, R1, Id1)
                            Element.GetNodes()[1].SetValue(KratosFemDem.IS_DEM, True)        # Has an asociated DEM now
                            Element.GetNodes()[1].SetValue(KratosMultiphysics.RADIUS, R1)

                            self.ParticleCreatorDestructor.FEMDEM_CreateSphericParticle(Coordinates2, R2, Id2)
                            Element.GetNodes()[2].SetValue(KratosFemDem.IS_DEM, True)        # Has an asociated DEM now
                            Element.GetNodes()[2].SetValue(KratosMultiphysics.RADIUS, R2)

                        # --------------
                        elif localId == 1:

                            # R0 = self.GetMinimumValue(dist01-RadiusOfDem, dist02*0.5)
                            R0 = dist01-RadiusOfDem
                            R2 = self.GetMinimumValue(dist12-RadiusOfDem, dist02-R0)

                            Coordinates0 = self.GetNodeCoordinates(Element.GetNodes()[0])
                            Id0 = Element.GetNodes()[0].Id
                            Coordinates2 = self.GetNodeCoordinates(Element.GetNodes()[2])
                            Id2 = Element.GetNodes()[2].Id

                            self.ParticleCreatorDestructor.FEMDEM_CreateSphericParticle(Coordinates0, R0, Id0)
                            Element.GetNodes()[0].SetValue(KratosFemDem.IS_DEM, True)        # Has an asociated DEM now
                            Element.GetNodes()[0].SetValue(KratosMultiphysics.RADIUS, R0)

                            self.ParticleCreatorDestructor.FEMDEM_CreateSphericParticle(Coordinates2, R2, Id2)
                            Element.GetNodes()[2].SetValue(KratosFemDem.IS_DEM, True)        # Has an asociated DEM now
                            Element.GetNodes()[2].SetValue(KratosMultiphysics.RADIUS, R2)

                        # --------------
                        elif localId == 2:

                            # R0 = self.GetMinimumValue(dist02-RadiusOfDem, dist01*0.5)
                            R0 = dist02-RadiusOfDem
                            R1 = self.GetMinimumValue(dist12-RadiusOfDem, dist01-R0)

                            Coordinates0 = self.GetNodeCoordinates(Element.GetNodes()[0])
                            Id0 = Element.GetNodes()[0].Id
                            Coordinates1 = self.GetNodeCoordinates(Element.GetNodes()[1])
                            Id1 = Element.GetNodes()[1].Id

                            self.ParticleCreatorDestructor.FEMDEM_CreateSphericParticle(Coordinates0, R0, Id0)
                            Element.GetNodes()[0].SetValue(KratosFemDem.IS_DEM, True)        # Has an asociated DEM now
                            Element.GetNodes()[0].SetValue(KratosMultiphysics.RADIUS, R0)

                            self.ParticleCreatorDestructor.FEMDEM_CreateSphericParticle(Coordinates1, R1, Id1)
                            Element.GetNodes()[1].SetValue(KratosFemDem.IS_DEM, True)        # Has an asociated DEM now
                            Element.GetNodes()[1].SetValue(KratosMultiphysics.RADIUS, R1)

                        # DEM generated for this Element
                        Element.SetValue(KratosFemDem.DEM_GENERATED, True)
                        Element.Set(KratosMultiphysics.TO_ERASE, True)

                    # --------------------- 4TH SCENARIO -----------------------------
                    elif NumberOfDEM == 3: # We must avoid possible indentations

                        dist01  = self.CalculateDistanceBetweenNodes(Element.GetNodes()[0], Element.GetNodes()[1])
                        dist02  = self.CalculateDistanceBetweenNodes(Element.GetNodes()[0], Element.GetNodes()[2])
                        dist12  = self.CalculateDistanceBetweenNodes(Element.GetNodes()[1], Element.GetNodes()[2])

                        R0  = Element.GetNodes()[0].GetValue(KratosMultiphysics.RADIUS)
                        R1  = Element.GetNodes()[1].GetValue(KratosMultiphysics.RADIUS)
                        R2  = Element.GetNodes()[2].GetValue(KratosMultiphysics.RADIUS)
                        Id0 = Element.GetNodes()[0].Id
                        Id1 = Element.GetNodes()[1].Id
                        Id2 = Element.GetNodes()[2].Id

                        # Check the 3 edges of the element
                        if R0 + R1 > dist01:
                            # R0 = self.GetMinimumValue(R0, dist01*0.5)
                            R1 = dist01 - R0

                            # assign the new radius to the DEM nodes
                            self.DEM_Solution.spheres_model_part.GetNode(Id0).SetSolutionStepValue(KratosMultiphysics.RADIUS, R0)
                            self.DEM_Solution.spheres_model_part.GetNode(Id1).SetSolutionStepValue(KratosMultiphysics.RADIUS, R1)
                            Element.GetNodes()[0].SetValue(KratosMultiphysics.RADIUS, R0)
                            Element.GetNodes()[1].SetValue(KratosMultiphysics.RADIUS, R1)

                        if R0 + R2 > dist02:
                            # R0 = self.GetMinimumValue(R0, 0.5*dist02)
                            R2 = dist02 - R0

                            # assign the new radius to the DEM nodes
                            self.DEM_Solution.spheres_model_part.GetNode(Id0).SetSolutionStepValue(KratosMultiphysics.RADIUS, R0)
                            self.DEM_Solution.spheres_model_part.GetNode(Id2).SetSolutionStepValue(KratosMultiphysics.RADIUS, R2)
                            Element.GetNodes()[0].SetValue(KratosMultiphysics.RADIUS, R0)
                            Element.GetNodes()[2].SetValue(KratosMultiphysics.RADIUS, R2)

                        if R1 + R2 > dist12:
                            # R1 = self.GetMinimumValue(R1, 0.5*dist12)
                            R2 = dist12 - R1

                            # assign the new radius to the DEM nodes
                            self.DEM_Solution.spheres_model_part.GetNode(Id1).SetSolutionStepValue(KratosMultiphysics.RADIUS, R1)
                            self.DEM_Solution.spheres_model_part.GetNode(Id2).SetSolutionStepValue(KratosMultiphysics.RADIUS, R2)
                            Element.GetNodes()[2].SetValue(KratosMultiphysics.RADIUS, R2)
                            Element.GetNodes()[1].SetValue(KratosMultiphysics.RADIUS, R1)

                        # DEM generated for this Element
                        Element.SetValue(KratosFemDem.DEM_GENERATED, True)
                        Element.Set(KratosMultiphysics.TO_ERASE, True)

                    else:
                        raise Exception("Not possible")

                elif is_active == False and DEM_Generated == True:
                    Element.Set(KratosMultiphysics.TO_ERASE, True)

                # Remove the isolated Elements
                self.RemoveIsolatedFiniteElements()

        # We remove the inactive DEM associated to fem_nodes
        self.RemoveAloneDEMElements()
        element_eliminator = KratosMultiphysics.AuxiliarModelPartUtilities(self.FEM_Solution.main_model_part)
        element_eliminator.RemoveElementsAndBelongings(KratosMultiphysics.TO_ERASE)

#============================================================================================================================
    def CheckForPossibleIndentations(self): # Verifies if an element has indentations between its DEM

        FEM_elements = self.FEM_Solution.main_model_part.Elements

        for Element in FEM_elements:
            is_active     = True
            DEM_Generated = Element.GetValue(KratosFemDem.DEM_GENERATED)
            if Element.IsDefined(KratosMultiphysics.ACTIVE):
                is_active = Element.Is(KratosMultiphysics.ACTIVE)

            NumberOfDEM = 0         # Number of nodes with DEM Associated
            for node in range(0, 3): # Loop over nodes of the FE
                Node = Element.GetNodes()[node]

                if Node.GetValue(KratosFemDem.IS_DEM) == True:
                    NumberOfDEM += 1

            if NumberOfDEM == 3 and is_active == True and DEM_Generated == False:  # Case in which the DEM have been generated by its neighbours
                # Just avoid the initial indentations
                dist01  = self.CalculateDistanceBetweenNodes(Element.GetNodes()[0], Element.GetNodes()[1])
                dist02  = self.CalculateDistanceBetweenNodes(Element.GetNodes()[0], Element.GetNodes()[2])
                dist12  = self.CalculateDistanceBetweenNodes(Element.GetNodes()[1], Element.GetNodes()[2])
                R0  = Element.GetNodes()[0].GetValue(KratosMultiphysics.RADIUS)
                R1  = Element.GetNodes()[1].GetValue(KratosMultiphysics.RADIUS)
                R2  = Element.GetNodes()[2].GetValue(KratosMultiphysics.RADIUS)
                Id0 = Element.GetNodes()[0].Id
                Id1 = Element.GetNodes()[1].Id
                Id2 = Element.GetNodes()[2].Id

                # Check the 3 edges of the element
                if R0 + R1 > dist01:
                    R0 = self.GetMinimumValue(R0, dist01*0.5)
                    R1 = dist01 - R0
                    # assign the new radius to the DEM nodes
                    self.DEM_Solution.spheres_model_part.GetNode(Id0).SetSolutionStepValue(KratosMultiphysics.RADIUS, R0)
                    self.DEM_Solution.spheres_model_part.GetNode(Id1).SetSolutionStepValue(KratosMultiphysics.RADIUS, R1)
                    Element.GetNodes()[0].SetValue(KratosMultiphysics.RADIUS, R0)
                    Element.GetNodes()[1].SetValue(KratosMultiphysics.RADIUS, R1)

                if R0 + R2 > dist02:
                    R0 = self.GetMinimumValue(R0, 0.5*dist02)
                    R2 = dist02 - R0
                    # assign the new radius to the DEM nodes
                    self.DEM_Solution.spheres_model_part.GetNode(Id0).SetSolutionStepValue(KratosMultiphysics.RADIUS, R0)
                    self.DEM_Solution.spheres_model_part.GetNode(Id2).SetSolutionStepValue(KratosMultiphysics.RADIUS, R2)
                    Element.GetNodes()[0].SetValue(KratosMultiphysics.RADIUS, R0)
                    Element.GetNodes()[2].SetValue(KratosMultiphysics.RADIUS, R2)

                if R1 + R2 > dist12:
                    R1 = self.GetMinimumValue(R1, 0.5*dist12)
                    R2 = dist12 - R1
                    # assign the new radius to the DEM nodes
                    self.DEM_Solution.spheres_model_part.GetNode(Id1).SetSolutionStepValue(KratosMultiphysics.RADIUS, R1)
                    self.DEM_Solution.spheres_model_part.GetNode(Id2).SetSolutionStepValue(KratosMultiphysics.RADIUS, R2)
                    Element.GetNodes()[2].SetValue(KratosMultiphysics.RADIUS, R2)
                    Element.GetNodes()[1].SetValue(KratosMultiphysics.RADIUS, R1)

                # DEM generated for this Element
                Element.SetValue(KratosFemDem.DEM_GENERATED, True)

#============================================================================================================================
    def CalculateDistanceBetweenNodes(self, Node1, Node2):
        # only in 2D
        X1 = Node1.X
        X2 = Node2.X
        Y1 = Node1.Y
        Y2 = Node2.Y
        return math.sqrt((X1 - X2) * (X1 - X2) + (Y1 - Y2) * (Y1 - Y2))

    def GetMinimumValue(self, val1, val2):
        res = val1
        if val2 < val1:
            res = val2
        return res

    def GetNodeCoordinates(self, Node):
        X = Node.X
        Y = Node.Y
        Z = Node.Z
        coord = KratosMultiphysics.Array3()
        coord[0] = X
        coord[1] = Y
        coord[2] = Z
        return coord

#============================================================================================================================
    def UpdateDEMVariables(self):

        FEM_Nodes = self.FEM_Solution.main_model_part.Nodes
        for fem_node in FEM_Nodes:
            if fem_node.GetValue(KratosFemDem.IS_DEM):
                id_node = fem_node.Id
                associated_dem = self.SpheresModelPart.GetNode(id_node)

                Coordinates    = self.GetNodeCoordinates(fem_node)
                velocity = fem_node.GetSolutionStepValue(KratosMultiphysics.VELOCITY)
                displacement = fem_node.GetSolutionStepValue(KratosMultiphysics.DISPLACEMENT)

                # Update Coordinates
                associated_dem.X = Coordinates[0]
                associated_dem.Y = Coordinates[1]

                # Update Displacements
                associated_dem.SetSolutionStepValue(KratosMultiphysics.DISPLACEMENT_X, displacement[0])
                associated_dem.SetSolutionStepValue(KratosMultiphysics.DISPLACEMENT_Y, displacement[1])

                # Update Velocities
                associated_dem.SetSolutionStepValue(KratosMultiphysics.VELOCITY_X, velocity[0])
                associated_dem.SetSolutionStepValue(KratosMultiphysics.VELOCITY_Y, velocity[1])

#============================================================================================================================
    def CheckInactiveNodes(self):

        FEM_Elements = self.FEM_Solution.main_model_part.Elements
        FEM_Nodes    = self.FEM_Solution.main_model_part.Nodes
        erased_nodes_id = []
        conditions_to_erase_id = []

        for node in FEM_Nodes:
            node.SetValue(KratosFemDem.NUMBER_OF_ACTIVE_ELEMENTS, 0)

        for Element in FEM_Elements:
            is_active = True
            if Element.IsDefined(KratosMultiphysics.ACTIVE):
                is_active = Element.Is(KratosMultiphysics.ACTIVE)

            if is_active == True:
                for i in range(0,3): # Loop over nodes of the element
                    node = Element.GetNodes()[i]
                    NumberOfActiveElements = node.GetValue(KratosFemDem.NUMBER_OF_ACTIVE_ELEMENTS)
                    NumberOfActiveElements += 1
                    node.SetValue(KratosFemDem.NUMBER_OF_ACTIVE_ELEMENTS, NumberOfActiveElements)

        NumberOfActiveElements = 0

        for node in FEM_Nodes:
            NumberOfActiveElements = node.GetValue(KratosFemDem.NUMBER_OF_ACTIVE_ELEMENTS)
            if NumberOfActiveElements == 0 and node.GetValue(KratosFemDem.INACTIVE_NODE) == False:
                Id = node.Id
                node.SetValue(KratosFemDem.INACTIVE_NODE, True)
                node.Set(KratosMultiphysics.TO_ERASE, True) # added
                DEMnode = self.SpheresModelPart.GetNode(Id)
                DEMnode.SetValue(KratosFemDem.INACTIVE_NODE, True)
                DEMnode.Set(KratosMultiphysics.TO_ERASE, True)
                erased_nodes_id.append(Id)

                for condition in self.FEM_Solution.main_model_part.GetSubModelPart("ContactForcesDEMConditions").Conditions:
                    if condition.GetNodes()[0].Id == Id:
                        conditions_to_erase_id.append(condition.Id)

        # let's remove the nodal dem conditions according to inactive nodes
        for Id in conditions_to_erase_id:
            self.FEM_Solution.main_model_part.RemoveCondition(Id)

        # Remove inactive nodes
        self.SpheresModelPart.RemoveElementsFromAllLevels(KratosMultiphysics.TO_ERASE)
        self.FEM_Solution.main_model_part.GetRootModelPart().RemoveNodesFromAllLevels(KratosMultiphysics.TO_ERASE) # added

#============================================================================================================================
    def RemoveIsolatedFiniteElements(self):

        FEM_Elements = self.FEM_Solution.main_model_part.Elements
        FEM_Nodes    = self.FEM_Solution.main_model_part.Nodes

        for node in FEM_Nodes:
            node.SetValue(KratosFemDem.NUMBER_OF_ACTIVE_ELEMENTS, 0)

        for Element in FEM_Elements:
            is_active = True
            if Element.IsDefined(KratosMultiphysics.ACTIVE):
                is_active = Element.Is(KratosMultiphysics.ACTIVE)

            if is_active == True:
                for i in range(0,3): # Loop over nodes of the element
                    node = Element.GetNodes()[i]
                    number_active_elements = node.GetValue(KratosFemDem.NUMBER_OF_ACTIVE_ELEMENTS)
                    number_active_elements += 1
                    node.SetValue(KratosFemDem.NUMBER_OF_ACTIVE_ELEMENTS, number_active_elements)

        for Element in FEM_Elements:
            total_elements_on_nodes = 0
            for i in range(0,3): # Loop over nodes of the element
                node = Element.GetNodes()[i]
                number_active_elements = node.GetValue(KratosFemDem.NUMBER_OF_ACTIVE_ELEMENTS)
                total_elements_on_nodes = total_elements_on_nodes + number_active_elements
            if total_elements_on_nodes == 3:
                Element.Set(KratosMultiphysics.TO_ERASE, True)

#============================================================================================================================

    def TransferNodalForcesToFEM(self):

        for condition in self.FEM_Solution.main_model_part.GetSubModelPart("ContactForcesDEMConditions").Conditions:
            id_node = condition.GetNodes()[0].Id

            if self.FEM_Solution.main_model_part.GetNode(id_node).GetValue(KratosFemDem.IS_DEM):
                dem_forces = self.SpheresModelPart.GetNode(id_node).GetSolutionStepValue(KratosMultiphysics.TOTAL_FORCES)
                condition.SetValue(Solid.FORCE_LOAD, dem_forces)

#============================================================================================================================
    def WritePostListFile(self):

        post_file_name = self.FEM_Solution.problem_name + ".post.lst"
        time_label = round(self.FEM_Solution.step, 0)
        PostListFile = open(post_file_name, "w")
        PostListFile.write("Merge\n\n")
        PostListFile.write(self.FEM_Solution.problem_name + "_" + str(time_label) + ".post.res\n")
        PostListFile.write(self.FEM_Solution.problem_name + "_" + str(time_label) + ".post.msh\n")
        PostListFile.write(os.path.join(self.FEM_Solution.problem_name + "_Post_Files", self.FEM_Solution.problem_name + "_" + str(time_label) + ".post.bin"))
        PostListFile.close()

#============================================================================================================================
    def PrintPlotsFiles(self):

        # Print the general file
        time = self.FEM_Solution.time
        TotalReaction_x     = 0.0
        TotalDisplacement_x = 0.0
        TotalReaction_y     = 0.0
        TotalDisplacement_y = 0.0
        interval = self.FEM_Solution.ProjectParameters["interval_of_watching"].GetDouble()

        if self.FEM_Solution.time - self.TimePreviousPlotting >= interval:

            for index in range(0, self.FEM_Solution.ProjectParameters["list_of_nodes_displacement"].size()):
                IdNode = self.FEM_Solution.ProjectParameters["list_of_nodes_displacement"][index].GetInt()
                node = self.FEM_Solution.main_model_part.GetNode(IdNode)
                TotalDisplacement_x += node.GetSolutionStepValue(KratosMultiphysics.DISPLACEMENT_X)
                TotalDisplacement_y += node.GetSolutionStepValue(KratosMultiphysics.DISPLACEMENT_Y)

            for index in range(0, self.FEM_Solution.ProjectParameters["list_of_nodes_reaction"].size()):
                IdNode = self.FEM_Solution.ProjectParameters["list_of_nodes_reaction"][index].GetInt()
                node = self.FEM_Solution.main_model_part.GetNode(IdNode)
                TotalReaction_x += node.GetSolutionStepValue(KratosMultiphysics.REACTION_X)
                TotalReaction_y += node.GetSolutionStepValue(KratosMultiphysics.REACTION_Y)

            self.PlotFile = open("PlotFile.txt","a")
            self.PlotFile.write("    " + "{0:.4e}".format(time).rjust(11) + "    " + "{0:.4e}".format(TotalDisplacement_x).rjust(11) +
                                "    " + "{0:.4e}".format(TotalDisplacement_y).rjust(11) + "    " + "{0:.4e}".format(TotalReaction_x).rjust(11) +
                                "    " + "{0:.4e}".format(TotalReaction_y).rjust(11) + "\n")
            self.PlotFile.close()

            # Print the selected nodes files
            if self.FEM_Solution.ProjectParameters["watch_nodes_list"].size() != 0:
                NumNodes = self.FEM_Solution.ProjectParameters["watch_nodes_list"].size()
                for inode in range(0, NumNodes):
                    IdNode = self.PlotFilesNodesIdList[inode]
                    node = self.FEM_Solution.main_model_part.GetNode(IdNode)
                    self.PlotFilesNodesList[inode] = open("PlotNode_" + str(IdNode) + ".txt","a")

                    displacement = node.GetSolutionStepValue(KratosMultiphysics.DISPLACEMENT)
                    velocity = node.GetSolutionStepValue(KratosMultiphysics.VELOCITY)
                    reaction = node.GetSolutionStepValue(KratosMultiphysics.REACTION)
                    acceleration = node.GetSolutionStepValue(KratosMultiphysics.ACCELERATION)

                    dx = displacement[0]
                    dy = displacement[1]
                    Rx = reaction[0]
                    Ry = reaction[1]
                    vx = velocity[0]
                    vy = velocity[1]
                    ax = acceleration[0]
                    ay = acceleration[1]

                    self.PlotFilesNodesList[inode].write("    " + "{0:.4e}".format(time).rjust(11) + "    " +
                        "{0:.4e}".format(dx).rjust(11) + "    " + "{0:.4e}".format(dy).rjust(11) + "    " +
                        "{0:.4e}".format(vx).rjust(11) + "    " + "{0:.4e}".format(vy).rjust(11) + "    " +
                        "{0:.4e}".format(ax).rjust(11) + "    " + "{0:.4e}".format(ay).rjust(11) + "    " +
                        "{0:.4e}".format(Rx).rjust(11) + "    " + "{0:.4e}".format(Ry).rjust(11) + "\n")

                    self.PlotFilesNodesList[inode].close()

            # print the selected element files
            if self.FEM_Solution.ProjectParameters["watch_elements_list"].size() != 0:
                NumElem = self.FEM_Solution.ProjectParameters["watch_elements_list"].size()
                for iElem in range(0, NumElem):
                    Idelem = self.PlotFilesElementsIdList[iElem]
                    Elem = self.FEM_Solution.main_model_part.GetElement(Idelem)
                    self.PlotFilesElementsList[iElem] = open("PlotElement_" + str(Idelem) + ".txt","a")

                    stress_tensor = Elem.GetValuesOnIntegrationPoints(KratosFemDem.STRESS_VECTOR_INTEGRATED, self.FEM_Solution.main_model_part.ProcessInfo)
                    strain_vector = Elem.GetValue(KratosFemDem.STRAIN_VECTOR)

                    Sxx = stress_tensor[0][0]
                    Syy = stress_tensor[0][1]
                    Sxy = stress_tensor[0][2]

                    Exx = strain_vector[0]
                    Eyy = strain_vector[1]
                    Exy = strain_vector[2]

                    damage = Elem.GetValue(KratosFemDem.DAMAGE_ELEMENT)

                    self.PlotFilesElementsList[iElem].write("    " + "{0:.4e}".format(time).rjust(11) + "    " +
                        "{0:.4e}".format(Sxx).rjust(11) + "    " + "{0:.4e}".format(Syy).rjust(11) + "    " +
                        "{0:.4e}".format(Sxy).rjust(11) + "    " + "{0:.4e}".format(Exx).rjust(11) +
                        "    " + "{0:.4e}".format(Eyy).rjust(11) + "    " + "{0:.4e}".format(Exy).rjust(11) +
                        "   " + "{0:.4e}".format(damage).rjust(11) + "\n")

                    self.PlotFilesElementsList[iElem].close()
            self.TimePreviousPlotting = time

#============================================================================================================================
    def InitializePlotsFiles(self):

        # open general Displ/Reaction File
        self.PlotFile = open("PlotFile.txt","w")
        self.PlotFile.write("This File Plots the SUM of the displacement and reactions of the nodes selected in the lists!\n\n")
        self.PlotFile.write("       time           displ_x        displ_y      Reaction_x     Reaction_y    \n")
        self.PlotFile.close()
        self.TimePreviousPlotting = 0.0
        self.PlotFilesNodesList    = []
        self.PlotFilesElementsList = []
        self.PlotFilesNodesIdList    = []
        self.PlotFilesElementsIdList = []

        # open plots for nodes selected
        if self.FEM_Solution.ProjectParameters["watch_nodes_list"].size() != 0:
            NumNodes = self.FEM_Solution.ProjectParameters["watch_nodes_list"].size()
            for node in range(0, NumNodes):

                Id = self.FEM_Solution.ProjectParameters["watch_nodes_list"][node].GetInt()
                iPlotFileNode = open("PlotNode_" + str(Id) + ".txt","w")
                iPlotFileNode.write("\n")
                iPlotFileNode.write("       time          displ_x        displ_y         vel_x           vel_y         acc_x          acc_y        Reaction_x     Reaction_y    \n")
                iPlotFileNode.close()
                self.PlotFilesNodesList.append(iPlotFileNode)
                self.PlotFilesNodesIdList.append(Id)

        # open plots for elements selected
        if self.FEM_Solution.ProjectParameters["watch_elements_list"].size() != 0:

            NumNElements = self.FEM_Solution.ProjectParameters["watch_elements_list"].size()
            for elem in range(0, NumNElements):
                Id = self.FEM_Solution.ProjectParameters["watch_elements_list"][elem].GetInt()
                iPlotFileElem = open("PlotElement_" + str(Id) + ".txt","w")
                iPlotFileElem.write("\n")
                iPlotFileElem.write("          time                       Sxx                   Syy                      Sxy                    Exx                     Eyy                   Exy                Damage  \n")
                iPlotFileElem.close()
                self.PlotFilesElementsList.append(iPlotFileElem)
                self.PlotFilesElementsIdList.append(Id)

#============================================================================================================================
    def InitializeMMGvariables(self):

        ZeroVector3 = KratosMultiphysics.Vector(3)
        ZeroVector3[0] = 0.0
        ZeroVector3[1] = 0.0
        ZeroVector3[2] = 0.0

        for node in self.FEM_Solution.main_model_part.Nodes:
            node.SetValue(MeshingApplication.AUXILIAR_GRADIENT, ZeroVector3)

#============================================================================================================================
    def GenerateDemAfterRemeshing(self):
        # we extrapolate the damage to the nodes
        KratosFemDem.DamageToNodesProcess(self.FEM_Solution.main_model_part, 2).Execute()

        # we create a submodelpart containing the nodes and radius of the corresponding DEM
        KratosFemDem.DemAfterRemeshIdentificatorProcess(self.FEM_Solution.main_model_part, 0.95).Execute()

        # Loop over the elements of the Submodelpart to create the DEM
        for node in self.FEM_Solution.main_model_part.GetSubModelPart("DemAfterRemeshingNodes").Nodes:
            Id = node.Id
            R = node.GetValue(KratosFemDem.DEM_RADIUS)
            Coordinates = self.GetNodeCoordinates(node)
            self.ParticleCreatorDestructor.FEMDEM_CreateSphericParticle(Coordinates, R, Id)
            node.SetValue(KratosFemDem.IS_DEM, True)

#============================================================================================================================
    def CheckIfHasRemeshed(self):

        is_remeshed = False

        if (self.RemeshingProcessMMG.initial_remeshing == False):
            step = self.RemeshingProcessMMG.step + 1
            # We need to check if the model part has been modified recently
            if self.RemeshingProcessMMG.step_frequency > 0:
                if step >= self.RemeshingProcessMMG.step_frequency:
                        if self.RemeshingProcessMMG.model_part.ProcessInfo[KratosMultiphysics.STEP] >= self.RemeshingProcessMMG.initial_step:
                            # Has remeshed
                            is_remeshed = True
        return is_remeshed

#============================================================================================================================
    def PrintDEMResults(self):

        if self.DEM_Solution.step == 1: # always print the 1st step
            self.DEM_Solution.PrintResultsForGid(self.DEM_Solution.time)
            self.DEM_Solution.time_old_print = self.DEM_Solution.time

        else:
            time_to_print = self.DEM_Solution.time - self.DEM_Solution.time_old_print

            if (self.DEM_Solution.DEM_parameters["OutputTimeStep"].GetDouble() - time_to_print < 1e-2 * self.DEM_Solution.solver.dt):
                self.DEM_Solution.PrintResultsForGid(self.DEM_Solution.time)
                self.DEM_Solution.time_old_print = self.DEM_Solution.time

#============================================================================================================================
    def CreateInitialSkinDEM(self):

        initial_dem_skin_process = KratosFemDem.InitialDemSkinProcess(self.FEM_Solution.main_model_part)
        initial_dem_skin_process.Execute()

        # Loop over the elements of the Submodelpart to create the DEM
        for node in self.FEM_Solution.main_model_part.GetSubModelPart("InitialDemSkin").Nodes:

            Id = node.Id
            R = node.GetValue(KratosFemDem.DEM_RADIUS)
            Coordinates = self.GetNodeCoordinates(node)
            self.ParticleCreatorDestructor.FEMDEM_CreateSphericParticle(Coordinates, R, Id)
            node.SetValue(KratosFemDem.IS_DEM, True)

#============================================================================================================================

    def InitializeIntegrationPointsVariables(self):

        for elem in self.FEM_Solution.main_model_part.Elements:
            elem.SetValue(KratosFemDem.STRESS_THRESHOLD, 0.0)
            elem.SetValue(KratosFemDem.DAMAGE_ELEMENT, 0.0)
            elem.SetValue(KratosFemDem.STRESS_VECTOR, [0.0,0.0,0.0])
            elem.SetValue(KratosFemDem.STRAIN_VECTOR, [0.0,0.0,0.0])

#============================================================================================================================

    def GetMaximumConditionId(self):
        max_id = 0
        for condition in self.FEM_Solution.main_model_part.Conditions:
            if condition.Id > max_id:
                max_id = condition.Id
        return max_id

#============================================================================================================================

    def InitializeDummyNodalForces(self):
        # we fill the submodel part with the nodes and dummy conditions
        max_id = self.GetMaximumConditionId()
        props = self.FEM_Solution.main_model_part.Properties[0]
        self.FEM_Solution.main_model_part.CreateSubModelPart("ContactForcesDEMConditions")
        for node in self.FEM_Solution.main_model_part.Nodes:
            self.FEM_Solution.main_model_part.GetSubModelPart("ContactForcesDEMConditions").AddNode(node, 0)
            max_id += 1
            cond = self.FEM_Solution.main_model_part.GetSubModelPart("ContactForcesDEMConditions").CreateNewCondition(
                                                                            "PointLoadCondition2D1N",
                                                                            max_id,
                                                                            [node.Id],
                                                                            props)
            self.FEM_Solution.main_model_part.GetSubModelPart("computing_domain").AddCondition(cond)
            self.FEM_Solution.main_model_part.GetCondition(max_id).SetValue(Solid.FORCE_LOAD, [0.0,0.0,0.0])

#============================================================================================================================
    def RemoveDummyNodalForces(self):

        for condition in self.FEM_Solution.main_model_part.GetSubModelPart("ContactForcesDEMConditions").Conditions:
            condition.Set(KratosMultiphysics.TO_ERASE, True)

        self.FEM_Solution.main_model_part.GetSubModelPart("ContactForcesDEMConditions").RemoveConditionsFromAllLevels(KratosMultiphysics.TO_ERASE)
        self.FEM_Solution.main_model_part.RemoveSubModelPart("ContactForcesDEMConditions")

#============================================================================================================================
    def RemoveAloneDEMElements(self):
        # method to remove the dem corresponding to inactive nodes
        FEM_Nodes = self.FEM_Solution.main_model_part.Nodes
        FEM_Elements = self.FEM_Solution.main_model_part.Elements

        for node in FEM_Nodes:
            node.SetValue(KratosFemDem.NUMBER_OF_ACTIVE_ELEMENTS, 0)

        for Element in FEM_Elements:
            for i in range(0, self.number_of_nodes_element): # Loop over nodes of the element
                if Element.IsNot(KratosMultiphysics.TO_ERASE):
                    node = Element.GetNodes()[i]
                    NumberOfActiveElements = node.GetValue(KratosFemDem.NUMBER_OF_ACTIVE_ELEMENTS)
                    NumberOfActiveElements += 1
                    node.SetValue(KratosFemDem.NUMBER_OF_ACTIVE_ELEMENTS, NumberOfActiveElements)

        NumberOfActiveElements = 0
        for node in FEM_Nodes:
            NumberOfActiveElements = node.GetValue(KratosFemDem.NUMBER_OF_ACTIVE_ELEMENTS)
            if NumberOfActiveElements == 0:
                self.SpheresModelPart.GetNode(node.Id).Set(KratosMultiphysics.TO_ERASE, True)

        self.SpheresModelPart.RemoveElementsFromAllLevels(KratosMultiphysics.TO_ERASE)

#============================================================================================================================

    def InitializeSolutionAfterRemeshing(self):
        # Initialize the "flag" IS_DEM in all the nodes
        KratosMultiphysics.VariableUtils().SetNonHistoricalVariable(KratosFemDem.IS_DEM, False, self.FEM_Solution.main_model_part.Nodes)
        # Initialize the "flag" NODAL_FORCE_APPLIED in all the nodes
        KratosMultiphysics.VariableUtils().SetNonHistoricalVariable(KratosFemDem.NODAL_FORCE_APPLIED, False, self.FEM_Solution.main_model_part.Nodes)
        # Initialize the "flag" RADIUS in all the nodes
        KratosMultiphysics.VariableUtils().SetNonHistoricalVariable(KratosMultiphysics.RADIUS, False, self.FEM_Solution.main_model_part.Nodes)

        self.pressure_load = False #hard coded
        if self.pressure_load:
            KratosFemDem.AssignPressureIdProcess(self.FEM_Solution.main_model_part).Execute()

        # Remove DEMS from previous mesh
        self.SpheresModelPart.Elements.clear()
        self.SpheresModelPart.Nodes.clear()

        self.InitializeDummyNodalForces()

        self.InitializeMMGvariables()
        self.FEM_Solution.model_processes = self.FEM_Solution.AddProcesses()
        self.FEM_Solution.model_processes.ExecuteInitialize()
        self.FEM_Solution.model_processes.ExecuteBeforeSolutionLoop()
        self.FEM_Solution.model_processes.ExecuteInitializeSolutionStep()

        # Search the skin nodes for the remeshing
        skin_detection_process_param = KratosMultiphysics.Parameters("""
        {
            "name_auxiliar_model_part" : "SkinDEMModelPart",
            "name_auxiliar_condition"  : "Condition",
            "echo_level"               : 0
        }""")
        skin_detection_process = KratosMultiphysics.SkinDetectionProcess2D(self.FEM_Solution.main_model_part,
                                                                            skin_detection_process_param)
        skin_detection_process.Execute()
        self.GenerateDemAfterRemeshing()


fname = input('Enter the file name: ')
fhand = open(fname)
sum = 0
count=0
for line in fhand:
    line = line.rstrip()
    if line.startswith('X-DSPAM-Confidence:'):
        rline = line
        count = count + 1
        fval = float(rline[20:])
        #print(rline[20:])
        sum = sum + fval

print('Average Confidence:',sum/count)


import project_functions
import numpy as np
import skimage
from skimage.morphology import disk
from PIL import Image
import numba as nb

import sys
sys.path.append('C:/Users/liuzhenye/Desktop/Project3/VSPV/model/python_layers/')
import forward_backward_map_layer
@nb.jit
def forward2backwardMap(forward_flow):
    backward_map = np.zeros((200,200))
    for x in range(0,200):
        for y in range(0,200):
            if((forward_flow[0,x,y]!=0)|(forward_flow[1,x,y]!=0)):
                uu = x+forward_flow[1,x,y]
                vv = y+forward_flow[0,x,y]
                uu = int(uu+0.5)
                vv = int(vv+0.5)

                if uu<0 or vv<0 or uu>=200 or vv>=200:
                    continue

                backward_map[uu,vv] = 1

    return backward_map

def forward_flow(path,number):
    for i in range(25,number):
        depth_map=np.fromfile(open(path+'depth/{}_9_d.bin'.format(i)), dtype = np.double)
        print(depth_map.shape)
        depth_map.resize(200,200)
        (K,Rt,C)=project_functions.getKRtC(9)
        new_xyz_image=project_functions.DepthMap2XyzImage(depth_map,K,Rt)
        for j in range(19):
            (K,Rt,C)=project_functions.getKRtC(j)
            forward_flow=project_functions.xyzImage2ForwardFlow(new_xyz_image, K, Rt)
            np.save(path+'forward_flow/{}_{}_u.bin'.format(i,j),forward_flow[0,:,:])
            np.save(path+'forward_flow/{}_{}_v.bin'.format(i,j),forward_flow[1,:,:])
        print(i)
@nb.jit
def forward_mask(path,number):
    for i in range(25,number):
        for j in range(19):
            forward_flow=np.zeros([2,200,200])
            forward_flow[0,:,:]=np.load(path+'forward_flow/{}_{}_u.bin.npy'.format(i,j))
            forward_flow[1,:,:]=np.load(path+'forward_flow/{}_{}_v.bin.npy'.format(i,j))
            flow_mask = forward2backwardMap(forward_flow)
            flow_mask = skimage.morphology.closing(flow_mask,disk(2)) * 255
            flow_mask = flow_mask
            np.save(path+'forward_mask/{}_{}'.format(i,j),flow_mask)
        print (i)

def reampped_forward_flow(path,number):
    for i in range(number):
        for j in range(19):
            bottom=np.zeros([2,200,200])
            bottom[0,:,:]=np.load(path+'forward_flow/{}_{}_u.bin.npy'.format(i,j))
            bottom[0,:,:]=np.load(path+'forward_flow/{}_{}_v.bin.npy'.format(i,j))
            top=np.zeros([2,200,200])
            f=forward_backward_map_layer.forward_backward_map_layer()
            np.save(path+'reampped_forward_flow/{}_{}_u.bin'.format(i,j),forward_flow[0,:,:])
            np.save(path+'remapped_forward_flow/{}_{}_v.bin'.format(i,j),forward_flow[1,:,:])
        print(i)
#forward_flow('H:/data/PVHM_8000-8999/',1000)
#forward_flow('H:/data/PVHM_0-999/',1000)
#forward_mask('H:/data/PVHM_0-999/',1000)
#flow_mask = np.loadtxt('H:/data/PVHM_0-999/forward_mask/{}_{}.png'.format(0,0))
#print(flow_mask)
reampped_forward_flow('H:/data/PVHM_0-999/',1000)


import jsonlines

TABLES = "data/dev.tables.jsonl"
QUERIES = "data/dev.jsonl"
PREDICTIONS = "test/my.pred.dev.jsonl"

tables = {}

# Read tables and data
with jsonlines.open(TABLES) as input_tables:
    for table in input_tables:
        tables[table["id"]] = table

# Open queries and output file
with jsonlines.open(QUERIES) as input_queries, jsonlines.open(PREDICTIONS, mode='w') as predictions_file:
    for query in input_queries:
        question = query["question"].lower()
        table = tables[query["table_id"]]

        # Determine selection
        sel = -1
        for i, field in enumerate(table["header"]):
            if field.lower() in question:
                sel = i

        # Determine conditions
        conds = []
        for row in table["rows"]:
            for i, cell in enumerate(row):
                if isinstance(cell, str):
                    if cell.lower() in question:
                        conds.append([i, 0, cell])

        prediction = {"query": {"sel": sel, "conds": conds, "agg": 0}, "error": ""}
        predictions_file.write(prediction)


from django.contrib.staticfiles.finders import find
from django.http import Http404
from markdown import markdown
from seminar import settings
import os.path

def load_markdown(markdown_filename, directory_name="mdown"):
    path = os.path.join(settings.STATIC_ROOT, directory_name, markdown_filename)

    try:
        mdfile = open(path, 'r+')
    except IOError:
        # We must be in development! Search for the static file using staticfiles finder
        match = find(directory_name + markdown_filename)
        if (match != None):
            mdfile = open(str(match), 'r+')
        else:
            raise Http404

    text = mdfile.read()
    html = markdown(text)
    mdfile.close()

    return html

def truncate(string, num_characters=50, continuation_string="..."):
    return string[:num_characters] + (string[num_characters:] and continuation_string)


from django.urls import path
from django.conf.urls import url
from . import views

urlpatterns = [
    path('', views.home, name="member"),
    path('signup/', views.signup, name="signup"),
    path('login/', views.login, name="login"),
    path('logout/', views.logout, name="logout"),
    path('findid/', views.findid, name="findid"),
    path('findpw/', views.findpw, name="findpw"),
]


import os
import numpy as np
import argparse
import torch
from pprint import pprint
from data.pretraining import DataReaderPlainImg, custom_collate
from data.transforms import get_transforms_pretraining
from utils import check_dir, accuracy, get_logger
from models.pretraining_backbone import ResNet18Backbone
import matplotlib.pyplot as plt
import pandas as pd

global_step = 0

def parse_arguments():
    parser = argparse.ArgumentParser()
    parser.add_argument('data_folder', type=str, help="folder containing the data (crops)")
    parser.add_argument('--weights-init', type=str,
                        default="random")
    parser.add_argument('--output-root', type=str, default='results')
    parser.add_argument('--lr', type=float, default=0.005, help='learning rate')
    parser.add_argument('--bs', type=int, default=8, help='batch_size')
    parser.add_argument("--size", type=int, default=256, help="size of the images to feed the network")
    parser.add_argument('--snapshot-freq', type=int, default=1, help='how often to save models')
    parser.add_argument('--exp-suffix', type=str, default="", help="string to identify the experiment")
    args = parser.parse_args()

    hparam_keys = ["lr", "bs", "size"]
    args.exp_name = "_".join(["{}{}".format(k, getattr(args, k)) for k in hparam_keys])

    args.exp_name += "_{}".format(args.exp_suffix)

    args.output_folder = check_dir(os.path.join(args.output_root, 'pretrain', args.exp_name))
    args.model_folder = check_dir(os.path.join(args.output_folder, "models"))
    args.logs_folder = check_dir(os.path.join(args.output_folder, "logs"))
    args.plots_folder = check_dir(os.path.join(args.output_folder, "plots"))

    return args

def main(args):
    # Logging to the file and stdout
    logger = get_logger(args.output_folder, args.exp_name)

    # Device configuration
    device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
    print('#### This is the device used: ', device, '####')
    # build model and load weights
    model = ResNet18Backbone(pretrained=False).to(device)

    # checkpoint = torch.load("pretrain_weights_init.pth")
    # model.load_state_dict(checkpoint['model'])

    model.load_state_dict(torch.load(args.weights_init, map_location = device)['model'] , strict=False)
    #raise NotImplementedError("TODO: load weight initialization")

    # load dataset
    data_root = args.data_folder
    train_transform, val_transform = get_transforms_pretraining(args)
    train_data = DataReaderPlainImg(os.path.join(data_root, str(args.size), "train"), transform=train_transform)
    # print(' hereeeeeeeeeeeeeeeeeeee', type(train_data.__getitem__(5)[0][0]))
    # plt.imshow(train_data.__getitem__(5)[0][0].numpy().transpose(2,1,0), interpolation='nearest')
    # plt.show()
    # plt.imshow(train_data.__getitem__(100)[0][0].numpy()[2])
    # plt.show()
    # plt.imshow(train_data.__getitem__(100)[0][1].numpy()[2])
    # plt.show()
    # plt.imshow(train_data.__getitem__(100)[0][2].numpy()[2])
    # plt.show()
    # plt.imshow(train_data.__getitem__(100)[0][3].numpy()[2])
    # plt.show()
    val_data = DataReaderPlainImg(os.path.join(data_root, str(args.size), "val"), transform=val_transform)
    train_loader = torch.utils.data.DataLoader(train_data, batch_size=args.bs, shuffle=True, num_workers=2,
                                               pin_memory=True, drop_last=True, collate_fn=custom_collate)

    print(train_loader)
    val_loader = torch.utils.data.DataLoader(val_data, batch_size=1, shuffle=False, num_workers=2,
                                             pin_memory=True, drop_last=True, collate_fn=custom_collate)

    # TODO: loss function
    criterion = torch.nn.CrossEntropyLoss() # This criterion combines nn.LogSoftmax() and nn.NLLLoss() in one single class.
    ###########raise NotImplementedError("TODO: loss function")
    optimizer = torch.optim.SGD(model.parameters(), lr=args.lr, momentum=0.9, weight_decay=1e-4)

    expdata = "  \n".join(["{} = {}".format(k, v) for k, v in vars(args).items()])
    logger.info(expdata)
    logger.info('train_data {}'.format(train_data.__len__()))
    logger.info('val_data {}'.format(val_data.__len__()))

    best_val_loss = np.inf
    best_val_acc = np.inf
    # Train-validate for one epoch. You don't have to run it for 100 epochs, preferably until it starts overfitting.
    train_loss_list = []
    train_acc_list = []
    val_loss_list = []
    val_acc_list = []
    for epoch in range(40):
        print("Epoch {}".format(epoch))
        train_loss, train_acc = train(train_loader, model, criterion, optimizer, device)
        val_loss, val_acc = validate(val_loader, model, criterion, device)
        #print('Epoch: ', epoch, ' val_acc ', val_acc, ' val_loss ', val_loss, ' train_acc: ',train_acc, ' train_loss: ', train_loss )

        logger.info("Epoch %d  train_loss %.3f train_acc %.3f val_loss: %.3f val_acc: %.3f" %
                    (epoch, train_loss, train_acc, val_loss, val_acc))
        train_loss_list.append(train_loss)
        train_acc_list.append(train_acc)
        val_loss_list.append(val_loss)
        val_acc_list.append(val_acc)
        # save for every epoch
        if not os.path.exists(args.model_folder):
            os.makedirs(args.model_folder)
        path_model = os.path.join(args.model_folder , 'checkpoint_' + str(epoch) +'_.pth')
        torch.save(model.state_dict(), path_model )

        # save model
        if val_loss < best_val_loss:
            best_val_loss = val_loss
            path_model = os.path.join(args.model_folder , 'checkpoint_best_val_' + str(epoch) +'_.pth')
            torch.save(model.state_dict(), path_model )
        if val_acc < best_val_acc:
            best_val_acc = val_acc
            path_model = os.path.join(args.model_folder , 'checkpoint_best_acc_' + str(epoch) +'_.pth')
            torch.save(model.state_dict(), path_model )
            ######raise NotImplementedError("TODO: save model if a new best validation error was reached")

            ######raise NotImplementedError("TODO: save model if a new best validation error was reached")

        save_fig (train_loss_list, 'train_loss')
        save_fig (train_acc_list, 'train_acc')
        save_fig (val_loss_list, 'val_loss')
        save_fig (val_acc_list, 'val_acc')

        pd.DataFrame({'train_loss':train_loss_list}).to_csv(os.path.join(args.plots_folder, 'train_loss.csv'), index= False)
        pd.DataFrame({'train_acc':train_acc_list}).to_csv(os.path.join(args.plots_folder, 'train_acc.csv'), index= False)
        pd.DataFrame({'val_loss':val_loss_list}).to_csv(os.path.join(args.plots_folder, 'val_loss.csv'), index= False)
        pd.DataFrame({'val_acc':val_acc_list}).to_csv(os.path.join(args.plots_folder, 'val_acc.csv'), index= False)

# train one epoch over the whole training dataset. You can change the method's signature.
def train(loader, model, criterion, optimizer, device):
    #model.train()
    train_loss = 0
    train_acc = 0
    for batch_i, (data, target) in enumerate(loader):
        optimizer.zero_grad()
        output = model(data.to(device))
        loss = criterion(output, target.to(device))
        loss.backward()
        optimizer.step()
        train_loss += loss.mean().item()
        train_acc += accuracy(output, target.to(device))[0].item()

        if ((batch_i % 200)== 0):
            print('train batch ', batch_i, ' with loss: ', round(train_loss/(batch_i+1),5))
    train_acc = round((train_acc/(batch_i +1)),5)
    train_loss = round((train_loss/(batch_i +1)),5)

    return train_loss, train_acc
    ############raise NotImplementedError("TODO: training routine")

# validation function. you can change the method's signature.
def validate(loader, model, criterion, device):
    val_loss = 0
    val_acc = 0
    with torch.no_grad():
        for batch_i, (data, target) in enumerate (loader):
            output = model(data.to(device))
            val_loss += criterion(output, target.to(device)).mean().item()
            val_acc += accuracy(output, target.to(device))[0].item()
            if ((batch_i % 200) == 0):
                print ('validation batch: ', batch_i, ' with loss: ', round(val_loss/(batch_i+1),5))
    val_acc = round((val_acc/(batch_i+1)),5)
    val_loss = round((val_loss/(batch_i+1)),5)
    return val_loss, val_acc
    #########raise NotImplementedError("TODO: validation routine")
    # return mean_val_loss, mean_val_accuracy

def save_fig (train_list, name):
    plt.plot(train_list)
    plt.xlabel('epochs')
    plt.ylabel(name)
    if not os.path.exists(args.plots_folder):
        os.makedirs(args.plots_folder)
    path = os.path.join(args.plots_folder, name+'.png')
    plt.savefig(path)

if __name__ == '__main__':
    args = parse_arguments()
    pprint(vars(args))
    print()
    main(args)