Index: /issm/trunk-jpl/src/m/classes/clusters/pfe.py
===================================================================
--- /issm/trunk-jpl/src/m/classes/clusters/pfe.py	(revision 19157)
+++ /issm/trunk-jpl/src/m/classes/clusters/pfe.py	(revision 19157)
@@ -0,0 +1,182 @@
+# import socket
+# import os
+# import math
+import subprocess
+from fielddisplay import fielddisplay
+from EnumToString import EnumToString
+from pairoptions import pairoptions
+from issmssh import issmssh
+from issmscpin import issmscpin
+from issmscpout import issmscpout
+from QueueRequirements import QueueRequirements
+try:
+	from pfe_settings import pfe_settings
+except ImportError:
+	print 'You need pfe_settings.py to proceed, check presence and sys.path'
+	
+class pfe(object):
+	"""
+	PFE cluster class definition
+ 
+	   Usage:
+	      cluster=pfe();
+	      cluster=pfe('np',3);
+	      cluster=pfe('np',3,'login','username');
+	"""
+
+	def __init__(self,*args):
+		# {{{
+
+		self.name           = 'pfe'
+		self.login          = ''
+		self.numnodes       = 20
+		self.cpuspernode    = 8
+		self.port           = 1025
+		self.queue          = 'long'
+		self.time           = 12*60
+		self.processor      = 'wes'
+		self.codepath       = ''
+		self.executionpath  = ''
+		self.grouplist      = 's1010'
+		self.interactive    = 0
+		self.bbftp          = 0
+		self.numstreams     = 8
+		self.hyperthreading = 0
+
+		self.np=self.numnodes*self.cpuspernode;
+		
+		#use provided options to change fields
+		options=pairoptions(*args)
+
+		#initialize cluster using user settings if provided
+		self=pfe_settings(self)
+
+		#OK get other fields
+		self=options.AssignObjectFields(self)
+		
+		# }}}
+
+	def __repr__(self):
+		# {{{
+		#  display the object
+		s = "class pfe object:"
+		s	= "%s\n%s"%(s,fielddisplay(self,'name','name of the cluster'))
+		s	= "%s\n%s"%(s,fielddisplay(self,'login','login'))
+		s = "%s\n%s"%(s,fielddisplay(self,'numnodes','number of nodes'))
+		s = "%s\n%s"%(s,fielddisplay(self,'cpuspernode','number of nodes per CPUs'))
+		s = "%s\n%s"%(s,fielddisplay(self,'np','number of CPUs'))
+		s = "%s\n%s"%(s,fielddisplay(self,'port','machine access port'))
+		s = "%s\n%s"%(s,fielddisplay(self,'codepath','code path on the cluster'))
+		s = "%s\n%s"%(s,fielddisplay(self,'executionpath','execution path on the cluster'))
+		s = "%s\n%s"%(s,fielddisplay(self,'queue','name of the queue'))
+		s = "%s\n%s"%(s,fielddisplay(self,'time','walltime requested'))
+		s = "%s\n%s"%(s,fielddisplay(self,'processor','type of processor'))
+		s = "%s\n%s"%(s,fielddisplay(self,'grouplist','name of the group'))
+		s = "%s\n%s"%(s,fielddisplay(self,'interactive',''))
+		s = "%s\n%s"%(s,fielddisplay(self,'bbftp',''))
+		s = "%s\n%s"%(s,fielddisplay(self,'numstreams',''))
+		s = "%s\n%s"%(s,fielddisplay(self,'hyperthreading',''))
+		return s
+	# }}}
+
+	def checkconsistency(self,md,solution,analyses):
+		# {{{
+
+
+		queuedict = {'long': [5*24*60, 2048],
+								 'normal': [8*60, 2048],
+								 'debug':[2*60,150],
+								 'devel':[2*60,150]}
+		QueueRequirements(queuedict,self.queue,self.np,self.time)
+
+		#now, check cluster.cpuspernode according to processor type
+		if self.processor=='har' or self.processor=='neh':
+			if self.hyperthreading:
+				if not 0<self.cpuspernode<17:
+					md = md.checkmessage('cpuspernode should be between 1 and 16 for ''neh'' and ''har'' processors in hyperthreading mode')
+			else:
+				if not 0<self.cpuspernode<9:
+					md = md.checkmessage('cpuspernode should be between 1 and 8 for ''neh'' and ''har'' processors')
+
+		elif self.processor=='wes':
+			if self.hyperthreading:
+				if not 0<self.cpuspernode<25:
+					md = md.checkmessage('cpuspernode should be between 1 and 24 for ''wes'' processors in hyperthreading mode')
+			else:
+				if not 0<self.cpuspernode<13:
+					md = md.checkmessage('cpuspernode should be between 1 and 12 for ''wes'' processors')
+
+		elif self.processor=='ivy':
+			if self.hyperthreading:
+				if not 0<self.cpuspernode<41:
+					md = md.checkmessage('cpuspernode should be between 1 and 40 for ''ivy'' processors in hyperthreading mode')
+			else:
+				if not 0<self.cpuspernode<21:
+					md = md.checkmessage('cpuspernode should be between 1 and 20 for ''ivy'' processors')
+		else:
+			md = md.checkmessage('unknown processor type, should be ''neh'',''wes'' or ''har'' or ''ivy''')
+	
+		#Miscelaneous
+		if not self.login:
+			md = md.checkmessage('login empty')
+		if not self.codepath:
+			md = md.checkmessage('codepath empty')
+		if not self.executionpath:
+			md = md.checkmessage('executionpath empty')
+		if not self.grouplist:
+			md = md.checkmessage('grouplist empty')
+		if self.interactive==1:
+			md = md.checkmessage('interactive mode not implemented')
+			
+		return self
+	# }}}
+	def BuildQueueScript(self,dirname,modelname,solution,io_gather,isvalgrind,isgprof):
+		# {{{
+
+		#write queuing script 
+		fid=open(modelname+'.queue','w')
+		fid.write('#PBS -S /bin/bash\n')
+		fid.write('#PBS -l select=%i:ncpus=%i:model=%s\n' % (self.numnodes,self.cpuspernode,self.processor))
+		fid.write('#PBS -l walltime=%i\n' % (self.time*60))
+		fid.write('#PBS -q %s \n' % self.queue)
+		fid.write('#PBS -W group_list=%s\n' % self.grouplist)
+		fid.write('#PBS -m e\n')
+		fid.write('#PBS -o %s/%s/%s.outlog \n' % (self.executionpath,dirname,modelname))
+		fid.write('#PBS -e %s/%s/%s.errlog \n\n' % (self.executionpath,dirname,modelname))
+		fid.write('. /usr/share/modules/init/bash\n\n')
+		fid.write('module load comp-intel/2015.0.090\n')
+		fid.write('module load mpi-sgi/mpt.2.11r13\n')
+		fid.write('export PATH="$PATH:."\n\n')
+		fid.write('export MPI_GROUP_MAX=64\n\n')
+		fid.write('export ISSM_DIR="%s/../"\n' % self.codepath)
+		fid.write('source $ISSM_DIR/etc/environment.sh\n')
+		fid.write('cd %s/%s/\n\n' % (self.executionpath,dirname))
+		fid.write('mpiexec -np %i %s/issm.exe %s %s/%s %s\n' % (self.np,self.codepath,str(EnumToString(solution)[0]),self.executionpath,dirname,modelname))
+		
+		fid.close()
+
+	# }}}
+	def LaunchQueueJob(self,modelname,dirname,filelist):
+		# {{{
+
+		#compress the files into one zip.
+		compressstring='tar -zcf %s.tar.gz ' % dirname
+		for file in filelist:
+			compressstring += ' %s' % file
+		subprocess.call(compressstring,shell=True)
+
+		print 'uploading input file and queueing script'
+		issmscpout(self.name,self.executionpath,self.login,self.port,[dirname+'.tar.gz'])
+
+		print 'launching solution sequence on remote cluster'
+		launchcommand='cd %s && rm -rf ./%s && mkdir %s && cd %s && mv ../%s.tar.gz ./ && tar -zxf %s.tar.gz  && qsub %s.queue' % (self.executionpath,dirname,dirname,dirname,dirname,dirname,modelname)
+		issmssh(self.name,self.login,self.port,launchcommand)
+
+		# }}}
+	def Download(self,dirname,filelist):
+		# {{{
+
+		#copy files from cluster to current directory
+		directory='%s/%s/' % (self.executionpath,dirname)
+		issmscpin(self.name,self.login,self.port,directory,filelist)
+	# }}}
Index: /issm/trunk-jpl/src/m/classes/model.py
===================================================================
--- /issm/trunk-jpl/src/m/classes/model.py	(revision 19156)
+++ /issm/trunk-jpl/src/m/classes/model.py	(revision 19157)
@@ -29,4 +29,6 @@
 from toolkits import toolkits
 from generic import generic
+from pfe import pfe
+from greenplanet import greenplanet
 from balancethickness import balancethickness
 from stressbalance import stressbalance
Index: /issm/trunk-jpl/src/m/consistency/QueueRequirements.py
===================================================================
--- /issm/trunk-jpl/src/m/consistency/QueueRequirements.py	(revision 19157)
+++ /issm/trunk-jpl/src/m/consistency/QueueRequirements.py	(revision 19157)
@@ -0,0 +1,20 @@
+def QueueRequirements(queudict,queue,np,time):
+	#QUEUEREQUIREMENTS - queue requirements in time, number of cpus, by name of queue.
+	#
+	#   Usage: 
+	#      QueueRequirements(available_queues,queue_requirements_time,queue_requirements_np,np,time)
+
+	#Ok, go through requirements for current queue:
+	try:
+		rtime=queudict[queue][0]
+	except KeyError:
+		raise Exception('QueueRequirements error message: availables queues are '+ queuedict.keys)
+		
+	if time<=0:
+		raise Exception('QueueRequirements: time should be a positive number')
+	if time>rtime:
+		raise Exception('QueueRequirements: time should be < '+ str(rtime)+ ' for queue: '+ queue)
+
+	#check on np requirements
+	if np<=0:
+		raise Exception('QueueRequirements: np should be a positive number')
Index: /issm/trunk-jpl/src/m/contrib/netCDF/export_netCDF.py
===================================================================
--- /issm/trunk-jpl/src/m/contrib/netCDF/export_netCDF.py	(revision 19156)
+++ /issm/trunk-jpl/src/m/contrib/netCDF/export_netCDF.py	(revision 19157)
@@ -1,3 +1,3 @@
-from netCDF4 import Dataset
+from netCDF4 import Dataset, stringtochar
 import numpy
 import time
@@ -34,5 +34,6 @@
 	Dimension3=NCData.createDimension('Dimension3',numpy.shape(md.mesh.elements)[1])
 	Dimension4=NCData.createDimension('Dimension4',StepNum)
-	Dimension5=NCData.createDimension('Dimension5',2) 
+	Dimension5=NCData.createDimension('Dimension5',40)
+	Dimension6=NCData.createDimension('Dimension6',2) 
 
 	DimDict = {len(Dimension1):'Dimension1',
@@ -40,5 +41,6 @@
 						 len(Dimension3):'Dimension3',
 						 len(Dimension4):'Dimension4',
-						 len(Dimension5):'Dimension5'}
+						 len(Dimension5):'Dimension5',
+						 len(Dimension6):'Dimension6'}
 
 	#get all model classes and create respective groups
@@ -114,8 +116,11 @@
 	elif val_type==list:
 		dimensions,DimDict=GetDim(NCData,var,val_shape,DimDict,val_dim,istime)
-		ncvar = Group.createVariable(str(field),str,dimensions,zlib=True)
+		ncvar = Group.createVariable(str(field),'S1',dimensions,zlib=True)
+		charvar=stringtochar(numpy.array(var))
+		print charvar
+		print charvar.shape
 		for elt in range(0,val_dim):
 			try:
-				ncvar[elt] = var[elt]
+				ncvar[elt] = charvar[elt]
 			except IndexError:
 				ncvar[0]= " "
@@ -123,5 +128,5 @@
 	elif val_type=='bool':
 		dimensions,DimDict=GetDim(NCData,var,val_shape,DimDict,val_dim,istime)
-		ncvar = Group.createVariable(str(field),str,dimensions,zlib=True)
+		ncvar = Group.createVariable(str(field),'S1',dimensions,zlib=True)
 		for elt in range(0,val_shape[0]):
 			ncvar[elt] = str(var[elt])
@@ -129,5 +134,5 @@
 	elif val_type==collections.OrderedDict:
 		dimensions,DimDict=GetDim(NCData,var,val_shape,DimDict,val_dim,istime)
-		ncvar = Group.createVariable(str(field),str,dimensions,zlib=True)
+		ncvar = Group.createVariable(str(field),'S1',dimensions,zlib=True)
 		for elt in range(0,val_dim):
 			ncvar[elt,0]=dict.keys(var)[elt]
@@ -169,4 +174,10 @@
 def GetDim(NCData,var,shape,DimDict,i,istime):
 	output=[]
+	#grab type
+	try:
+		val_type=str(var.dtype)
+	except AttributeError:
+		val_type=type(var)
+	#grab dimension
 	for dim in range(0,i): #loop on the dimensions
 		if type(shape[0])==int: 
@@ -187,8 +198,21 @@
 				NewDim=NCData.createDimension('Dimension'+str(index),numpy.shape(shape)[0])
 				DimDict[len(NewDim)]='Dimension'+str(index)
-				output=[str(DimDict[numpy.shape(dict.keys(var))[0]])]+['Dimension5']
+				output=[str(DimDict[numpy.shape(dict.keys(var))[0]])]+['Dimension6']
 				print 'Defining dimension ' +'Dimension'+str(index)
 			break
 	if istime:
 		output=output+['Dimension4']
+	#dealing with char and not string as we should so we need to had a string length
+	if val_type=='bool' or val_type==collections.OrderedDict or val_type==list:
+		charvar=stringtochar(numpy.array(var))
+		stringlength=charvar.shape[charvar.ndim-1]
+		try:
+			output=output+[str(DimDict[stringlength])] #test if the dimension allready exist
+		except KeyError: #if not create it
+			if (shape[dim])>1:
+				index=len(DimDict)+1
+				NewDim=NCData.createDimension('Dimension'+str(index),(stringlength))
+				DimDict[len(NewDim)]='Dimension'+str(index)
+				output=output+[str(DimDict[stringlength])]
+				print 'Defining dimension ' +'Dimension'+str(index)
 	return tuple(output), DimDict
Index: /issm/trunk-jpl/src/m/contrib/netCDF/read_netCDF.m
===================================================================
--- /issm/trunk-jpl/src/m/contrib/netCDF/read_netCDF.m	(revision 19156)
+++ /issm/trunk-jpl/src/m/contrib/netCDF/read_netCDF.m	(revision 19157)
@@ -21,5 +21,5 @@
 				subclass = netcdf.getAtt(subgroupIDs(j),netcdf.getConstant('NC_GLOBAL'),'classtype');
 				self.results=setfield(self.results,subclass,struct);
-				[ndims nvar natts]=netcdf.inq(groupIDs(j));
+				[ndims nvar natts]=netcdf.inq(subgroupIDs(j));
 				varIDs=netcdf.inqVarIDs(subgroupIDs(j));
 				%first loop on group atributes
@@ -27,5 +27,5 @@
 					attname = netcdf.inqAttName(subgroupIDs(j),netcdf.getConstant('NC_GLOBAL'),k-1);
 					[xtype,attlen] = netcdf.inqAtt(subgroupIDs(j),netcdf.getConstant('NC_GLOBAL'),attname);
-					%disp(sprintf('In %s, Treating attribute %s of type %i',subclass,attname,xtype));
+					disp(sprintf('In %s, Treating attribute %s of type %i',subclass,attname,xtype));
 					%classtype have done is job, no need to keep it any more
 					if ~strcmp(attname,'classtype'),
@@ -43,5 +43,5 @@
 				for k=1:length(varIDs),
 					[varname, xtype, varDimIDs, varAtts] =netcdf.inqVar(subgroupIDs(j),varIDs(k));
-					%disp(sprintf('In %s, Treating variable %s of type %i',whichclass,varname,xtype));
+					disp(sprintf('In %s, Treating variable %s of type %i',whichclass,varname,xtype));
 					%time dimension seems to be last in our construction
 					for l=1:length(varDimIDs),
@@ -68,5 +68,5 @@
 			varID=netcdf.inqVarIDs(groupIDs(i));
 			[varname, xtype, varDimIDs, varAtts] =netcdf.inqVar(groupIDs(i),varID);
-			%disp(sprintf('In %s, Treating variable %s of type %i',whichclass,varname,xtype));
+			disp(sprintf('In %s, Treating variable %s of type %i',whichclass,varname,xtype));
 			[dimname,numoffields] = netcdf.inqDim(ncid,varDimIDs(end));
 			self.(groupName)=eval(whichclass);
@@ -97,5 +97,5 @@
 				attname = netcdf.inqAttName(groupIDs(i),netcdf.getConstant('NC_GLOBAL'),j-1);
 				[xtype,attlen] = netcdf.inqAtt(groupIDs(i),netcdf.getConstant('NC_GLOBAL'),attname);
-				%disp(sprintf('In %s, Treating attribute %s of type %i',whichclass,attname,xtype));
+				disp(sprintf('In %s, Treating attribute %s of type %i',whichclass,attname,xtype));
 				%classtype have done is job, no need to keep it any more
 				if ~strcmp(attname,'classtype'),
@@ -113,5 +113,5 @@
 			for j=1:length(varIDs),
 				[varname, xtype, varDimIDs, varAtts] =netcdf.inqVar(groupIDs(i),varIDs(j));
-				%disp(sprintf('In %s, Treating variable %s of type %i',whichclass,varname,xtype));			
+				disp(sprintf('In %s, Treating variable %s of type %i',whichclass,varname,xtype));			
 				%if the value is a single string, we need to transpose it (cross check with python file is necessary)
 				if xtype==2
Index: /issm/trunk-jpl/src/m/contrib/paraview/exportVTK.m
===================================================================
--- /issm/trunk-jpl/src/m/contrib/paraview/exportVTK.m	(revision 19156)
+++ /issm/trunk-jpl/src/m/contrib/paraview/exportVTK.m	(revision 19157)
@@ -112,6 +112,5 @@
 			%check which field is a real result and print
 			for k=1:num_of_fields
-				if ((numel(sol_struct{j}(timestep).(fieldnames{k})))== ...
-						num_of_points);
+				if ((numel(sol_struct{j}(timestep).(fieldnames{k})))==num_of_points);
 					%paraview does not like NaN, replacing
 					nanval=find(isnan(sol_struct{j}(timestep).(fieldnames{k})));
Index: /issm/trunk-jpl/src/m/dev/devpath.py
===================================================================
--- /issm/trunk-jpl/src/m/dev/devpath.py	(revision 19156)
+++ /issm/trunk-jpl/src/m/dev/devpath.py	(revision 19157)
@@ -1,11 +1,14 @@
 #!/usr/bin/env python
-
 import os,sys
+import warnings
 
 #Recover ISSM_DIR and USERNAME
-ISSM_DIR=os.getenv('ISSM_DIR')
-USERNAME =os.getenv('USER')
+ISSM_DIR = os.getenv('ISSM_DIR')
+USERNAME = os.getenv('USER')
+JPL_SVN  = os.getenv('JPL_SVN')
 if(ISSM_DIR==None):
 	raise NameError('"ISSM_DIR" environment variable is empty! You should define ISSM_DIR in your .cshrc or .bashrc!')
+if(JPL_SVN==None):
+	warnings.warn('"JPL_SVN" environment variable is empty! add it to your .cshrc or .bashrc if you want to do distant computing')
 
 #Go through src/m and append any directory that contains a *.py file to PATH 
@@ -21,4 +24,10 @@
 sys.path.append(ISSM_DIR + '/lib')
 sys.path.append(ISSM_DIR + '/src/wrappers/python/.libs')
+# If using clusters, we need to have the path to the cluster settings directory
+if(JPL_SVN!=None):
+	if os.path.exists(JPL_SVN + '/usr/' + USERNAME):
+		sys.path.append(JPL_SVN + '/usr/' + USERNAME)
+	else:
+		raise NameError ('cluster settings should be in, '+ JPL_SVN +'/usr/' + USERNAME)
 
 #Manual imports for commonly used functions
Index: /issm/trunk-jpl/src/m/io/structtonc.m
===================================================================
--- /issm/trunk-jpl/src/m/io/structtonc.m	(revision 19156)
+++ /issm/trunk-jpl/src/m/io/structtonc.m	(revision 19157)
@@ -28,5 +28,6 @@
 %Double vector
 elseif isa(field,'double') & size(field,2)==1,
-	if step==1,
+
+if step==1,
 		dim_id          = netcdf.defDim(ncid,[fieldname '_size1'],size(field,1));
 		var_id(counter) = netcdf.defVar(ncid,fieldname,'NC_DOUBLE',dim_id);
Index: /issm/trunk-jpl/src/m/os/issmscpin.py
===================================================================
--- /issm/trunk-jpl/src/m/os/issmscpin.py	(revision 19156)
+++ /issm/trunk-jpl/src/m/os/issmscpin.py	(revision 19157)
@@ -55,16 +55,10 @@
 			#just use standard unix scp
 			#string to copy multiple files using scp: 
-			if len(packages)==1:
-				string=packages[0]
+			string='\{'+','.join([str(x) for x in packages])+'\}'
+			
+			if port:
+				subprocess.call('scp -P %d %s@localhost:%s %s/. ' % (port,login,os.path.join(path,string),os.getcwd()),shell=True)
 			else:
-				string='{'
-				for package in packages:
-					string+=packages[i]+','
-				string=string[:-1]+'}'
-
-			if port:
-				subprocess.call('scp -P %d %s@localhost:%s %s' % (port,login,os.path.join(path,string),os.getcwd),shell=True)
-			else:
-				subprocess.call('scp %s@%s:%s %s' % (login,host,os.path.join(path,string),os.getcwd),shell=True)
+				subprocess.call('scp %s@%s:%s %s/.' % (login,host,os.path.join(path,string),os.getcwd()),shell=True)
 		
 			#check scp worked
Index: /issm/trunk-jpl/src/m/solve/loadresultsfromcluster.py
===================================================================
--- /issm/trunk-jpl/src/m/solve/loadresultsfromcluster.py	(revision 19156)
+++ /issm/trunk-jpl/src/m/solve/loadresultsfromcluster.py	(revision 19157)
@@ -35,27 +35,37 @@
 	#erase the log and output files
 	if md.qmu.isdakota:
-		os.remove(os.path.join('qmu'+str(os.getpid()),md.miscellaneous.name+'.outlog'))
-		os.remove(os.path.join('qmu'+str(os.getpid()),md.miscellaneous.name+'.errlog'))
+		filename=os.path.join('qmu'+str(os.getpid()),md.miscellaneous.name)
 	else:
-		os.remove(md.miscellaneous.name+'.outlog')
-		os.remove(md.miscellaneous.name+'.errlog')
-		os.remove(md.miscellaneous.name+'.outbin')
-		if not m.ispc():
-			os.remove(md.private.runtimename+'.tar.gz')
+		filename=md.miscellaneous.name
 
-	#erase input file if run was carried out on same platform.
+	TryRem('.errlog',filename)
+	TryRem('.outlog',filename)
+	
+	if not m.ispc():
+		TryRem('.tar.gz',md.private.runtimename)
+		if not md.qmu.isdakota:
+			TryRem('.outbin',filename)
+
+			#erase input file if run was carried out on same platform.
 	hostname=socket.gethostname()
 	if m.strcmpi(hostname,cluster.name):
 		if md.qmu.isdakota:
-			os.remove(os.path.join('qmu'+str(os.getpid()),md.miscellaneous.name+'.bin'))
-			os.remove(os.path.join('qmu'+str(os.getpid()),md.miscellaneous.name+'.queue'))
+			filename=os.path.join('qmu'+str(os.getpid()),md.miscellaneous.name)
+			TryRem('.queue',filename)
 		else:
-			os.remove(md.miscellaneous.name+'.bin')
-			os.remove(md.miscellaneous.name+'.toolkits')
+			filename=md.miscellaneous.name
+			TryRem('.toolkits',filename)
 			if not m.ispc():
-				os.remove(md.miscellaneous.name+'.queue')
+				TryRem('.queue',filename)
 			else:
-				os.remove(md.miscellaneous.name+'.bat')
+				TryRem('.bat',filename)
+
+		TryRem('.bin',filename)
 
 	return md
 
+def TryRem(extension,filename):
+	try:	
+		os.remove(filename+extension)
+	except OSError:
+		print 'WARNING, no '+extension+'  is present for run '+filename
