Index: framspy/FramsticksCLI.py
===================================================================
--- framspy/FramsticksCLI.py	(revision 953)
+++ framspy/FramsticksCLI.py	(revision 956)
@@ -2,4 +2,5 @@
 from enum import Enum
 from typing import List
+from itertools import count  # for tracking multiple instances
 import json
 import sys, os
@@ -11,5 +12,5 @@
 	"""Runs Framsticks CLI (command-line) executable and communicates with it using standard input and output.
 	You can perform basic operations like mutation, crossover, and evaluation of genotypes.
-	This way you can perform evolution controlled by python, access and manipulate genotypes.
+	This way you can perform evolution controlled by python as well as access and manipulate genotypes.
 	You can even design and use in evolution your own genetic representation implemented entirely in python.
 
@@ -30,20 +31,23 @@
 	SETEXPEDEF_CMD = "expdef standard-eval" + "\n"
 	GETSIMPLEST_CMD = "getsimplest"
-	GETSIMPLEST_FILE = FILE_PREFIX + "simplest.gen"
-	EVALUATE_CMD = "evaluate eval-allcriteria.sim "
+	GETSIMPLEST_FILE = "simplest.gen"
+	EVALUATE_CMD = "evaluate eval-allcriteria.sim"
 	EVALUATE_FILE = "genos_eval.json"
 	CROSSOVER_CMD = "crossover"
-	CROSSOVER_FILE = FILE_PREFIX + "child.gen"
+	CROSSOVER_FILE = "child.gen"
 	DISSIMIL_CMD = "dissimil"
-	DISSIMIL_FILE = FILE_PREFIX + "dissimilarity_matrix.gen"
+	DISSIMIL_FILE = "dissimilarity_matrix.gen"
 	ISVALID_CMD = "isvalid"
-	ISVALID_FILE = FILE_PREFIX + "validity.gen"
+	ISVALID_FILE = "validity.gen"
 	MUTATE_CMD = "mutate"
-	MUTATE_FILE = FILE_PREFIX + "mutant.gen"
-
-	CLI_INPUT_FILE = FILE_PREFIX + "genotypes.gen"
+	MUTATE_FILE = "mutant.gen"
+
+	CLI_INPUT_FILE = "genotypes.gen"
+
+	_last_instance_id = count(0)  # "static" counter incremented when a new instance is created. Used for unique filenames
 
 
 	def __init__(self, framspath, framsexe):
+		self.id = next(FramsticksCLI._last_instance_id)
 		self.frams_path = framspath
 		self.frams_exe = framsexe if framsexe is not None else 'frams.exe' if os.name == "nt" else 'frams.linux'
@@ -89,8 +93,8 @@
 		print('OK.')
 		print('Performing a basic test 2/3... ', end='')
-		assert self.isValid("X[0:0]") == True
+		assert self.isValid("X[0:0]") is True
 		print('OK.')
 		print('Performing a basic test 3/3... ', end='')
-		assert self.isValid("X[0:0],") == False
+		assert self.isValid("X[0:0],") is False
 		print('OK.')
 		if not self.DETERMINISTIC:
@@ -105,26 +109,25 @@
 
 
-	def __saveGenotypeToFile(self, genotype, name, mode):
-		outpath = os.path.join(self.writing_path, name)
-		outfile = open(outpath, mode)
-		outfile.write("org:\n")
-		outfile.write("genotype:~\n")
-		outfile.write(genotype + "~\n\n")  # TODO proper quoting of special characters in genotype...
-		outfile.close()
-		return name
-
-
-	def __saveToFile(self, genotype, name, mode):
-		outpath = os.path.join(self.writing_path, name)
-		outfile = open(outpath, mode)
-		outfile.write(genotype)
-		outfile.close()
-		return name
-
-
-	def __removeFile(self, path):
-		filepath = os.path.join(self.writing_path, path)
-		if os.path.exists(filepath):
-			os.remove(filepath)
+	def __getPrefixedFilename(self, filename: str) -> str:
+		# Returns filename with unique instance id appended so there is no clash when many instances of this class use the same Framsticks CLI executable
+		return FramsticksCLI.FILE_PREFIX + str(chr(ord('A') + self.id)) + '_' + filename
+
+
+	def __saveGenotypeToFile(self, genotype, name, mode, saveformat):
+		relname = self.__getPrefixedFilename(name)
+		absname = os.path.join(self.writing_path, relname)
+		if mode == 'd':  # special mode, 'delete'
+			if os.path.exists(absname):
+				os.remove(absname)
+		else:
+			outfile = open(absname, mode)
+			if saveformat == self.GENO_SAVE_FILE_FORMAT["RAWGENO"]:
+				outfile.write(genotype)
+			else:
+				outfile.write("org:\n")
+				outfile.write("genotype:~\n")
+				outfile.write(genotype + "~\n\n")  # TODO proper quoting of special characters in genotype...
+			outfile.close()
+		return relname, absname
 
 
@@ -140,30 +143,32 @@
 
 	def __runCommand(self, command, genotypes, result_file_name, saveformat) -> List[str]:
-		filenames = []  # list of file names with input data for the command
+		filenames_rel = []  # list of file names with input data for the command
+		filenames_abs = []  # same list but absolute paths actually used
 		if saveformat == self.GENO_SAVE_FILE_FORMAT["RAWGENO"]:
 			for i in range(len(genotypes)):
-				filenames.append(self.__saveToFile(genotypes[i], "genotype" + str(i) + ".gen", "w"))  # plain text format = must have a separate file for each genotype
+				# plain text format = must have a separate file for each genotype
+				rel, abs = self.__saveGenotypeToFile(genotypes[i], "genotype" + str(i) + ".gen", "w", self.GENO_SAVE_FILE_FORMAT["RAWGENO"])
+				filenames_rel.append(rel)
+				filenames_abs.append(abs)
 		elif saveformat == self.GENO_SAVE_FILE_FORMAT["NATIVEFRAMS"]:
-			self.__removeFile(self.CLI_INPUT_FILE)  # ensure there is nothing left from the last run of the program because we "a"ppend to file in the loop below
+			self.__saveGenotypeToFile(None, self.CLI_INPUT_FILE, 'd', None)  # 'd'elete: ensure there is nothing left from the last run of the program because we "a"ppend to file in the loop below
 			for i in range(len(genotypes)):
-				outfilename = self.__saveGenotypeToFile(genotypes[i], self.CLI_INPUT_FILE, "a")
-			filenames.append(outfilename)  # since we use the same file in the loop above, add this file only once (i.e., outside of the loop)
-
-		if result_file_name != self.EVALUATE_FILE:  # all functions except for evaluate provide frams with the file name to write to
-			self.child.sendline(command + " " + " ".join(filenames) + " " + result_file_name + "\n")
-		else:
-			self.child.sendline(command + " " + " ".join(filenames) + "\n")
+				rel, abs = self.__saveGenotypeToFile(genotypes[i], self.CLI_INPUT_FILE, "a", self.GENO_SAVE_FILE_FORMAT["NATIVEFRAMS"])
+			#  since we use the same file in the loop above, add this file only once (i.e., outside of the loop)
+			filenames_rel.append(rel)
+			filenames_abs.append(abs)
+
+		result_file_name = self.__getPrefixedFilename(result_file_name)
+		cmd = command + " " + " ".join(filenames_rel) + " " + result_file_name
+		self.child.sendline(cmd + '\n')
 		self.__readFromFramsCLIUntil(self.STDOUT_ENDOPER_MARKER)
-		filenames.append(os.path.join(self.writing_path, self.OUTPUT_DIR, result_file_name))
-		return filenames  # last element is a path to the file containing results
-
-
-	def __cleanUpCommandResults(self, filepaths):
-		"""Deletes files with results created by the command."""
-		for i in filepaths:
-			if i == filepaths[-1]:
-				os.remove(i)  # the result is written with its full path and we have used it before so the file surely exists
-			else:
-				self.__removeFile(i)
+		filenames_abs.append(os.path.join(self.writing_path, self.OUTPUT_DIR, result_file_name))
+		return filenames_abs  # last element is a path to the file containing results
+
+
+	def __cleanUpCommandResults(self, filenames):
+		"""Deletes files with results just created by the command."""
+		for name in filenames:
+			os.remove(name)
 
 
@@ -237,5 +242,5 @@
 	parser.add_argument('-path', type=ensureDir, required=True, help='Path to Framsticks CLI without trailing slash.')
 	parser.add_argument('-exe', required=False, help='Executable name. If not given, "frams.exe" or "frams.linux" is assumed.')
-	parser.add_argument('-genformat', required=False, help='Genetic format for the demo run, for example 4, 9, or B. If not given, f1 is assumed.')
+	parser.add_argument('-genformat', required=False, help='Genetic format for the demo run, for example 4, 9, or S. If not given, f1 is assumed.')
 	return parser.parse_args()
 
