# -*- coding: utf-8 -*-
# ALL SI UNITS
# milliMolar is same as mol/m^3

## USAGE: nohup python2.6 inhibition_tuftinput_repeats.py &> nohup_tuft.out < /dev/null &
## if running multiple of these, change tuft to tuft1, tuft2, etc above,
## change loop lists to result in largely non-overlapping runs or opposite order,
## change the ADIproc command to have tuft1, tuft2, etc unique str.

import os,sys
import os.path
import pickle
import subprocess
cwd = os.getcwd() # current working directory

from lock_utils import *

IN_VIVO = True
directed = True
reverse_list = [False] # lat B inhibits central A (False), vs A inhibits B (True)
frac_directed = 0.01#0.03#0.05 # for activity dependent inhibition, only geometric connectivity
## PROXIMAL_CONNECTION is not set by below proximal in networkConstantsMinimal.py,
## set it manually in networkConstants.py too + related USE_SECDEND_DECAY, strongsynfactorexclateral:
## -- see my labnote of 6th Aug, 2013.
proximal = True
NONLINEAR_ORNS = False
## UPDATE: I'm using odorinh=False to just give half the input when odorinh=True.
## Hence, for this half-comparison, ensure that odor bgnd to granules is same as air bgnd.
ODORINH = True#False # if ODORINH, use odor granule bgnd and 10Hz ORN to mitB, else air bgnd (35Hz) and 5Hz.
if ODORINH: mitB_freq = 10.0 # Hz # odor ORN input to tuft of mitB to cause lat inh
else: mitB_freq = 5.0#3.0 # Hz # air ORN input to tuft of mitB to cause lat inh
ASYM_TEST = False#True # Here unlike activdep inh, ASYM_TEST puts same ORN frate into B as A, rather than const.

mit_distance_list = [50.0,200.0,400.0,600.0,800.0,1000.0,1200.0,1400.0,1600.0,1800.0,1850.0,1900.0]
netseeds = [100.0,200.0,300.0,400.0,500.0,600.0,700.0,800.0,900.0,1000.0]

## inh_options = [ (no_singles,no_joints,no_PGs), ... ]
inh_options = [ (False,False,False) ]

ADI = []
for reverse in reverse_list:
    ADIdists = []
    for mit_distance in mit_distance_list:
        ADIfilenames = []
        for netseed in netseeds:
            for inh in inh_options:
                files_locked = True   # files have started to be opened for this iteration
                                    # made False, once simulation is loaded and files closed
                ## a special lock file to keep track of locking,
                ## since portalocker didn't work properly with multiple files
                print "Acquiring Lock for ADI."
                sys.stdout.flush()
                #mylock('locksimfile.txt','ADI\n')
                lock_file = portalock_open('locksimfile.txt')
                print "Locked files for ADI."
                sys.stdout.flush()

                gen_file = open('../generators/stimuliConstantsMinimal.py','w') # blank file created
                gen_file.write('## This file is programmatically generated.\n')
                gen_file.write('\n')
                gen_file.write('## used by generate_firerates.py\n')
                gen_file.write('stim_rate_seednum = 1000.0#441.0#212.0#191.0\n')
                gen_file.write('## used by generate_neuroml.py\n')
                gen_file.write('stim_net_seed = '+str(netseed)+'\n')
                gen_file.write('## distance between 2 mitrals for activity dependent inhibition\n')
                gen_file.write('mit_distance = '+str(mit_distance)+' # microns\n')
                gen_file.write('## use thresholded erf() on ORN firing rate?\n')
                gen_file.write('NONLINEAR_ORNS = '+str(NONLINEAR_ORNS)+'\n')
                gen_file.write('scaledWidth = 0.2 # s # width of scaled pulses\n')
                gen_file.close()

                net_file = open('../networks/networkConstantsMinimal.py','w') # blank file created    
                net_file.write('## actual number of modelled gloms could be 10 (for odor testing)\n')
                net_file.write('## or 2 (for inhibition testing) decided during neuroml generation.\n')
                net_file.write('## can set number of modelled glom to whatever you like.\n')
                net_file.write('## Randomly half of them will lie on central glom\'s mit0 or mit1.\n')
                net_file.write('## First half will receive odor A. Rest will receive odor B.\n')
                net_file.write('NUM_GLOMS = 2\n')
                net_file.write('\n')
                net_file.write('## Whether FRAC_DIRECTED of mits_per_syns will be\n')
                net_file.write('## connected between pairs listed in DIRECTED_CONNS.\n')
                net_file.write('## Keep directed True for simulating odors,\n')
                net_file.write('## Even for ADI, choose two connected mitrals.\n')
                net_file.write('directed = '+str(directed)+'\n')
                net_file.write('\n')
                net_file.write('## ensure that FRAC_DIRECTED * num of mitrals directed < 1.\n')
                net_file.write('## For NUM_GLOMS=10, 20mits all connected to mit0, FRAC_DIRECTED < 0.05.\n')
                net_file.write('## Can set FRAC_DIRECTED to 0.0 keeping DIRECTED=True. This will ensure that\n')
                net_file.write('## other mits lat dends are over directed centralmit\'s soma, if PROXIMAL_CONNECTION = True\n')
                net_file.write('frac_directed = '+str(frac_directed))
                net_file.write(' # I think you need to set this to 0.05 to get reasonable phase separation?\n')
                net_file.close()

                OBNet_file = '../netfiles/syn_conn_array_10000_singlesclubbed100_jointsclubbed1'\
                    '_numgloms2_seed'+str(netseed)+"_mitdist"+str(mit_distance)
                if directed:
                    OBNet_file += '_directed'+str(frac_directed)
                    if proximal: OBNet_file += '_proximal'
                    else: OBNet_file += '_distal'
                OBNet_file += '_2GLOMS'
                if not IN_VIVO: OBNet_file += '_INVITRO.xml'
                else: OBNet_file += '.xml'
                if not os.path.exists(OBNet_file):
                    print "Generating netfile",OBNet_file
                    gen_command = 'python2.6 '+cwd+'/../generators/generate_neuroML.py 2GLOMS'
                    if not IN_VIVO:
                        gen_command += ' INVITRO'
                    subprocess.check_call(gen_command,shell=True)
                else:
                    print "Netfile",OBNet_file,"already exists."

                simset_file = open('simset_activinhibition_minimal.py','w') # blank file created
                simset_file.write('## This file is programmatically generated.\n')
                simset_file.write('\n')
                simset_file.write('netseedstr = "'+str(netseed)+'"\n')
                simset_file.write('mitdistance = '+str(mit_distance)+' # microns\n')
                simset_file.write('mitdistancestr = "_mitdist'+str(mit_distance)+'" # microns\n')
                simset_file.write('\n')
                ## inh = (no_singles,no_joints,no_PGs)
                simset_file.write('NO_SINGLES = '+str(inh[0])+'\n')
                simset_file.write('## spine inhibition and singles are self-inh\n')
                simset_file.write('## toggle them on/off together\n')
                simset_file.write('NO_SPINE_INH = NO_SINGLES\n')
                simset_file.write('NO_JOINTS = '+str(inh[1])+'\n')
                simset_file.write('NO_MULTIS = NO_JOINTS\n')
                simset_file.write('NO_PGS = '+str(inh[2])+'\n')
                simset_file.write('\n')
                simset_file.write('## When testing ADI (ASYM_TEST = False),'\
                    ' fixed current in mitB to generate 80Hz. 1mM Mg++.\n')
                simset_file.write('## When testing asymmetry in inhibition (ASYM_TEST=True),'\
                    ' same currents in mitA and mitB, and 0.2mM Mg++.\n')
                simset_file.write('ASYM_TEST = '+str(ASYM_TEST)+'\n')
                simset_file.write('## reverse roles of mitA and mitB in activity dependent inhibition\n')
                simset_file.write('REVERSED_ADI = '+str(reverse)+'\n')
                simset_file.write('IN_VIVO = '+str(IN_VIVO)+'\n')
                simset_file.write('## tuftinput: if ODORINH, use higher inputs to ORNs, higher gran bgnd not used.\n')
                simset_file.write('ODORINH = '+str(ODORINH)+'\n')
                simset_file.write('oninject_ext = '+str(mitB_freq)+' # Hz \n')
                simset_file.close()

                ## activdep_inhibition.py checks if the output files exists
                ## if there is already an output file, it quits.
                ## NOSHOW is for not showing plots, adi/adi2 is uniquestr
                ## for running multiple parallel activdep_inhibition_repeats.py.
                ADIproc = subprocess.Popen('mpiexec -machinefile ~/hostfile -n 41'\
                    ' ~/Python-2.6.4/bin/python2.6 inhibition_tuftinput.py NOSHOW tuft1',\
                    shell=True,stdout=subprocess.PIPE)
                while True:
                    next_line = ADIproc.stdout.readline()
                    if not next_line:
                        break
                    sys.stdout.write(next_line)
                    if files_locked and ('Loading' in next_line):
                        ## now that the simulation has loaded,
                        ## unlock files for the other process.
                        ## only if files are locked still,
                        ## else redundant since 'Loading' appears multiple times
                        #myunlock('locksimfile.txt')
                        portalocker.unlock(lock_file)
                        lock_file.close()
                        files_locked = False # files are closed now
                        print "UnLocked files for ADI."
                    if 'Wrote' in next_line:
                        ADIfilename = next_line.split()[1]
                        ADIfilenames.append(ADIfilename)
                        break
                print ADIproc.communicate()[0]
                ## unlock in case files are locked even after odor_morphs quits.
                if files_locked:
                    #myunlock('locksimfile.txt')
                    portalocker.unlock(lock_file)
                    lock_file.close()
                    print "UnLocked files for ADI after quit."
        ADIdists.append(ADIfilenames)
    ADI.append(ADIdists)

print ADI
if IN_VIVO: invivo_str = '_invivo'
else: invivo_str = ''
if ODORINH: odorinh_str = '_odorinh'
else: odorinh_str = '_airinh'
fullfilename = '../results/tuftADI/tuftADI'+invivo_str+odorinh_str+'.pickle'
fullfile = open(fullfilename,'w')
pickle.dump(ADI, fullfile)
fullfile.close()
print "Wrote",fullfilename
