#!/usr/bin/perl
use strict;
use warnings;

#(c) Christian Troost, Universität Hohenheim, 2009-2026



#use DBI;
use POSIX;
use lib qw(/usr/local/lib/mpmasql/modules);
use File::Path;
use List::Util qw[min max];
use Storable qw/dclone/;
use Data::Dumper;
use Term::ReadKey;
#use Parallel::Iterator;


#Own Classes
use CtUtilities qw(trim get_unique queryhash extqueryhash strip_sql nice_hash_dump stamp_time);
use IndexedTable;
use SimpleObjectRegistry;
#use MpmasQLConfigReader qw(ReadCfg ReadCll ReadIni ReadVar);
#use MpmasQLVariableProcessing qw(define_scenarios adapt_for_scenario);
#use MpmasQLFunctionLanguage;
#use MpmasQLClassDefinition;
#MP-MAS Input File Classes
use MpmasInputfile;
use MpmasInputfileSet;
use MpmasBData;
use MpmasSpatialExchangeInfo;
use MpmasTimehandler;
use MpmasMarketSet;
use MpmasMarket;
use MpmasMILPSet;
#use MpmasMILP;
use MpmasMILPMultiperiod;
use MpmasClusterSet;
use MpmasDemographySet;
use MpmasNetworkSet;
use MpmasSegmentSet;
use MpmasCropExt;
use MpmasCropExtLinkXN;
use MpmasCropDbgActivityID;
use MpmasCropDbgYield;
use MpmasCropYieldsSet;
use MpmasCropSimilarity;
use MpmasRegion;
use MpmasPerennial;
use MpmasLivestock;
use MpmasCropWat;
use MpmasCropWatPrecipitation;
use MpmasCropWatEvapotranspiration;
use MpmasEDICRiverFlows;
use MpmasEDICRiverFlowTimeSeries;
use MpmasEDICIrrigation;
use MpmasEDICSurface;
use MpmasEDICSubsurface;
use MpmasActualWaterRights;
use MpmasInfrastructureProjects;
use MpmasEDICCanalModel;
use MpmasRentalContracts;
#use MpmasProducerOrganizationSet;
#use MpmasProducerOrganizationMILPSet;
use MpmasSoilToNRU;
use MpmasLandMarket;
use MpmasInvestmentsAttachedToLand;
use MpmasLivSimCouplingInfo;
use MpmasEUCAP2003;
use MpmasExternalScriptCalls;
use MpmasCharacteristicsInfo;
use MpmasCropCharacteristicsInfo;
use MpmasAgentExpectationParameters;
use MpmasCommonProperty;
use MpmasInitialAgentCharacteristics;
use MpmasSimulationRunParameterListExtra;

#auxiliary File classes
use MpmasActivityInfo;
use MpmasActivityInfoEdicMatlab;
use MpmasConstraintInfo;
use MpmasConstraintInfoEdicMatlab;
use MpmasNetworkObjectInfo;
use MpmasStataLabelsU;
use MpmasStataLabelsK;
use MpmasStataLabelsP;
use MpmasStataGroups;
use MpmasStataImport;
use MpmasRImport;
use MpmasQLConstraintAnalysis;
use MpmasSimulationRunParameterScens;
#use MpmasSimulationRunParameterListDefaults;
use MpmasSimulationRunParameterScenList;




use MpmasQlEqnTranslatorMarpa;
use MpmasQLRegistry;

IndexedTable->set_useCacheWorkbooks(2);



#$Carp::Verbose = 0;

=head1 mpmasql

mpmasql Perl script to create MPMAS input files (ASCII) from SQL databases and configuration files


=cut

##Version:

my $thisversion = "4.1.32";
my $lastchange = "1 Jul 2026";


my $starttime = time;

my $longwelcome = <<WC;

	Model building toolbox for MPMAS 
	Version: $thisversion, last change: $lastchange
	(c) Troost, C., Univ. Hohenheim, 2009-2026
	
	
WC

my $shortwelcome = <<WC2;
	mpmasql v$thisversion		
WC2

#Declarations and hard-coded defaults initializations
my $ininame;
my $singlemode = 0; my $newsinglemode = 1;
my $docmode = 0;
my $singlefiles = 0;
my $octave = 0;
my $selgroup = "crop";
my $mpmasoff = 0;
my $tableau_compact = 0;
my $outdir = "testoutput/"; #global for the output directory
my $perennials = 0;
my $outdir_override = 0;
my %verbosityflag;
my %additionaloutput;
$additionaloutput{"NO_COMMENTED"} = 1;

my $backwards;
my $runonly = 0;
my %setstrings;
my %dbgParameters;
my $dumpTables = 0;

my $parallelElems = 0;
my $parallelTabs = 0;
my $parallelInst = 0;
my $parallelInstThreshold = 1000;

my $strictlySorted = 1;
my $runModel = 0;
my $OSfiles = $^O ;
my $testformat = 0;

my @scens_only;
my @prefixed_scens_only;

MpmasMILPConstraint->be_lazy();
MpmasMILPActivity->be_lazy();


STDOUT->autoflush(1);
print $shortwelcome;


#Parse commandline arguments
while (@ARGV) {
	my $element = shift @ARGV;
	if  ($element =~ /^-v$/) {
		print $longwelcome;
		exit 0;
	}
	elsif  ($element =~ s/^-S//) {
		#set conversion modus to Single Matrix Mode
		$singlemode = 1;
		$singlefiles = 1;
		unshift @ARGV, "-".$element if (defined $element and not $element =~/^\s*$/);
	}
	elsif  ($element =~ s/^--latex//) {
		#set conversion modus to Latex files
		$docmode = 1;
		unshift @ARGV, "-".$element if (defined $element and not $element =~/^\s*$/);
	}
	elsif  ($element =~ /^--octave/) {
		#create single matrix for use with octave
		$octave = 1;
		$singlemode = 1; 
		$selgroup = shift @ARGV if (not $ARGV[0] =~ /^-/);
	}
	elsif ($element =~ /^-O/) {
		# alternative output directory
		$outdir_override = 1;
		my $od;
		$od = shift @ARGV if (not $ARGV[0] =~ /^-/);
		$outdir = $od || ".";
		print "Output directory in control file overridden by commandline argument...\n";
	}
	elsif ($element =~ /^--temp-dir/) {
	    my $td;
		$td = shift @ARGV if (not $ARGV[0] =~ /^-/);
		print "Default temp directory overridden by commandline argument...\n";
	    MpmasInputBlockImmediate->set_tempfilepath_base($td);
	}
	elsif ($element =~ /^-R/) {
		my $od;
		srand( shift( @ARGV)) if ($ARGV[0] =~ /^\s*\d+\s*/);
		
	}
	elsif ($element =~ /^--win/) { #force Windows formats for outputs, even if on Linux
		$OSfiles = "MSWin32";	
	}
	elsif ($element =~ /^--linux/) { #force Linux formats for outputs, even if on Windows
		$OSfiles = "linux";
	}
	elsif  ($element =~ /^--nomas$/ or $element =~ /^-n/) {
		#verbosity 1
		$mpmasoff = 1;
		print "MPMAS specific checking of MILP switched off!\n";
		unshift @ARGV, "-".$element if (defined $element and not $element =~/^\s*$/);

	}
#	elsif  ($element =~ s/^--compact$// or $element =~ s/^-c//) {
#		#verbosity 1
#		$tableau_compact = 1;
#		print "Use compact format for decision matrix\n";
#		unshift @ARGV, "-".$element if (defined $element and not $element =~/^\s*$/);
#	}
	elsif  ($element =~ /^--fast$/) {
		$strictlySorted = 0;
	}
	elsif  ($element =~ /^--lowmem$/) {
		MpmasMILPConstraint->be_lazy();
		MpmasMILPActivity->be_lazy();
	}
	elsif  ($element =~ /^--oldmem$/) {
		MpmasMILPConstraint->dont_be_lazy();
		MpmasMILPActivity->dont_be_lazy();
	}
	elsif  ($element =~ /^--run$/) {
	
		$runModel = 1;
	}
	elsif  ($element =~ /^--run-and-wait$/) {
	
		$runModel = 2;
	}
	elsif  ($element =~ /^--prefixed-scens$/) {
		if (not $ARGV[0] =~ /^-/ ) {
		    my $string = shift @ARGV;
		    @prefixed_scens_only = split /\s*,\s*/, $string;
		}
	}
	elsif  ($element =~ /^--scens$/) {
		if (not $ARGV[0] =~ /^-/ ) {
		    my $string = shift @ARGV;
		    @scens_only = split /\s*,\s*/, $string;
		}
	}
	
	elsif  ($element =~ /^--runonly$/ or $element =~ /^-r/) {
		#verbosity 1
		$runonly = 1;
		print "Only create run scripts\n";
	}
	elsif  ($element =~ /^-l(\d+)$/) {
		
		#verbosity flags
		my %temp = (
			1 => "VERBOSE_READINI" ,
			2 => "VERBOSE_READCFG",
			3 => "VERBOSE_READDATA",
			10 => "VERBOSE_READMAS",
			4 => "VERBOSE_SCEN",
			5 => "VERBOSE_BIND",
			6 => "VERBOSE_CLASS",
			7 => "VERBOSE_INTERPRETE",
			8 => "VERBOSE_SORT" ,
			9 => "VERBOSE_FILES",
			11 => "LIST_ACTIVITIES",
			);
		my $flag = $temp{$1};
		$verbosityflag{$flag} = 1;
	}
	elsif  ($element =~ /^--nocomment$/ or $element =~ s/^-x//) {
	      $additionaloutput{"NO_COMMENTED"} = 1;
	      #unshift @ARGV, "-".$element if (defined $element and not $element =~/^\s*$/);
	}
	elsif  ($element =~ /^--comment$/) {
	      $additionaloutput{"NO_COMMENTED"} = 0;
          #unshift @ARGV, "-".$element if (defined $element and not $element =~/^\s*$/);
	}
	elsif  ($element =~ /^-a(\d+)$/) {
		my %temp = (
			0 => "NO_COMMENTED",
			1 => "ADD_CONANALYSIS",
			2 => "ADD_EDICMATLAB");
		my $flag = $temp{$1};
		$additionaloutput{$flag} = 1;
	}	
	elsif  ($element =~ /^--bw(\d+)$/) {
		$backwards = $1;

	}
	elsif ($element =~ /^--set/ ) {
		if (not $ARGV[0] =~ /^-/ ) {
		    my $setstring = shift @ARGV;
		    my ($var, $val) = split /=/,$setstring,2;
		    $var =~ s/^\s*//;
		    $val =~ s/^\s*//;
		    $var =~ s/\s*$//;
		    $val =~ s/\s*$//;

		    $setstrings{$var} = $val;
		}
	}
	elsif ($element =~ /^--test-format/ ) {
		$testformat = 1;
	}
	elsif ($element =~ /^--debug/ ) {
		if (not $ARGV[0] =~ /^-/ ) {
		    my $name = shift @ARGV;
		    $dbgParameters{$name} = 1;
		}
	}
	elsif ($element =~ /^--no-spreadsheet-cache$/) {
		IndexedTable->set_useCacheWorkbooks(0);
	}
	elsif ($element =~ /^--short-spreadsheet-cache$/) {
		IndexedTable->set_useCacheWorkbooks(1);
	}
	elsif ($element =~ /^--log-time$/) {
		MpmasQlEqnTranslatorMarpa->set_logTime(1);
	}
##	elsif ($element =~ /^--parallel-mpm/ || $element =~ /^-p/ ) {
##		if (not $ARGV[0] =~ /^-/ ) {
##		    $parallelElems = shift @ARGV;
##		}
#	}
#	elsif ($element =~ /^--parallel-mpm2/ || $element =~ /^-P/ ) {
#		if (not $ARGV[0] =~ /^-/ ) {
#		    $parallelInst = shift @ARGV;
#		}
#	}
#	elsif ($element =~ /^--parallel-mpm2-threshold/ || $element =~ /^-T/ ) {
#		if (not $ARGV[0] =~ /^-/ ) {
#		    $parallelInstThreshold = shift @ARGV;
#		}
#	}	
	
	
#	elsif ($element =~ /^--parallel-tabs/ || $element =~ /^-q/ ) {
#		if (not $ARGV[0] =~ /^-/ ) {
#		    $parallelTabs = shift @ARGV;
#		}
#	}
	elsif ($element =~ /^--dump-tables/ ) {
			$dumpTables = 1;
	}
	elsif (not $element =~ /^-/) {
		# inifile name
		$ininame = $element;
		print "\nConversion control file:\t\t". $ininame."\n";  
	}
	elsif ($element =~ /^-h/ or $element =~ /^--help/ or $element =~ /^-\?/) {
		print <<HELP;
		
Usage:
	mpmasql <filename> [options]
	
	<filename>	name of the conversion control file .ini or pure .mpm file to be processed

Options:
	-S		single/standalone matrix mode

	--comment	write commented output files
	-O <directory>	override output directory set in .ini file (for both uncommented and commented files)
	-r, --runonly	create only run script (and parameter variation scenarios if applicable)
	--run		create input files and directly run model
	--run-and-wait	create input files and directly run model (and return to calling script afterwards)
	--test-format   run with output suitable for test_mpmas
		
	--set "<variable>=<value>"	change value of .ini file entry
	
	--debug <variable> 	print to screen content of table, set, parameter after conversion
	--dump-tables	dump all data tables to tab-separated ASCII files
		
	-v		print version information
	-h, --help, -?	print this help
	
	
	--log-time	print timings for processing of individual model elements
	--no-spreadsheet-cache	do not cache opened spreadsheet files in memory (try if running into memory issues)
	--short-spreadsheet-cache	only shortly opened spreadsheet files in memory (try if running into memory issues)
					[will be cached only as long as several sheets will be read from a file directly after one another]

HELP
#	-p <n>, --parallel-mpm <n>  parallelize MIP template generation using <n> processors
#	-q <n>, --parallel-tabs <n>  parallelize table retrieval using <n> processors (exper#mental)
#	-n, --nomas	do not check for compatibility with MPMAS format


		exit (0);
	}
	else {
		print STDERR "Error: Unknown commandline argument $element\nCall with flag --help for usage information\n" ;
		exit(1);
	}
}

#	Verbosity flags:
	#-l1		show conversion control settings
	#-l2		show model configuration 
	#-l3		verbose when reading model data file
	#-l4		verbose when processing scenario adaptations
	#-l5		verbose when binding variables and tables
	#-l6		verbose when preparing model elements
	#-l7		verbose when parsing field and value definitions
	#-l8		verbose when sorting matrix elements
	#-l9		verbose when creating input files


print "Verbosity flag $_\n" foreach keys %verbosityflag;

#Give error message if no input file was specified
print STDERR "You forgot to specify a conversion control file (.ini)\n" and exit(1) unless $ininame;


use constant logMem => 0;

#if ($logMem) {
	#use Devel::SizeMe qw(perl_size heap_size size total_size);
	#use Devel::Cycle;
	
require Memory::Usage if logMem;
my $mu;
$mu = Memory::Usage->new() if logMem;
#}



if ($docmode) {
	my $docCreator = MpmasQlEqnTranslatorMarpa->new_doc($ininame, \%setstrings, \%verbosityflag);
	my $filename = $ininame;
	$filename =~ s/.ini/.tex/;
	$docCreator->make_doc($filename);
	exit(0);
}

if ($parallelTabs || $parallelElems || $parallelInst){
	require Parallel::Iterator;

	if ($parallelTabs) {	
		print "Info: Using $parallelTabs parallel processors for table retrieval\n";

	}
	if ($parallelElems) {
		MpmasQLModelElementAbstract->set_coeffWithConstraints();
		print "Info: Using $parallelElems parallel processors for MIP generation (template level)\n";
	}
	if ($parallelInst) {
		MpmasQLModelElementAbstract->set_coeffWithConstraints();
		print "Info: Using $parallelInst parallel processors for MIP generation (instance level)\n";
	}
}
MpmasQLModelElementAbstract->set_coeffWithConstraints();


MpmasInputfile->skip_comments() if ($additionaloutput{"NO_COMMENTED"} );
MpmasInputfile->set_strict_sorting($strictlySorted);


$mu->record('before new_model') if logMem;

######## Read Ini-File
#my $inihash = ReadIni($ininame);
my $modelCreator = MpmasQlEqnTranslatorMarpa->new_model($ininame, \%setstrings, \%verbosityflag, $singlemode);
my $inihash = $modelCreator->inihash();

if (exists $inihash->{STANDALONE} and $inihash->{STANDALONE} > 0)
{
		$singlemode = 1;
		$singlefiles = 1;
}

my $outdir_cm;
if ($outdir_override) {
	$outdir_cm = $outdir;
}
elsif ($singlemode) {
	$outdir =  $inihash->{OUTDIR} if (exists $inihash->{OUTDIR});
	$outdir =  $inihash->{OUTDIR_S} if (exists $inihash->{OUTDIR_S});   
	$outdir_cm = $inihash->{OUTDIR_S_CM} || $outdir;
}
else {
	$outdir =  $inihash->{OUTDIR} if (exists $inihash->{OUTDIR});   
	$outdir_cm = $inihash->{OUTDIR_CM} || $outdir;
}
#

#create the output path if non-existent
&mkpath ($outdir); 
&mkpath ($outdir_cm); 

my $skipping = 0;
#$skipping = 1  if exists $inihash->{SKIP} and $inihash->{SKIP};

my %skiplist;
#if ($skipping > 0) {
	#for my $i (@{$inihash->{SKIP}}) {
	#	my $h = lc($i);
	#	$skiplist{$h} = 1;
	#	print "Skipping $h -> $skiplist{$h}\n";
	#}
#}

#print "\nModel configuration file:\t\t". $inihash->{CONFIGURATION}."\n";
#print "Model data file:\t\t\t". $inihash->{DATA}."\n";
#print "Decision model parameter file:\t\t". $inihash->{DECISION_PARAMETERS}."\n";
#print "Decision model file:\t\t\t". $inihash->{DECISION_MODEL}."\n";
#print "Mpmas parameters file:\t\t\t". $inihash->{MAS_PARAMETERS}."\n";

print "\nMPMAS input files (.dat) will be written to directory:\n\t\t". $outdir."\n";
print "Commented input files (.txt) will be written to directory:\n\t\t". $outdir_cm."\n" unless ($additionaloutput{"NO_COMMENTED"});

$mu->record('before scenario tables') if logMem;

#### Connect to Database
my $dbh;
ReadMode(0);
if (defined  $inihash->{DBTYPE} and defined $inihash->{DB}) {
	require 'DBI.pm';
	
	if (not $inihash->{DBPWD}) {
		print "Password: ";
		ReadMode 2;	
		 $inihash->{DBPWD} = ReadLine (0);
		print "\n";
		ReadMode 1;
	}
	chomp( $inihash->{DBPWD});
	$dbh = DBI->connect("dbi:".$inihash->{DBTYPE}.":". $inihash->{DB}, $inihash->{DBUSER}, $inihash->{DBPWD}, { RaiseError => 1, AutoCommit => 1, mysql_auto_reconnect => 1 }) or die $!;
	print "Successfully connected to " . $inihash->{DB} . " as ". $inihash->{DBUSER} . "\n"; 
	$dbh->do("SET NAMES utf8");
}
{ 
my $prefix = $inihash->{PREFIX};

	push @scens_only, map { my $x = $_; $x =~ s/^$prefix//;$x   } @prefixed_scens_only
}
print join (";", @scens_only),"\n";

my ($uscenlist, $scendef, $scencommon) = $modelCreator->transform_scenario_tables($dbh, \@scens_only, $inihash->{ONLY_DEFINED_SCENARIOS});

my @scenlist = sort { $a cmp $b} @$uscenlist;
my %paramscenlistCollector;
my %paramscen_filename;


my ($baserhsdef, $rhslist, $collected_rhshash);
if ($singlemode && ! $newsinglemode) {
    if (defined $modelCreator->{INITABLEDEFS}->{RHSDEF} and $modelCreator->{INITABLEDEFS}->{RHSDEF}->type =~ /^\s*transform_assets/) {
	($rhslist, $baserhsdef) = $modelCreator->transform_rhs_tables($dbh);
		$baserhsdef = "-99";
    }
    else {
	($rhslist, $baserhsdef) = $modelCreator->transform_rhs_tables($dbh);
    }
}
elsif ( $singlemode &&  $newsinglemode) {
    if (defined ($modelCreator->{INITABLEDEFS}->{RHSDEF}) or defined($modelCreator->{INITABLEDEFS}->{RHSLIST})) {
		print STDERR "RHSDEF/RHSLIST is not supported any more in mpmasql4 version >= 4.1\n";
		exit(1);
	}
}


my $scenflags = {};
my @ConstraintGroupingsForAllScenarios;
my @ActivityGroupingsForAllScenarios;
my $maxperiods = 1;
my ($fh, $frh);
my $Nsimrunparams = 0;
####LOOP OVER SCENARIOS 



$mu->record('starting scenario loop') if logMem;

SCENARIOLOOP: for my $curScen (  @scenlist){
	MpmasInputfile->setMemUsageObj($mu) if logMem;
	print "\e[K\n>> Preparing Scenario $curScen...\n\n";
	
	
		stamp_time($starttime, $curScen) if logMem;
		$mu->record("starting $curScen") if logMem;

		#print "heap size/ perl size: ", heap_size(),", ", perl_size(),"\n";
		#print "modelCreator: ", size($modelCreator),", ", total_size($modelCreator),"\n";
		#print "scenflags: ", size($scenflags),", ", total_size($scenflags),"\n";

		#print "ConstraintGroupingsForAllScenarios: ", size(\@ConstraintGroupingsForAllScenarios),", ", total_size(\@ConstraintGroupingsForAllScenarios),"\n";
		#print "ActivityGroupingsForAllScenarios: ", size(\@ActivityGroupingsForAllScenarios),", ", total_size(\@ActivityGroupingsForAllScenarios),"\n";
	
	### reset counters
	MpmasNetworkObject->reset_existing_onames();
	
	
	$modelCreator->create_globals_and_configs($curScen, $dbh, $mpmasoff, $verbosityflag{VERBOSE_READMAS} || $verbosityflag{VERBOSE_READCFG}, $parallelTabs);

	$mu->record('after globals, configs, tables') if logMem;
	stamp_time($starttime, 'after globals, configs, tables') if logMem;

	print Dumper( $modelCreator->{GLOBALS})if ($verbosityflag{VERBOSE_READDATA});
	print Dumper( $modelCreator->{GLOBAL_SETS})if ($verbosityflag{VERBOSE_READDATA});
	print Dumper( $modelCreator->{CONFIG}) if ($verbosityflag{VERBOSE_READCFG});
	print Dumper( $modelCreator->{TABLES}) if ($verbosityflag{VERBOSE_READDATA});
	print Dumper( $modelCreator->{SIMRUN_PARAMETERS}) if ($verbosityflag{VERBOSE_READDATA});

	print Dumper( $modelCreator->{MPMAS_TABLES}) if ($verbosityflag{VERBOSE_READMAS});
	
	my $configs = Hash::Merge::merge($modelCreator->{CONFIG}, $modelCreator->{MPMAS_TABLES});
	my $mname = "$inihash->{PREFIX}"."$curScen";
	my $rhsdef = $baserhsdef; #for now!!!!

	### Bind all variables in CFG and VAR entries with scenario specific settings
	
	unless ($runonly) {
	      my @milplist;
	      my @landownermilptypes = (1);
	      push @landownermilptypes, 2 if ($configs->{LANDMARKET_MODEL} == 2);
	      for my $t (@landownermilptypes) {
			  for my $m (0..$configs->{MARKETS} -1) {
				  push @milplist, sprintf("%01d%01d" , $t , $m);
			  }
	      }
	      MpmasInputfile->set_milplist(\@milplist);

	      ### Declare Registries for Model Objects - obsolete, replace later
	     
	      my $PerennialObjectRegistry = SimpleObjectRegistry->create();
	      my $LivestockObjectRegistry = SimpleObjectRegistry->create();	
	      my $TPPenaltyObjectRegistry = SimpleObjectRegistry->create();	
	      my $SOSRegistry = SimpleObjectRegistry->create();

	      ### Create default values for class elements

	     MpmasNetworkObject->set_default_value(	"eqshare", 	$modelCreator->config_entry("EQSHARE") );
	     MpmasNetworkObject->set_default_value(	"irate", 	$modelCreator->config_entry("INTEREST_LGCRD") );

		##Output values requested with --debug flag to screen
		for my $vn (keys %dbgParameters) {
			    #Note:: Sets and parameters are reported directly after creating them
			    my $v = $modelCreator->{TABLES}->get_object_by_id($vn);
	      		if ( defined $v ) {				
					print "$vn:".$v->printme_with_header_sorted();
					print "\n";
				}
				 
	      		if ( exists $modelCreator->{MPMAS_TABLES}->{$vn} ) {	
					print "Error: $vn empty\n" and exit(1) if (not defined $modelCreator->{MPMAS_TABLES}->{$vn} );			
					print "$vn:".$modelCreator->{MPMAS_TABLES}->{$vn}->printme_with_header_sorted();
					print "\n";
				} 
	      		if ( exists $modelCreator->{GLOBALS}->{$vn}) {				
					print "$vn: ", $modelCreator->{GLOBALS}->{$vn};
					print "\n";
				}
				if ( exists $modelCreator->{GLOBAL_SETS}->{$vn}) {				
					print "$vn: ", join(", ", @{$modelCreator->{GLOBAL_SETS}->{$vn}});
					print "\n";
				}
				if (exists $modelCreator->{SIMRUN_PARAMETERS}->{$vn}) {				
					print "$vn: ", $modelCreator->{SIMRUN_PARAMETERS}->{$vn};
					print "\n";
				}
	      }



	      ###Create decision model elements     
	      #   Prepare database for conversion
	      #Create parameters and sets
	      $modelCreator->create_sets_and_parameters2(\%dbgParameters);
	      
	      
	      		#print "heap size/ perl size before model elements: ", heap_size(),", ", perl_size(),"\n";
	      $mu->record('after sets and parameters') if logMem;
		  stamp_time($starttime, 'after sets and parameters') if logMem;

	      
	      #   Run through ASTs and create assets, activities and constraints
	      my ($NetworkObjectRegistry, $ActivityRegistry, $ConstraintRegistry, $MultiperiodInserterRegistry, $MultiperiodReaderRegistry) = $modelCreator->create_model_elements2(\@milplist, $verbosityflag{"LIST_ACTIVITIES"}, $parallelElems, $parallelInst, $parallelInstThreshold);
		  
	      		#print "heap size/ perl size after model elements: ", heap_size(),", ", perl_size(),"\n";
	      stamp_time($starttime, "after model elements") if logMem;;
	      $mu->record('after model elements') if logMem;
	      
		  #Output results to screen for debugging as requested
	      for my $vn (keys %dbgParameters) {
		    #Note:: Sets and parameters are reported directly after creating them
	  	    my $v = $modelCreator->{ASSETS}->get_object_by_id($vn);
	      	    if ( defined $v ) {				
					print "$vn:".Dumper($v);
					print "\n";
		    }
	      }

  		#Output all tables to ascii files if requested
	        if ($dumpTables) {
		    my $taboutFH;
		    my $dumpedtablepath = $outdir."dumped_tables/";
		    &mkpath ($dumpedtablepath);
		    for my $t ($modelCreator->{TABLES}->object_list() ) {
					my $fname =$dumpedtablepath.$inihash->{PREFIX}.$curScen."_". $t->id() .".tab";
					open( $taboutFH ,">", $fname) or (print(STDERR "Error: $fname could not be created\n") and exit 1);
					$t->printme_with_header_sorted_to_fh($taboutFH);
					close($taboutFH);
	            }
	            for my $tn ( keys %MpmasQLRegistry::mpmas_tables ) {
					if (exists $configs->{$tn}) {
						my $t = $configs->{$tn};
						my $fname =$dumpedtablepath.$inihash->{PREFIX}.$curScen."_". $t->id() .".tab";
						open( $taboutFH ,">", $fname) or (print(STDERR "Error: $fname could not be created\n") and exit 1);
						$t->printme_with_header_sorted_to_fh($taboutFH);
						close($taboutFH);
					}
		    }
	     }
	      	

	      
   	      MpmasInputfile->set_global_references($mname, $outdir, $outdir_cm, $inihash, $configs, $modelCreator, $ActivityRegistry, 
						$ConstraintRegistry, $NetworkObjectRegistry,$PerennialObjectRegistry,$LivestockObjectRegistry,$TPPenaltyObjectRegistry,
						$SOSRegistry,$dbh, $backwards, $tableau_compact, $mu, $starttime, $MultiperiodInserterRegistry, $MultiperiodReaderRegistry, $modelCreator->{SIMRUN_PARAMETERS});	#Note: Other globals are set by the prepare_shared methods of InputFiles, especially by MpmasMILPfile

	       #Output specific tables as extra input for coupled scripts or R shiny if requested
	       my @specificTablesToBeDumped = MpmasInputfile->get_cfg_list_empty_ok("TABLES_AS_EXTRA_INPUT");
	       if (scalar @specificTablesToBeDumped   ) {
		    my $taboutFH;
		    my $dumpedtablepath = $outdir."extraInputData/";
		    &mkpath ($dumpedtablepath);
		    for my $tn (@specificTablesToBeDumped ) {
					my $fname =$dumpedtablepath.$inihash->{PREFIX}.$curScen."_". $tn .".tab";
					my $t = $modelCreator->{TABLES}->get_object_by_id($tn);
					if (not defined $t) {
						print STDERR "Table $tn requested for TABLES_AS_EXTRA_INPUT does not exist.\n";
						exit(1);
					}
					open( $taboutFH ,">", $fname) or (print(STDERR "Error: $fname could not be created\n") and exit 1);
					$t->printme_with_header_sorted_to_fh($taboutFH);
					close($taboutFH);
	            }
		}
	      
			#print "heap size/ perl size before file creation: ", heap_size(),", ", perl_size(),"\n";
			$mu->record('before file creation') if logMem;
			stamp_time($starttime, "before file creation") if logMem;
			#print "modelCreator: ", size($modelCreator),", ", total_size($modelCreator),"\n";
			#	print $MpmasInputfile::mname,"\n";
			#	print "MpmasInputfile: ", total_size($MpmasInputfile::mname),"\n";
			#	print "MpmasInputfile: ", total_size($MpmasInputfile::outdir),"\n";
			#	print "MpmasInputfile: ", total_size($MpmasInputfile::outdir_cm),"\n";
			#	print "MpmasInputfile: ", total_size(\$MpmasInputfile::inihash),"\n";
			#	print "MpmasInputfile: ", total_size(\$MpmasInputfile::configs),"\n";
			#	print "MpmasInputfile: ", total_size(\$MpmasInputfile::setup),"\n";
			#	print "MpmasInputfile ActivityRegistry: ", total_size(\$MpmasInputfile::ActivityRegistry),"\n";
			#	print "MpmasInputfile ConstraintRegistry: ", total_size( \$MpmasInputfile::ConstraintRegistry),"\n";
			#	print "MpmasInputfile NetworkObjectRegistry: ", total_size($MpmasInputfile::NetworkObjectRegistry),"\n";
			#	print "MpmasInputfile: ", total_size($MpmasInputfile::PerennialObjectRegistry),"\n";
			#	print "MpmasInputfile: ", total_size($MpmasInputfile::LivestockObjectRegistry),"\n";
			#	print "MpmasInputfile: ", total_size($MpmasInputfile::TPPenaltyObjectRegistry),"\n";
			#	print "MpmasInputfile: ", total_size($MpmasInputfile::SOSRegistry),"\n";;
			#	print "MpmasInputfile: ", total_size(\$MpmasInputfile::dbh),"\n";;
			#	print "MpmasInputfile: ", total_size($MpmasInputfile::backwards),"\n";
			#	print "MpmasInputfile: ", total_size($MpmasInputfile::tableau_compact),"\n";;
			
	  #### Prepare input files
	      $| = 1; #autoflush print  
	      ## for standalone matrix use
	      if ($singlemode) { 			
		      my $milp;
			  $milp = MpmasMILPMultiperiod->new(10,1,"","");
 
		      $milp->prepare_shared($singlemode);
		      
			  unless($newsinglemode) {
				  ## create rhshash if in #transform_assets mode
				  if (defined $baserhsdef and not ref $baserhsdef and $baserhsdef == -99) {
					my $soiltab;
					if (defined $modelCreator->{INITABLEDEFS}->{RHS_SOILTAB}) {
					  $modelCreator->{INITABLEDEFS}->{RHS_SOILTAB}->set_keys(2);
					  $soiltab = $modelCreator->{INITABLEDEFS}->{RHS_SOILTAB}->transform($dbh);
					}
					elsif (defined $modelCreator->{INITABLEDEFS}->{RHS_MAPDIR}) {
					  my $mapdir = $modelCreator->{INITABLEDEFS}->{RHS_MAPDIR};	
					  $mapdir = $mapdir ."/" unless ($mapdir =~/\/$/);
					  use EnhancedGrid;
					  my $soilmap = EnhancedGrid->create_from_ascii($mapdir."CatchMap00Soil.txt");
					  my $propmap = EnhancedGrid->create_from_ascii($mapdir."CatchMap00Prop.txt");
					  $soiltab = IndexedTable->create_from_hash($soilmap->tabulate_values_by_grid($propmap), 2, "soiltab");
					}
			#	    my $agentinfo = $milp->config_entry("AGENT_INFO")->transform ($dbh,1);
		#		    my $householdtab = $milp->config_entry("HOUSEHOLD_COMPOSITION")->transform ($dbh,2);
	#			    my $assettab = $milp->config_entry("ASSET_ENDOWMENTS")->transform ($dbh,2);
	#			    my $sexagedef = $milp->config_entry("HOUSEHOLD_MEMBER_TYPES")->transform ($dbh,1);

					
					my $nwset = MpmasNetworkSet->new();
					$nwset->define_specobjs();
					$nwset->prepare_shared_files;
					my $dmset = MpmasDemographySet->new();
					$dmset->prepare_shared_files;
					my $demotab = $milp->config_entry("CONVERTED_DEMOTAB");
					
					my $cluset = MpmasClusterSet->new();
					$cluset->prepare_shared_files();
					
					my $agentinfo = $cluset->agentinfo;
					my $householdtab = $cluset->householdhash;
					my $assettab = $cluset->assethash;
					my $sexagedef = $cluset->sexagedef;
					
					
					my %specobjindex = %{$milp->get_specobj_indices()};
					my ($lilprow, $liq_constraint) = $milp->find_special_constraint("MASliq" ,1, ,1);
					my ($numsoilrows, $firstsoilrow) = $milp->find_special_constraints("MASsoil");
					my $rhshash;
					foreach my $ag (@{$rhslist}) {
						##transform assets to rhs
						my $liqassigned = 0;
						foreach my $as ($assettab->query([$ag],0)) {
						  if ($as eq "liquidity") {
							  #special treatment for liquidity
							  $rhshash->{$ag}->{$liq_constraint} = $assettab->query([$ag, $as],3);
							  $liqassigned = 1;
						  }
						  elsif (defined $specobjindex{$as}) {
							  #skip other special objects
							  next;
						  }
						  else {
							my $asset_object = $milp->networkobject($as);
							print STDERR "Error in RHS for agent $ag. Asset $as is not part of the current model.\n" and exit(1) unless (defined $asset_object);
							my $constraint = $milp->constraint_at_row( $asset_object->con );
							my $rhs_multiplier = $asset_object->attr("multiplier");
							$rhshash->{$ag}->{$constraint->id} = $rhs_multiplier * $assettab->query([$ag, $as],3);
							#print "$ag\t$as\t".join("\t", $rhs_multiplier * $assettab->query([$ag, $as],3), $assettab->query([$ag, $as],3), $rhs_multiplier)."\n" if ($ag == 4320);
						  }
						}
						#assign global liquidity value if no special liquidity as been assigned
						$rhshash->{$ag}->{$liq_constraint} = $milp->config_entry("LIQUIDITY") unless ($liqassigned);
						##transform houshold members to labor rhs
						my $pop = $agentinfo->query([$ag], 2);
						
						
						foreach my $hm ($householdtab->query([$ag],0)) {
							my $career = $sexagedef->query([$hm],2);
							my $age = ($sexagedef->query([$hm],4) +  $sexagedef->query([$hm],5)) / 2 ;
							my $agecat;
							for my $agc (sort { $b <=> $a }  $demotab->query([$pop, $career],0 )) {
								if ($age <= $agc) {
								  $agecat = $agc;
								  last;
								}
							}
							print STDERR "Error: Household member age ($age) for agent $ag out of bounds of demography information for population $pop and career $career!\n" and exit(1) unless (defined $agecat);
							my $labcat = $demotab->query([$pop, $career, $agecat],4);
							my $labprov = $demotab->query([$pop, $career, $agecat],5);
							my $constraint = $milp->constraint_at_row($milp->config_entry("FIRSTLAB") + $milp->config_entry("LABGRPS")->{$labcat}->{lid}); 
							$rhshash->{$ag}->{$constraint->id} = $householdtab->query([$ag, $hm],3) * $labprov;
							
						}
						##transform soils to soil rhs
						foreach my $soil ($soiltab->query([$ag],0)) {
							print STDERR "Error, when creating RHS: Soil index $soil out of bounds for agent $ag!\n" and exit(1) if ($soil >= $numsoilrows or $soil < 0 );
							my $constraint = $milp->constraint_at_row($firstsoilrow + $soil); 
							$rhshash->{$ag}->{$constraint->id} = $soiltab->query([$ag, $soil],3);
						}
					}
					$rhsdef = IndexedTable->create_from_hash($rhshash, 2, "RHSDEF");
				  }
			  }
		      #print Dumper($rhshash);
		      #print STDERR "Warning: You requested a stand-alone matrix, but did not specify any agent-specifc right hand side values." unless (ref $rhsdef);
		      $collected_rhshash->{$curScen} = $rhsdef;
		      
		      ##preparation of matrix files
		      ## for GNU Octave
		      
		      if ($octave) {
			    my $groupcodes = $milp->write_octave($selgroup);
			    my $fn = $milp->outdir().$milp->mname()."_OGROUP.dat";
			    open($fh, ">", $fn ) or die "Can't open $fn: $!";
			    print $fh "Code\tGroup\n";
			    for my $g (sort {$groupcodes->{$a} <=> $groupcodes->{$b}  } keys %$groupcodes) {
				print $fh "$g\t$groupcodes->{$g}\n";
			    }
			    close($fh);
			    my $fnh = $milp->outdir().$milp->mname()."_ORHS.dat";
			    open($frh, ">", $fnh ) or die "Can't open $fnh: $!";
			    my $c = 1;
			    
			    for my $curRHS (@{$rhslist}) {
	      
				  for my $curC ($rhsdef->query([$curRHS],0)) {
					my $x = $milp->constraint($curC);
					print STDERR "Error: RHS value for $curC provided, but constraint $curC does not exist!\n" and exit(1) unless (defined $x);
					print $frh join("\t", $c, $x->lp_row + 1, $rhsdef->query([$curRHS,$curC],4))."\n";
				  }
				  $c++;
			    }
			    close($frh);
		      }
		      ## for mqlmatrix/MilpCheckExe
		      if ($singlefiles) {
			    $milp->prepare_special($singlemode,undef, $rhsdef, $newsinglemode);
				if($newsinglemode) {
						print "\nWriting LP matrix file ...\n";
						$milp->write(0,"", undef, $singlemode, $newsinglemode );
						$milp->write(1,"", undef, $singlemode, $newsinglemode) unless( $additionaloutput{NO_COMMENTED});
				}
				else {
					for my $curRHS (@{$rhslist}) {
						print "\nWriting matrix file for RHS $curRHS...\n";
						$milp->write(0,$curRHS, $rhsdef, $singlemode,$newsinglemode);
						$milp->write(1,$curRHS, $rhsdef, $singlemode, $newsinglemode)  unless( $additionaloutput{NO_COMMENTED});
						
					}
				}
			    for my $curFile ( "MpmasActivityInfo", "MpmasConstraintInfo", "MpmasSimulationRunParameterListExtra") {#, "MpmasSimulationRunParameterListDefaults") {
				    my $f;
				    if (eval("$curFile"."->required") ){	
					    eval("\$f = $curFile"."->new(1)")  or die "Error $@ trying to create  $curFile\n";
					    $f->prepare_shared(); 
					    $f->prepare_special();
					    $f->write(0); 
					    $f->write(1)  unless( $additionaloutput{NO_COMMENTED});
				    }
				    die $@ if $@;

			    }
		      }
		      $milp->blank_file;
	      } 
	      ### for full model use
	      else { 
		      my @filelist = ("MpmasMILPSet", "MpmasNetworkSet", "MpmasSegmentSet", "MpmasDemographySet","MpmasTimehandler","MpmasRegion", 
		      "MpmasMarketSet", "MpmasClusterSet",
		      "MpmasRentalContracts", "MpmasBData", "MpmasCropExt", "MpmasCropExtLinkXN", "MpmasCropDbgActivityID", 
		      "MpmasCropDbgYield","MpmasCropYieldsSet", "MpmasCropSimilarity","MpmasSoilToNRU", "MpmasLandMarket", 
		      "MpmasInvestmentsAttachedToLand", 
		      "MpmasActivityInfo", "MpmasConstraintInfo", "MpmasNetworkObjectInfo","MpmasLivSimCouplingInfo", "MpmasExternalScriptCalls", 
		      "MpmasCharacteristicsInfo", "MpmasCropCharacteristicsInfo", "MpmasAgentExpectationParameters","MpmasCommonProperty");#,"MpmasSimulationRunParameterListDefaults");
		      # ,"MpmasStataLabelsU","MpmasStataLabelsK","MpmasStataLabelsP", "MpmasStataGroups" );
		      push @filelist, "MpmasQLConstraintAnalysis" if $additionaloutput{ADD_CONANALYSIS};
		      push @filelist, ("MpmasConstraintInfoEdicMatlab", "MpmasActivityInfoEdicMatlab") if $additionaloutput{ADD_EDICMATLAB};

		      my $fileregistry = SimpleObjectRegistry->create();
			  MpmasInputfile->set_fileregistry($fileregistry);
			  	
		      ##Create input files: Shared Preparation loop -> this is run in any case, even if the user wants to skip the file, because it prepares data that might be needed by other files as well
		      my $c = 0;
		      for my $curFile (@filelist){
			      my $f;
			      $c += 10;
			      if (eval("$curFile"."->required") ){	
				      eval("\$f = $curFile"."->new($c)")  or die "Error $@ trying to create  $curFile\n";
				      $fileregistry->add_objects($f);
				      my $msg = "\e[K \rPreparing shared information from ".$f->filename."...\r" ;
				      $msg = "\e[K \rPreparing shared information from ".$f->filename."...\n"  if $verbosityflag{VERBOSE_FILES};
				      print $msg;
				      $f->prepare_shared(); 
				      
				    
						#print "heap size/ perl size after $curFile ->prepare_shared: ", heap_size(),", ", perl_size(),"\n";
						#print "$curFile: ", size($f),", ", total_size($f),"\n";
						$mu->record("after prepare_shared $curFile") if logMem;
						stamp_time($starttime, "after prepare_shared $curFile") if logMem;
				      
			      }
			      die $@ if $@;
		      }
		      print "\e[K \rFinished preparing shared information\n";

		      ##Create input files: Special Preparation and Writing loop
		      for my $curFile (sort {$a->priority <=> $b->priority}  $fileregistry->object_list()) {		

			      my $simplefilename = $curFile;
			      $simplefilename =~ s/^Mpmas//;
			      $simplefilename =~ s/file$//;
			      $simplefilename =~ s/Set$//;
			      if ($curFile->required and not exists $skiplist{$simplefilename} ) {
				      my $msg = "\e[K \rCreating ".$curFile->filename."...\r" ;
				      $msg = "\e[K \rCreating ".$curFile->filename."...\n"  if $verbosityflag{VERBOSE_FILES};
				      print $msg;
				      $curFile->prepare_special(); #layout of file is prepared
				      
						#print "heap size/ perl size after ".$curFile->filename." ->prepare_special: ", heap_size(),", ", perl_size(),"\n";
						#print $curFile->filename.": ", size($curFile),", ", total_size($curFile),"\n";
						$mu->record("after prepare_special $curFile") if logMem;
						stamp_time($starttime, "after prepare_special ".$curFile->filename) if logMem;

				      

				      $curFile->write(0) ; #MP-MAS input version of file is written
				      $curFile->write(1) unless( $additionaloutput{NO_COMMENTED}); # commented version is written
			      }
		      }
		      ##Set scenario-specific MP-MAS command line options
		      if ($configs->{EDICEXTENDEDCANAL}) {
				$scenflags->{$curScen}->{C} = "-C".$inihash->{RUNCNLDIR}.$mname."_CanalModel.dat";
		      }
		      if (exists $configs->{EDICSURPLUS}) {
				$scenflags->{$curScen}->{H} = "-H".$configs->{EDICSURPLUS};
		      }
		      if (defined $configs->{GENERATE_MAPS} and  $configs->{GENERATE_MAPS} > 0) { 
		      
			      if (exists $configs->{MAPS} and defined $configs->{MAPS}) {
					$scenflags->{$curScen}->{P} = "-P".$configs->{MAPS}."/".$mname;
			      }
			      else {
			      		$scenflags->{$curScen}->{P} = "-Pgis/".$mname;
			      }
		      }
		      else {
		      	      if (exists $configs->{MAPS} and defined $configs->{MAPS}) {
					$scenflags->{$curScen}->{P} = "-P".$configs->{MAPS};
			      }
		      }
		      if (exists $configs->{TERRAINMAPSTUB} and defined $configs->{TERRAINMAPSTUB}) {
				$scenflags->{$curScen}->{t} = "-t".$configs->{TERRAINMAPSTUB};
		      }
			  if ($inihash->{SKIP_AGENTS}  || $inihash->{USE_ONLY_AGENTS}) {
				$scenflags->{$curScen}->{b} = "-b";
			  }
		      ##extend list of all groupings
		      @ConstraintGroupingsForAllScenarios = keys %{ MpmasInputfile->config_entry("Groupings")->{constraint} };
		      @ActivityGroupingsForAllScenarios = keys %{ MpmasInputfile->config_entry("Groupings")->{activity} };
		      $maxperiods = MpmasInputfile->config_entry("NYEARS")  if ( MpmasInputfile->config_entry("NYEARS") > $maxperiods);
	      }

	      print "\e[K \r<< Finished writing of input files for scenario $curScen\n";
      }
      else {
	      if ($configs->{EDICEXTENDEDCANAL}) {
			$scenflags->{$curScen}->{C} = "-C".$inihash->{RUNCNLDIR}.$mname."_CanalModel.dat";

	      }
	      if (exists $configs->{EDICSURPLUS}) {
			$scenflags->{$curScen}->{H} = "-H".$configs->{EDICSURPLUS};

	      }
	      if (exists $configs->{MAPS} && defined $configs->{MAPS}) {
			$scenflags->{$curScen}->{P} = "-P".$configs->{MAPS};
	      }
	      if ($inihash->{SKIP_AGENTS}  || $inihash->{USE_ONLY_AGENTS}) {
			  $scenflags->{$curScen}->{b} = "-b";
		  }
		  if (exists $configs->{TERRAINMAPSTUB} && defined $configs->{TERRAINMAPSTUB}) {
			$scenflags->{$curScen}->{t} = "-t".$configs->{TERRAINMAPSTUB};
		  }
		  
      }

      $Nsimrunparams = MpmasInputfile-> get_num_simrun_parameters() if (MpmasInputfile-> get_num_simrun_parameters() > $Nsimrunparams);
	  MpmasInputfile->set_global_references(undef,undef, undef, undef, undef, undef, undef, undef, undef,undef,undef,undef,undef,undef, undef, undef, undef, undef);	     
   	  stamp_time($starttime, "end of $curScen") if logMem;
   	  $mu->record("end of $curScen") if logMem;   
   	  $mu->dump() if logMem; 
   	  
   	  
   	  
}#END SCENARIO LOOP
	my ($paramscenlist, $paramscendef) = $modelCreator->transform_parameter_variation_tables($dbh);

    $mu->record("after transform_parameter_variation_tables") if logMem;
	stamp_time($starttime, "after transform_parameter_variation_tables") if logMem;
	
	MpmasInputfile->set_global_references($inihash->{PREFIX}, $outdir, $outdir_cm, $inihash, undef, undef, undef, 
						undef, undef,undef,undef,undef,
						undef,$dbh, undef, undef, undef, $starttime, undef, undef, undef);	
	
    my $paramscen_filename;
    if ((!$singlemode || $newsinglemode) && defined($paramscendef) && ! $paramscendef->is_empty() ) {
		my $mps = MpmasSimulationRunParameterScens->new();
		$mps->prepare_special($paramscendef, $Nsimrunparams, $strictlySorted, 1);
		$paramscen_filename = $mps->write(0, $inihash->{PREFIX});
		$mps->write(1, $inihash->{PREFIX}) unless( $additionaloutput{NO_COMMENTED});
	}
	$mu->record("after MpmasSimulationRunParameterScens") if logMem;
	stamp_time($starttime, "after MpmasSimulationRunParameterScens") if logMem;
	
	my $paramscenlist_filename;
	if ((!$singlemode || $newsinglemode) && scalar(@$paramscenlist) > 0  && defined($paramscendef) && ! $paramscendef->is_empty()) {
  	    my $psl = MpmasSimulationRunParameterScenList->new();
		$psl->prepare_special($paramscenlist);
		$paramscenlist_filename = $psl->write(0, $inihash->{PREFIX});
		$psl->write(1, $inihash->{PREFIX}) unless( $additionaloutput{NO_COMMENTED});
	}

	#print "heap size/ perl size before run script: ", heap_size(),", ", perl_size();
	stamp_time($starttime, "run scripts") if logMem;
	$mu->record("before run script") if logMem;  
	$mu->dump() if logMem;

my $runfilename; 
RUNFILES:	{
	print "\nWriting run scripts...";

	
	if ($OSfiles eq "MSWin32") {
		$inihash->{RUNSCRIPTDIR} = "" if (not exists $inihash->{RUNSCRIPTDIR} or $inihash->{RUNSCRIPTDIR} eq "./");
		$runfilename = $inihash->{RUNSCRIPTDIR}.$inihash->{PREFIX}."run.bat";
	}
	else {
		$inihash->{RUNSCRIPTDIR} = "./" unless (exists $inihash->{RUNSCRIPTDIR});
		$runfilename = $inihash->{RUNSCRIPTDIR}.$inihash->{PREFIX}."run";
	}
	
	open(my $runout, ">",  $runfilename) or print STDERR "$!" and exit(1);
	

	my $sfmout;
	my $scenout;
	my $rhsout;
	if ($singlemode && ! $newsinglemode) {
		open($sfmout, ">",  $outdir.$inihash->{PREFIX}."sam_list.txt") or die "$!";
		open($scenout, ">",  $outdir.$inihash->{PREFIX}."sceninfo.txt") or die "$!";
		open($rhsout, ">",  $outdir.$inihash->{PREFIX}."rhsinfo.txt") or die "$!";
		print $sfmout "scenario\tfarm\n";
		print $scenout "scenario\tvariable\tvalue\n";
		print $rhsout "scenario\tagent\tvariable\tvalue\n";
	}
	if ($OSfiles eq "linux") {
		print $runout "#!/bin/sh\n";
		print $runout "# Info: This script was created with mpmasql4 v$thisversion ($lastchange ) on ", scalar(localtime), "\n";
		print "ulimit -c unlimited\n" if $inihash->{DUMP_CORE};
	}
	elsif ($OSfiles eq "MSWin32") {
		print $runout "REM Info: This script was created with mpmasql4 v$thisversion ($lastchange ) on ", scalar(localtime), "\n";
		
		$inihash->{RUNOUTDIR} =~ s/\/+/\\/g if 	($inihash->{RUNOUTDIR});
		$inihash->{RUNINDIR} =~ s/\/+/\\/g if 	($inihash->{RUNINDIR});
	}
#	my $maspipeout;
#	if (exists $inihash->{MASPIPESERVER}) {
#	      my $runscriptdir = "./";
#	      $runscriptdir = $inihash->{RUNSCRIPTDIR} if (exists $inihash->{RUNSCRIPTDIR});
#	      open($maspipeout, ">",  $runscriptdir.$inihash->{PREFIX}."runmaspipe") or print STDERR "$!" and exit(1);
#	      print $maspipeout "#!/bin/sh\n";
#	}
	for my $curScen (@scenlist){
		my $mname = "$inihash->{PREFIX}"."$curScen";
		
		unless ($singlemode) {
			for my $paramscen (@$paramscenlist) {
			
				my $exec = $inihash->{EXEC} || "mpmasMP";
				if ($OSfiles eq "MSWin32" and not $exec =~ /\.(exe|bat)$/) {
						$exec .= ".exe";
				}
				
				if($inihash->{RUNOUTDIR} and not $inihash->{RUNINDIR}) {
				        $inihash->{RUNINDIR}   = "." ;
				}
				
				if ($inihash->{ADD_TIME_CMD} and $OSfiles eq "linux") {
					if (not defined $inihash->{TIMING_FORMAT}) {
						$inihash->{TIMING_FORMAT} = "%C: %x, real %E, user %U, system %S, Percent cpu %P, Total memory %K, Resident memory %M, Nswapped %W\\n"
					}
					print $runout "\\time -f \"" . $inihash->{TIMING_FORMAT} . "\" -o ";  
					print $runout $inihash->{RUNOUTDIR} if ( $inihash->{RUNOUTDIR});
					print $runout "out/".$mname."_runStats.log ";
				}
				
				print $runout $exec."  -N".$mname."_ ";
				print $runout " -V".$paramscen unless($paramscen eq "_");
				print $runout " -W".$paramscen_filename unless($paramscen eq "_");
				print $runout " -I".$inihash->{RUNINDIR} if ( $inihash->{RUNINDIR});
				print $runout " -O".$inihash->{RUNOUTDIR} if ( $inihash->{RUNOUTDIR});
				print $runout " -X".$inihash->{RUNTDTDIR} if ( $inihash->{RUNTDTDIR});
				print $runout " ".$inihash->{FLAGS} if (defined $inihash->{FLAGS});
					

			
				if (exists $scenflags->{$curScen}) {
					  for my $i (keys %{ $scenflags->{$curScen} }) {
						print $runout " ".$scenflags->{$curScen}->{$i} ." ";
					  }
				}
				print $runout "\n";
	#			if (exists $inihash->{MASPIPESERVER}) {
	#					  my $user = " ";
	#					  $user = "-u".$inihash->{MASPIPEUSER} if (exists $inihash->{MASPIPEUSER});
	#					  print $maspipeout "maspipe ".$user. " run ".$inihash->{MASPIPESERVER}." ".$inihash->{MASPIPEEXEC}. " ". $inihash->{MASPIPEVERSION}. " ". $mname."_ ". $inihash->{FLAGS};
	#					  if (exists $scenflags->{$curScen}) {
	#						for my $i (keys %{ $scenflags->{$curScen} }) {
	#							  print $maspipeout " ".$scenflags->{$curScen}->{$i} ." ";
	#						}
	#					  }
	#					  print $maspipeout "\n";
	#			}
			
			}
		}
		elsif ($singlemode && $newsinglemode) {
			my $exec = $inihash->{EXEC} || "mpmasMipSolver" ;
			if ($OSfiles eq "MSWin32" and not $exec =~ /\.(exe|bat)$/) {
					$exec .= ".exe";
			}
			if ($inihash->{ADD_TIME_CMD}  and $OSfiles eq "linux") {
				if (not defined $inihash->{TIMING_FORMAT}) {
					$inihash->{TIMING_FORMAT} = "%C: %x, real %E, user %U, system %S, Percent cpu %P, Total memory %K, Resident memory %M, Nswapped %W\\n"
				}
				print $runout "\\time -f \"" . $inihash->{TIMING_FORMAT} . "\" -o ";  
				print $runout $inihash->{RUNOUTDIR}  if ( $inihash->{RUNOUTDIR});
				print $runout "out/".$inihash->{PREFIX}."_runStats.log ";
			}
			print $runout $exec." ";
			 if (defined $inihash->{RUNINDIR}) {
				 print $runout $inihash->{RUNINDIR};
			 } 
			 else {
				 print $runout $inihash->{OUTDIR};
			 }
			print $runout $mname,"_MILP.mtx";

			print $runout " -l ".$paramscenlist_filename if (defined $paramscenlist_filename);
			print $runout " -W ".$paramscen_filename if(defined $paramscen_filename);
			
			unless (defined $inihash->{NO_ACTIVITY_NAMES} &&  $inihash->{NO_ACTIVITY_NAMES}) {
				print $runout " -names ", (defined $inihash->{OUTDIR} ?  $inihash->{OUTDIR} : $inihash->{RUNINDIR} ),  $mname,"_ActivityInfo.txt";

			}
			if (defined $inihash->{FLAGS}) 
			{
				my $flags = $inihash->{FLAGS};
				$flags =~ s/\\"/"/g;
				print $runout " $flags";
			}
			print $runout " -test" if ($testformat);
			
			print $runout " -O ".$inihash->{RUNOUTDIR} if ( $inihash->{RUNOUTDIR});
			
			
			print $runout "\n";
		}
		elsif ($singlemode && !$newsinglemode) {
			
			for my $i ( ref $scendef ? $scendef->query([$curScen],0) : "base"   ){
				print $scenout "$mname\t$i\t".$scendef->query([$curScen,$i],3)."\n" if (ref $scendef);
			}
			for my $curRHS(@{$rhslist}) {
				print $sfmout "$mname\t$curRHS\n";
				if (ref  $collected_rhshash->{$curScen} ) {
					for my $j ( $collected_rhshash->{$curScen}->query([$curRHS],0)){
						print $rhsout "$mname\t$curRHS\t$j\t".$collected_rhshash->{$curScen}->query([$curRHS,$j],3)."\n";
					}
				}
			}
			

		}		
	
	}
	if ($singlemode && !$newsinglemode) {
			my $exec = $inihash->{EXEC} ||  "mpmasqlBatchSolve";
			if ($OSfiles eq "MSWin32" and not $exec =~ /\.(exe|bat)$/) {
					$exec .= ".bat";
			}
			if ($inihash->{ADD_TIME_CMD}) {
				if (not defined $inihash->{TIMING_FORMAT}) {
					$inihash->{TIMING_FORMAT} = "%C: %x, real %E, user %U, system %S, Percent cpu %P, Total memory %K, Resident memory %M, Nswapped %W\\n"
				}
				print $runout "\\time -f \"" . $inihash->{TIMING_FORMAT} . "\" -o ";  
				print $runout $inihash->{RUNOUTDIR}  if ( $inihash->{RUNOUTDIR});
				print $runout $inihash->{RUNOUTDIR} .$inihash->{PREFIX}."_runStats.log ";
			}
			print $runout $exec." ".$inihash->{PREFIX}." ";

			
			if (defined $inihash->{FLAGS}) 
			{
				my $flags = $inihash->{FLAGS};
				$flags =~ s/\\"/"/g;
				print $runout " $flags";
			}

			print $runout "\n";
	}

	
	
	close $scenout if ($singlemode && ! $newsinglemode);
	close $rhsout if ($singlemode && ! $newsinglemode);
	close $sfmout if ($singlemode && ! $newsinglemode);
	close $runout;
	chmod 0755, $runfilename;
	
#	close $maspipeout if (exists $inihash->{MASPIPESERVER}) ;
  
	#Write importing scripts for statistical programs
#	unless ($singlemode) {
	if(0) {
		MpmasStataImport->create();
		MpmasStataImport->write($inihash, \@scenlist, $maxperiods, \@ConstraintGroupingsForAllScenarios, \@ActivityGroupingsForAllScenarios);
		MpmasRImport->create();
		MpmasRImport->write($inihash, \@scenlist, $maxperiods);
	}
} #END RUNFILES

stamp_time($starttime, "END") if logMem;
$mu->record("END") if logMem;  
$mu->dump() if logMem;

print "\n";
if (defined $dbh) {
      $dbh->disconnect;
      print "Disconnected from database $inihash->{DB}.\n";
}
my $totaltime = (time - $starttime);
my $minutes = int ($totaltime / 60);
my $seconds = $totaltime % 60;
print "Needed $minutes:".sprintf("%02d",$seconds)." minutes for creating the model and scenarios.\n\n";

if ($runModel == 1) {
	print "Running: $runfilename";
	exec($runfilename);
	
}
if ($runModel == 2) {
	print "Running and waiting for: $runfilename";
	system($runfilename);
	
}

