from abaqusConstants import *
from abaqusGui import *
from kernelAccess import mdb, session
import os

thisPath = os.path.abspath(__file__)
thisDir = os.path.dirname(thisPath)


###########################################################################
# Class definition
###########################################################################

class MonolithFE2DB(AFXDataDialog):

    #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    def __init__(self, form):

        # Construct the base class.
        #

        AFXDataDialog.__init__(self, form, 'MonolithFE2 Toolbox',
            self.OK|self.CANCEL, DIALOG_ACTIONS_SEPARATOR)
            

        okBtn = self.getActionButton(self.ID_CLICKED_OK)
        okBtn.setText('OK')
            
        TabBook_1 = FXTabBook(p=self, tgt=None, sel=0,
            opts=TABBOOK_NORMAL,
            x=0, y=0, w=0, h=0, pl=DEFAULT_SPACING, pr=DEFAULT_SPACING,
            pt=DEFAULT_SPACING, pb=DEFAULT_SPACING)
        tabItem = FXTabItem(p=TabBook_1, text='Mode', ic=None, opts=TAB_TOP_NORMAL,
            x=0, y=0, w=0, h=0, pl=6, pr=6, pt=DEFAULT_PAD, pb=DEFAULT_PAD)
        TabItem_1 = FXVerticalFrame(p=TabBook_1,
            opts=FRAME_RAISED|FRAME_THICK|LAYOUT_FILL_X,
            x=0, y=0, w=0, h=0, pl=DEFAULT_SPACING, pr=DEFAULT_SPACING,
            pt=DEFAULT_SPACING, pb=DEFAULT_SPACING, hs=DEFAULT_SPACING, vs=DEFAULT_SPACING)
        GroupBox_1 = FXGroupBox(p=TabItem_1, text='General Information', opts=FRAME_GROOVE|LAYOUT_FILL_X)
        l = FXLabel(p=GroupBox_1, text='Version 3.0', opts=JUSTIFY_LEFT)
        fileName = os.path.join(thisDir, 'Logo.png')
        icon = afxCreatePNGIcon(fileName)
        FXLabel(p=GroupBox_1, text='', ic=icon)
        l = FXLabel(p=GroupBox_1, text='This Plugin bundles all necessary tools to control MonolithFE2', opts=JUSTIFY_LEFT)
        GroupBox_2 = FXGroupBox(p=TabItem_1, text='Choose the current step:', opts=FRAME_GROOVE|LAYOUT_FILL_X)
        FXRadioButton(p=GroupBox_2, text='Generate a Inputscript for MonolithFE2', tgt=form.modeKw1, sel=116)
        FXRadioButton(p=GroupBox_2, text='Set Analysisparameters to control the Simulation', tgt=form.modeKw1, sel=117)
        FXRadioButton(p=GroupBox_2, text='Extract postprocessing data for a resimulation', tgt=form.modeKw1, sel=118)
        FXRadioButton(p=GroupBox_2, text='Generate Training data for ROM simulations', tgt=form.modeKw1, sel=119)
        FXRadioButton(p=GroupBox_2, text='Evaluate the training simulations', tgt=form.modeKw1, sel=120)
        tabItem = FXTabItem(p=TabBook_1, text='General', ic=None, opts=TAB_TOP_NORMAL,
            x=0, y=0, w=0, h=0, pl=6, pr=6, pt=DEFAULT_PAD, pb=DEFAULT_PAD)
        TabItem_2 = FXVerticalFrame(p=TabBook_1,
            opts=FRAME_RAISED|FRAME_THICK|LAYOUT_FILL_X,
            x=0, y=0, w=0, h=0, pl=DEFAULT_SPACING, pr=DEFAULT_SPACING,
            pt=DEFAULT_SPACING, pb=DEFAULT_SPACING, hs=DEFAULT_SPACING, vs=DEFAULT_SPACING)
        l = FXLabel(p=TabItem_2, text='Specify the previously created RVE model:', opts=JUSTIFY_LEFT)
        frame = AFXVerticalAligner(TabItem_2, 0, 0,0,0,0, 0,0,0,0)

        # Model combo
        # Since all forms will be canceled if the  model changes,
        # we do not need to register a query on the model.
        #
        self.RootComboBox_1 = AFXComboBox(p=frame, ncols=0, nvis=1, text='Model:', tgt=form.ModelnameKw, sel=0)
        self.RootComboBox_1.setMaxVisible(10)

        names = mdb.models.keys()
        names.sort()
        for name in names:
            self.RootComboBox_1.appendItem(name)
        if not form.ModelnameKw.getValue() in names:
            form.ModelnameKw.setValue( names[0] )
        msgCount = 36
        form.ModelnameKw.setTarget(self)
        form.ModelnameKw.setSelector(AFXDataDialog.ID_LAST+msgCount)
        msgHandler = str(self.__class__).split('.')[-1] + '.onComboBox_1PartsChanged'
        exec('FXMAPFUNC(self, SEL_COMMAND, AFXDataDialog.ID_LAST+%d, %s)' % (msgCount, msgHandler) )

        # Parts combo
        #
        self.ComboBox_1 = AFXComboBox(p=frame, ncols=0, nvis=1, text='Part:', tgt=form.PartnameKw, sel=0)
        self.ComboBox_1.setMaxVisible(10)

        self.form = form
        self.regModelName = None
        AFXTextField(p=TabItem_2, ncols=12, labelText='RVE Volume: ', tgt=form.RVE_VolumeKw, sel=0)
        if isinstance(TabItem_2, FXHorizontalFrame):
            FXVerticalSeparator(p=TabItem_2, x=0, y=0, w=0, h=0, pl=2, pr=2, pt=2, pb=2)
        else:
            FXHorizontalSeparator(p=TabItem_2, x=0, y=0, w=0, h=0, pl=2, pr=2, pt=2, pb=2)
        AFXTextField(p=TabItem_2, ncols=17, labelText='Job name of the macro job:', tgt=form.jobnameKw, sel=0)
        ComboBox_2 = AFXComboBox(p=TabItem_2, ncols=0, nvis=1, text='RVE-Number:', tgt=form.rve_numberKw, sel=0)
        ComboBox_2.setMaxVisible(10)
        ComboBox_2.appendItem(text='1')
        ComboBox_2.appendItem(text='2')
        ComboBox_2.appendItem(text='3')
        ComboBox_2.appendItem(text='4')
        ComboBox_2.appendItem(text='5')
        if isinstance(TabItem_2, FXHorizontalFrame):
            FXVerticalSeparator(p=TabItem_2, x=0, y=0, w=0, h=0, pl=2, pr=2, pt=2, pb=2)
        else:
            FXHorizontalSeparator(p=TabItem_2, x=0, y=0, w=0, h=0, pl=2, pr=2, pt=2, pb=2)
        AFXTextField(p=TabItem_2, ncols=17, labelText='RVE description:', tgt=form.informationKw, sel=0)
        l = FXLabel(p=TabItem_2, text='The text is written into the input file for informational purposes only,', opts=JUSTIFY_LEFT)
        l = FXLabel(p=TabItem_2, text='but has to be present.', opts=JUSTIFY_LEFT)
        if isinstance(TabItem_2, FXHorizontalFrame):
            FXVerticalSeparator(p=TabItem_2, x=0, y=0, w=0, h=0, pl=2, pr=2, pt=2, pb=2)
        else:
            FXHorizontalSeparator(p=TabItem_2, x=0, y=0, w=0, h=0, pl=2, pr=2, pt=2, pb=2)
        tabItem = FXTabItem(p=TabBook_1, text='Boundary', ic=None, opts=TAB_TOP_NORMAL,
            x=0, y=0, w=0, h=0, pl=6, pr=6, pt=DEFAULT_PAD, pb=DEFAULT_PAD)
        TabItem_3 = FXVerticalFrame(p=TabBook_1,
            opts=FRAME_RAISED|FRAME_THICK|LAYOUT_FILL_X,
            x=0, y=0, w=0, h=0, pl=DEFAULT_SPACING, pr=DEFAULT_SPACING,
            pt=DEFAULT_SPACING, pb=DEFAULT_SPACING, hs=DEFAULT_SPACING, vs=DEFAULT_SPACING)
        ComboBox_3 = AFXComboBox(p=TabItem_3, ncols=0, nvis=1, text='mode:', tgt=form.PBCKw, sel=0)
        ComboBox_3.setMaxVisible(10)
        ComboBox_3.appendItem(text='Create Periodic BCs')
        ComboBox_3.appendItem(text='Read Boundary Condiions from Equations')
        GroupBox_4 = FXGroupBox(p=TabItem_3, text='Only when the Periodic BCs are to be created:', opts=FRAME_GROOVE|LAYOUT_FILL_X)
        AFXTextField(p=GroupBox_4, ncols=12, labelText='Setname of the RVE boundary:', tgt=form.set_boundaryKw, sel=0)
        l = FXLabel(p=GroupBox_4, text='Note: Must be defined at the Part level', opts=JUSTIFY_LEFT)
        AFXTextField(p=GroupBox_4, ncols=12, labelText='Periodicity vectors:', tgt=form.period_vectorsKw, sel=0)
        l = FXLabel(p=GroupBox_4, text='Note: The vectors have to be inputed in the format', opts=JUSTIFY_LEFT)
        l = FXLabel(p=GroupBox_4, text='n_11,n_21,n_31;n_12,n_22,n_32;...', opts=JUSTIFY_LEFT)
        GroupBox_18 = FXGroupBox(p=TabItem_3, text='When the BCs are read from Equations:', opts=FRAME_GROOVE|LAYOUT_FILL_X)
        l = FXLabel(p=GroupBox_18, text='Be careful to follow the conventions of this plugin:', opts=JUSTIFY_LEFT)
        l = FXLabel(p=GroupBox_18, text='The macro steering reference points have to be named exactly', opts=JUSTIFY_LEFT)
        l = FXLabel(p=GroupBox_18, text='E11,E22,E33,E12,E13,E23 whereby the shear strains are', opts=JUSTIFY_LEFT)
        l = FXLabel(p=GroupBox_18, text='the engineering strains! The macro rigid body displacement must', opts=JUSTIFY_LEFT)
        l = FXLabel(p=GroupBox_18, text='be named U1,U2,U3 (and set to zero) and to be enforced via', opts=JUSTIFY_LEFT)
        l = FXLabel(p=GroupBox_18, text='equations to a certain node. In all Equations each set has', opts=JUSTIFY_LEFT)
        l = FXLabel(p=GroupBox_18, text='to correspond to a single node of the mesh.', opts=JUSTIFY_LEFT)
        tabItem = FXTabItem(p=TabBook_1, text='Parameters', ic=None, opts=TAB_TOP_NORMAL,
            x=0, y=0, w=0, h=0, pl=6, pr=6, pt=DEFAULT_PAD, pb=DEFAULT_PAD)
        TabItem_4 = FXVerticalFrame(p=TabBook_1,
            opts=FRAME_RAISED|FRAME_THICK|LAYOUT_FILL_X,
            x=0, y=0, w=0, h=0, pl=DEFAULT_SPACING, pr=DEFAULT_SPACING,
            pt=DEFAULT_SPACING, pb=DEFAULT_SPACING, hs=DEFAULT_SPACING, vs=DEFAULT_SPACING)
        ComboBox_4 = AFXComboBox(p=TabItem_4, ncols=0, nvis=1, text='solution scheme:', tgt=form.schemeKw, sel=0)
        ComboBox_4.setMaxVisible(10)
        ComboBox_4.appendItem(text='monolithic')
        ComboBox_4.appendItem(text='staggered')
        GroupBox_5 = FXGroupBox(p=TabItem_4, text='staggered control parameters:', opts=FRAME_GROOVE|LAYOUT_FILL_X)
        l = FXLabel(p=GroupBox_5, text='convergence criterion for the ratio of largest residual to largest nonzero force', opts=JUSTIFY_LEFT)
        AFXTextField(p=GroupBox_5, ncols=12, labelText='parameter:', tgt=form.convergence_ratioKw, sel=0)
        l = FXLabel(p=GroupBox_5, text='maximum number of iterations', opts=JUSTIFY_LEFT)
        AFXTextField(p=GroupBox_5, ncols=12, labelText='parameter:', tgt=form.max_itersKw, sel=0)
        GroupBox_9 = FXGroupBox(p=TabItem_4, text='monolithic control parameters:', opts=FRAME_GROOVE|LAYOUT_FILL_X)
        l = FXLabel(p=GroupBox_9, text='storing the stiffness matrix factorization for the next iteration (true is faster, but', opts=JUSTIFY_LEFT)
        l = FXLabel(p=GroupBox_9, text='needs significantly more memory when not in ROM mode)', opts=JUSTIFY_LEFT)
        ComboBox_7 = AFXComboBox(p=GroupBox_9, ncols=0, nvis=1, text='parameter:', tgt=form.save_soeKw, sel=0)
        ComboBox_7.setMaxVisible(10)
        ComboBox_7.appendItem(text='true')
        ComboBox_7.appendItem(text='false')
        GroupBox_7 = FXGroupBox(p=TabItem_4, text='solver settings:', opts=FRAME_GROOVE|LAYOUT_FILL_X)
        l = FXLabel(p=GroupBox_7, text='assumption about the stiffness matrix definiteness', opts=JUSTIFY_LEFT)
        ComboBox_5 = AFXComboBox(p=GroupBox_7, ncols=0, nvis=1, text='parameter:', tgt=form.indefinite_matrixKw, sel=0)
        ComboBox_5.setMaxVisible(10)
        ComboBox_5.appendItem(text='indefinite')
        ComboBox_5.appendItem(text='positive definite')
        l = FXLabel(p=GroupBox_7, text='assumption about the stiffness matrix symmetry', opts=JUSTIFY_LEFT)
        ComboBox_6 = AFXComboBox(p=GroupBox_7, ncols=0, nvis=1, text='parameter', tgt=form.symmetric_matrixKw, sel=0)
        ComboBox_6.setMaxVisible(10)
        ComboBox_6.appendItem(text='symm')
        ComboBox_6.appendItem(text='unsymm')
        l = FXLabel(p=GroupBox_7, text='solution method:', opts=JUSTIFY_LEFT)
        ComboBox_8 = AFXComboBox(p=GroupBox_7, ncols=0, nvis=1, text='parameter:', tgt=form.solving_processKw, sel=0)
        ComboBox_8.setMaxVisible(10)
        ComboBox_8.appendItem(text='full')
        ComboBox_8.appendItem(text='reduced')
        ComboBox_8.appendItem(text='hyperreduced')
        tabItem = FXTabItem(p=TabBook_1, text='Postprocessing', ic=None, opts=TAB_TOP_NORMAL,
            x=0, y=0, w=0, h=0, pl=6, pr=6, pt=DEFAULT_PAD, pb=DEFAULT_PAD)
        TabItem_5 = FXVerticalFrame(p=TabBook_1,
            opts=FRAME_RAISED|FRAME_THICK|LAYOUT_FILL_X,
            x=0, y=0, w=0, h=0, pl=DEFAULT_SPACING, pr=DEFAULT_SPACING,
            pt=DEFAULT_SPACING, pb=DEFAULT_SPACING, hs=DEFAULT_SPACING, vs=DEFAULT_SPACING)
        l = FXLabel(p=TabItem_5, text='Select the macro-odb to extract the load history', opts=JUSTIFY_LEFT)
        frame = FXHorizontalFrame(TabItem_5, 0, 0,0,0,0, 0,0,0,0)

        # ODB combo
        #
        self.RootComboBox_9 = AFXComboBox(p=frame, ncols=0, nvis=1, text='ODB:', tgt=form.macro_odbNameKw, sel=0)
        self.RootComboBox_9.setMaxVisible(10)
        msgCount = 37
        form.macro_odbNameKw.setTarget(self)
        form.macro_odbNameKw.setSelector(AFXDataDialog.ID_LAST+msgCount)
        msgHandler = str(self.__class__).split('.')[-1] + '.onPartsChanged'
        exec('FXMAPFUNC(self, SEL_COMMAND, AFXDataDialog.ID_LAST+%d, %s)' % (msgCount, msgHandler) )

        # Parts combo
        #
        self.ComboBox_9 = AFXComboBox(p=frame, ncols=0, nvis=1, text='Part:', tgt=form.macro_modelNameKw, sel=0)
        self.ComboBox_9.setMaxVisible(10)

        self.form = form
        pickHf = FXHorizontalFrame(p=TabItem_5, opts=0, x=0, y=0, w=0, h=0,
            pl=0, pr=0, pt=0, pb=0, hs=DEFAULT_SPACING, vs=DEFAULT_SPACING)
        # Note: Set the selector to indicate that this widget should not be
        #       colored differently from its parent when the 'Color layout managers'
        #       button is checked in the RSG Dialog Builder dialog.
        pickHf.setSelector(99)
        label = FXLabel(p=pickHf, text='Pick an element:' + ' (None)', ic=None, opts=LAYOUT_CENTER_Y|JUSTIFY_LEFT)
        pickHandler = MonolithFE2DBPickHandler(form, form.elementKw, 'Pick an entity', ELEMENTS, ONE, label)
        icon = afxGetIcon('select', AFX_ICON_SMALL )
        FXButton(p=pickHf, text='\tPick Items in Viewport', ic=icon, tgt=pickHandler, sel=AFXMode.ID_ACTIVATE,
            opts=BUTTON_NORMAL|LAYOUT_CENTER_Y, x=0, y=0, w=0, h=0, pl=2, pr=2, pt=1, pb=1)
        AFXTextField(p=TabItem_5, ncols=12, labelText='Specify the integration point:', tgt=form.integration_pointKw, sel=0)
        ComboBox_10 = AFXComboBox(p=TabItem_5, ncols=0, nvis=1, text='Get the load history from:', tgt=form.sourceKw, sel=0)
        ComboBox_10.setMaxVisible(10)
        ComboBox_10.appendItem(text='SDV')
        ComboBox_10.appendItem(text='E')
        l = FXLabel(p=TabItem_5, text='Note in order to use SDV (solution depenend variables) as source of the load', opts=JUSTIFY_LEFT)
        l = FXLabel(p=TabItem_5, text='history, SDVs must be requested as field output in the STEP. Use strains E only', opts=JUSTIFY_LEFT)
        l = FXLabel(p=TabItem_5, text='for geometricalls linear simulations.', opts=JUSTIFY_LEFT)
        tabItem = FXTabItem(p=TabBook_1, text='Training', ic=None, opts=TAB_TOP_NORMAL,
            x=0, y=0, w=0, h=0, pl=6, pr=6, pt=DEFAULT_PAD, pb=DEFAULT_PAD)
        TabItem_6 = FXVerticalFrame(p=TabBook_1,
            opts=FRAME_RAISED|FRAME_THICK|LAYOUT_FILL_X,
            x=0, y=0, w=0, h=0, pl=DEFAULT_SPACING, pr=DEFAULT_SPACING,
            pt=DEFAULT_SPACING, pb=DEFAULT_SPACING, hs=DEFAULT_SPACING, vs=DEFAULT_SPACING)
        l = FXLabel(p=TabItem_6, text='General Settings:', opts=JUSTIFY_LEFT)
        l.setFont( getAFXFont(FONT_BOLD) )
        AFXTextField(p=TabItem_6, ncols=12, labelText='Number of cpus:', tgt=form.ncpusKw, sel=0)
        ComboBox_14 = AFXComboBox(p=TabItem_6, ncols=0, nvis=1, text='Method:', tgt=form.MethodKw, sel=0)
        ComboBox_14.setMaxVisible(10)
        ComboBox_14.appendItem(text='ROM')
        ComboBox_14.appendItem(text='hyperROM')
        GroupBox_12 = FXGroupBox(p=TabItem_6, text='Training data generation:', opts=FRAME_GROOVE|LAYOUT_FILL_X)
        ComboBox_16 = AFXComboBox(p=GroupBox_12, ncols=0, nvis=1, text='get training directions from: ', tgt=form.training_directionsKw, sel=0)
        ComboBox_16.setMaxVisible(10)
        ComboBox_16.appendItem(text='clustering')
        ComboBox_16.appendItem(text='unspecific')
        ComboBox_13 = AFXComboBox(p=GroupBox_12, ncols=0, nvis=1, text='Training mode:', tgt=form.training_modeKw, sel=0)
        ComboBox_13.setMaxVisible(10)
        ComboBox_13.appendItem(text='stress and strain')
        ComboBox_13.appendItem(text='stress')
        ComboBox_13.appendItem(text='strain')
        ComboBox_12 = AFXComboBox(p=GroupBox_12, ncols=0, nvis=1, text='NLGEOM:', tgt=form.nlgeomKw, sel=0)
        ComboBox_12.setMaxVisible(10)
        ComboBox_12.appendItem(text='YES')
        ComboBox_12.appendItem(text='NO')
        AFXTextField(p=GroupBox_12, ncols=12, labelText='data dump every x [s]:', tgt=form.dtime_data_dumpKw, sel=0)
        fileHandler = MonolithFE2DBFileHandler(form, 'program_directory', 'All files (*)')
        fileTextHf = FXHorizontalFrame(p=GroupBox_12, opts=0, x=0, y=0, w=0, h=0,
            pl=0, pr=0, pt=0, pb=0, hs=DEFAULT_SPACING, vs=DEFAULT_SPACING)
        # Note: Set the selector to indicate that this widget should not be
        #       colored differently from its parent when the 'Color layout managers'
        #       button is checked in the RSG Dialog Builder dialog.
        fileTextHf.setSelector(99)
        AFXTextField(p=fileTextHf, ncols=12, labelText='Path to UMAT_Driver binary:', tgt=form.program_directoryKw, sel=0,
            opts=AFXTEXTFIELD_STRING|LAYOUT_CENTER_Y)
        icon = afxGetIcon('fileOpen', AFX_ICON_SMALL )
        FXButton(p=fileTextHf, text='	Select File\nFrom Dialog', ic=icon, tgt=fileHandler, sel=AFXMode.ID_ACTIVATE,
            opts=BUTTON_NORMAL|LAYOUT_CENTER_Y, x=0, y=0, w=0, h=0, pl=1, pr=1, pt=1, pb=1)
        FXCheckButton(p=GroupBox_12, text='directly start training simulations', tgt=form.start_simulationsKw, sel=0)
        GroupBox_16 = FXGroupBox(p=GroupBox_12, text='Clustered training:', opts=FRAME_GROOVE|LAYOUT_FILL_X)
        frame = FXHorizontalFrame(GroupBox_16, 0, 0,0,0,0, 0,0,0,0)

        # ODB combo
        #
        self.RootComboBox_15 = AFXComboBox(p=frame, ncols=0, nvis=1, text='ODB:', tgt=form.odb_for_clusteringKw, sel=0)
        self.RootComboBox_15.setMaxVisible(10)
        msgCount = 38
        form.odb_for_clusteringKw.setTarget(self)
        form.odb_for_clusteringKw.setSelector(AFXDataDialog.ID_LAST+msgCount)
        msgHandler = str(self.__class__).split('.')[-1] + '.onPartsChanged'
        exec('FXMAPFUNC(self, SEL_COMMAND, AFXDataDialog.ID_LAST+%d, %s)' % (msgCount, msgHandler) )

        # Parts combo
        #
        self.ComboBox_15 = AFXComboBox(p=frame, ncols=0, nvis=1, text='Part:', tgt=form.part_for_clusteringKw, sel=0)
        self.ComboBox_15.setMaxVisible(10)

        self.form = form
        FXRadioButton(p=GroupBox_16, text='cluster all time steps', tgt=form.GroupBox_clusteringmodeKw1, sel=121)
        FXRadioButton(p=GroupBox_16, text='cluster only speficific timesteps (e.g. last one)', tgt=form.GroupBox_clusteringmodeKw1, sel=122)
        AFXTextField(p=GroupBox_16, ncols=12, labelText='     timestep-numbers sparated by comma:', tgt=form.timestep_numbers_clusteringKw, sel=0)
        FXRadioButton(p=GroupBox_16, text='cluster normalized values of the last timestep', tgt=form.GroupBox_clusteringmodeKw1, sel=123)
        GroupBox_17 = FXGroupBox(p=GroupBox_16, text='get number of clusters by', opts=FRAME_GROOVE|LAYOUT_FILL_X)
        FXRadioButton(p=GroupBox_17, text='prescribed number of clusters:', tgt=form.prescribe_number_clustersKw1, sel=124)
        AFXTextField(p=GroupBox_17, ncols=12, labelText='Label:', tgt=form.n_clustersKw, sel=0)
        FXRadioButton(p=GroupBox_17, text='share of error drop rate w.r.t. inital rate', tgt=form.prescribe_number_clustersKw1, sel=125)
        AFXTextField(p=GroupBox_17, ncols=12, labelText='Label:', tgt=form.cluster_rel_error_dropKw, sel=0)
        GroupBox_15 = FXGroupBox(p=GroupBox_12, text='Unspecific training:', opts=FRAME_GROOVE|LAYOUT_FILL_X)
        l = FXLabel(p=GroupBox_15, text='Number of variations of each component of the strain/stress tensor', opts=JUSTIFY_LEFT)
        AFXTextField(p=GroupBox_15, ncols=12, labelText='number of variations', tgt=form.n_variationsKw, sel=0)
        AFXTextField(p=GroupBox_15, ncols=12, labelText='Stress amplitude:', tgt=form.stress_ampKw, sel=0)
        AFXTextField(p=GroupBox_15, ncols=12, labelText='Strain amplitude:', tgt=form.strain_ampKw, sel=0)
        AFXTextField(p=GroupBox_15, ncols=12, labelText='total simulation time [s]:', tgt=form.simulation_timeKw, sel=0)
        GroupBox_14 = FXGroupBox(p=TabItem_6, text='Training data evaluation:', opts=FRAME_GROOVE|LAYOUT_FILL_X)
        AFXTextField(p=GroupBox_14, ncols=12, labelText='Number of modes:', tgt=form.n_modesKw, sel=0)
        AFXTextField(p=GroupBox_14, ncols=12, labelText='Number of hyper elements:', tgt=form.NELEMKw, sel=0)
        fileHandler = MonolithFE2DBFileHandler(form, 'path_to_inputfile', '(*.FE1)')
        fileTextHf = FXHorizontalFrame(p=GroupBox_14, opts=0, x=0, y=0, w=0, h=0,
            pl=0, pr=0, pt=0, pb=0, hs=DEFAULT_SPACING, vs=DEFAULT_SPACING)
        # Note: Set the selector to indicate that this widget should not be
        #       colored differently from its parent when the 'Color layout managers'
        #       button is checked in the RSG Dialog Builder dialog.
        fileTextHf.setSelector(99)
        AFXTextField(p=fileTextHf, ncols=12, labelText='micro Inputfile:', tgt=form.path_to_inputfileKw, sel=0,
            opts=AFXTEXTFIELD_STRING|LAYOUT_CENTER_Y)
        icon = afxGetIcon('fileOpen', AFX_ICON_SMALL )
        FXButton(p=fileTextHf, text='	Select File\nFrom Dialog', ic=icon, tgt=fileHandler, sel=AFXMode.ID_ACTIVATE,
            opts=BUTTON_NORMAL|LAYOUT_CENTER_Y, x=0, y=0, w=0, h=0, pl=1, pr=1, pt=1, pb=1)

    #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    def show(self):

        AFXDataDialog.show(self)

        # Register a query on parts
        #
        currentModelName = getCurrentContext()['modelName']
        self.form.ModelnameKw.setValue(currentModelName)
        mdb.models.registerQuery(self.updateComboBox_1Models, False)
        self.registerComboBox_1PartQuery(currentModelName)

        # Select the current ODB, if there is one
        #
        names = session.odbs.keys()
        names.sort()
        objectType = getCurrentContext()['objectType']
        if objectType == 'ODB':
            self.currentOdbName = getCurrentContext()['objectPath']
        elif names:
            self.currentOdbName = names[0]
        else:
            self.currentOdbName = ''

        self.form.macro_odbNameKw.setValue(self.currentOdbName)

        session.odbs.registerQuery(self.updateRootComboBox_9Odbs)

        # Select the current ODB, if there is one
        #
        names = session.odbs.keys()
        names.sort()
        objectType = getCurrentContext()['objectType']
        if objectType == 'ODB':
            self.currentOdbName = getCurrentContext()['objectPath']
        elif names:
            self.currentOdbName = names[0]
        else:
            self.currentOdbName = ''

        self.form.odb_for_clusteringKw.setValue(self.currentOdbName)

        session.odbs.registerQuery(self.updateRootComboBox_15Odbs)

    #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    def hide(self):

        AFXDataDialog.hide(self)

        self.registerComboBox_1PartQuery(None)
        mdb.models.unregisterQuery(self.updateComboBox_1Models)

        session.odbs.unregisterQuery(self.updateRootComboBox_9Odbs)

        session.odbs.unregisterQuery(self.updateRootComboBox_15Odbs)

    #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    def registerComboBox_1PartQuery(self, modelName):

        if modelName == self.regModelName:
           return

        cbFunc = self.updateComboBox_1Parts
        modelKeys = mdb.models.keys()
        if self.regModelName in modelKeys:
           mdb.models[self.regModelName].unregisterQuery(cbFunc)
        self.regModelName = None

        if modelName in modelKeys:
           mdb.models[modelName].registerQuery(cbFunc, False)
           self.regModelName = modelName

    #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    def updateComboBox_1Models(self):

        # Update the names in the Models combo
        #
        self.RootComboBox_1.clearItems()
        names = mdb.models.keys()
        names.sort()
        for name in names:
           self.RootComboBox_1.appendItem(name)

        modelName = self.form.ModelnameKw.getValue()
        if not modelName in names:
           modelName = names[0]
        self.form.ModelnameKw.setValue(modelName) # Triggers parts combo update

    #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    def onComboBox_1PartsChanged(self, sender, sel, ptr):

        self.updateComboBox_1Parts()
        return 1

    #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    def updateComboBox_1Parts(self):

        # This is needed to handle lost registrations caused by model rename
        if not self.regModelName:
           return 1

        # Update the names in the Parts combo
        # 
        modelName = self.form.ModelnameKw.getValue()

        self.ComboBox_1.clearItems()
        names = mdb.models[modelName].parts.keys()
        names.sort()
        for name in names:
            self.ComboBox_1.appendItem(name)
        if names:
            if not self.form.PartnameKw.getValue() in names:
                self.form.PartnameKw.setValue( names[0] )
        else:
            self.form.PartnameKw.setValue('')

        self.resize( self.getDefaultWidth(), self.getDefaultHeight() )

        # Change parts container registration if the model has changed
        self.registerComboBox_1PartQuery(modelName)

    #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    def updateRootComboBox_9Odbs(self):

        # Update the names in the ODB combo
        #
        self.RootComboBox_9.clearItems()
        names = session.odbs.keys()
        names.sort()
        for name in names:
            self.RootComboBox_9.appendItem(name)

        if names:
            if not self.form.macro_odbNameKw.getValue() in names:
                self.form.macro_odbNameKw.setValue( names[0] )
        else:
            self.form.macro_odbNameKw.setValue('')

        self.onPartsChanged(None, None, None)

    #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    def onPartsChanged(self, sender, sel, ptr):

        odbName = self.form.macro_odbNameKw.getValue()

        # Update the names in the Parts combo
        #
        self.ComboBox_9.clearItems()
        if odbName:
            names = session.odbs[odbName].parts.keys()
            names.sort()
            for name in names:
                self.ComboBox_9.appendItem(name)

            if names:
                if not self.form.macro_modelNameKw.getValue() in names:
                    self.form.macro_modelNameKw.setValue( names[0] )
            else:
                self.form.macro_modelNameKw.setValue('')

        else:
            self.form.macro_modelNameKw.setValue('')

        self.resize( self.getDefaultWidth(), self.getDefaultHeight() )

        return 1

    #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    def updateRootComboBox_15Odbs(self):

        # Update the names in the ODB combo
        #
        self.RootComboBox_15.clearItems()
        names = session.odbs.keys()
        names.sort()
        for name in names:
            self.RootComboBox_15.appendItem(name)

        if names:
            if not self.form.odb_for_clusteringKw.getValue() in names:
                self.form.odb_for_clusteringKw.setValue( names[0] )
        else:
            self.form.odb_for_clusteringKw.setValue('')

        self.onPartsChanged(None, None, None)

    #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    def onPartsChanged(self, sender, sel, ptr):

        odbName = self.form.odb_for_clusteringKw.getValue()

        # Update the names in the Parts combo
        #
        self.ComboBox_15.clearItems()
        if odbName:
            names = session.odbs[odbName].parts.keys()
            names.sort()
            for name in names:
                self.ComboBox_15.appendItem(name)

            if names:
                if not self.form.part_for_clusteringKw.getValue() in names:
                    self.form.part_for_clusteringKw.setValue( names[0] )
            else:
                self.form.part_for_clusteringKw.setValue('')

        else:
            self.form.part_for_clusteringKw.setValue('')

        self.resize( self.getDefaultWidth(), self.getDefaultHeight() )

        return 1



###########################################################################
# Class definition
###########################################################################

class MonolithFE2DBPickHandler(AFXProcedure):

        count = 0

        #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        def __init__(self, form, keyword, prompt, entitiesToPick, numberToPick, label):

                self.form = form
                self.keyword = keyword
                self.prompt = prompt
                self.entitiesToPick = entitiesToPick # Enum value
                self.numberToPick = numberToPick # Enum value
                self.label = label
                self.labelText = label.getText()

                AFXProcedure.__init__(self, form.getOwner())

                MonolithFE2DBPickHandler.count += 1
                self.setModeName('MonolithFE2DBPickHandler%d' % (MonolithFE2DBPickHandler.count) )

        #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        def getFirstStep(self):

                return  AFXPickStep(self, self.keyword, self.prompt, 
                    self.entitiesToPick, self.numberToPick, sequenceStyle=TUPLE)

        #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        def getNextStep(self, previousStep):

                self.label.setText( self.labelText.replace('None', 'Picked') )
                return None

        def deactivate(self):

            AFXProcedure.deactivate(self)
            if  self.numberToPick == ONE and self.keyword.getValue() and self.keyword.getValue()[0]!='<':
                sendCommand(self.keyword.getSetupCommands() + '\nhighlight(%s)' % self.keyword.getValue() )



###########################################################################
# Class definition
###########################################################################

class MonolithFE2DBFileHandler(FXObject):

    #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    def __init__(self, form, keyword, patterns='*'):

        self.form = form
        self.patterns = patterns
        self.patternTgt = AFXIntTarget(0)
        exec('self.fileNameKw = form.%sKw' % keyword)
        self.readOnlyKw = AFXBoolKeyword(None, 'readOnly', AFXBoolKeyword.TRUE_FALSE)
        FXObject.__init__(self)
        FXMAPFUNC(self, SEL_COMMAND, AFXMode.ID_ACTIVATE, MonolithFE2DBFileHandler.activate)

    #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    def activate(self, sender, sel, ptr):

       fileDb = AFXFileSelectorDialog(getAFXApp().getAFXMainWindow(), 'Select a File',
           self.fileNameKw, self.readOnlyKw,
           AFXSELECTFILE_ANY, self.patterns, self.patternTgt)
       fileDb.setReadOnlyPatterns('*.odb')
       fileDb.create()
       fileDb.showModal()
