Exporting output results from a model into the input of a different model - anylogic

I'm trying to build a model of a factory using the personal learning edition of AnyLogic. Since this version has a limited number of blocks per model, building the full factory on a single model is presenting itself as an impossible task. In order to surpass this issue I want to split the factorys main processes into different models, which means I'll have to feed the output of process A into the input of process B.
My question is: how can I export a time stamped output of a model into the input of a different model?
Thank you in advance.

You have 2 options
Option 1: Through an Excel file (or txt file)
Simply link an Excel file in your model, using the object from the connectivity palette
Then you can get the data using code similar to below
int excelRow = 2;
String sheetName = "Sheet1!";
String cellName = sheetName + "A" + excelRow;
while (excelFile.cellExists( cellName )) {
int x = (int)excelFile.getCellNumericValue( sheetName + "A" + excelRow);
int b = (int)excelFile.getCellNumericValue( sheetName + "B" + excelRow);
int c = (int)excelFile.getCellNumericValue( sheetName + "C" + excelRow);
boolean d = excelFile.getCellBooleanValue( sheetName + "D" + excelRow);
excelRow ++; // Increase the row that we will lookup in the Excel
}
Just a while loop where you go from one excel line to the next as long as the line exists, and then do what ever is needed with the data
Option 2: AnyLogic Internal DB
Simply import your excel sheet to the AnyLogic DB and then loop over the entries in the table using a for loop
List<Tuple> rows = selectFrom(db_table).list();
for (Tuple row : rows) {
traceln(
row.get( db_table.db_column )
);
}

Related

Expand rows based on the integer values of a column while parsing through the values in remainder columns to separate values among the inserted rows

What I need is to insert rows according to the integer value in a column while parsing through the values in the remaining columns to separate their values on the new inserted rows.
I have a table like this
ID
Household
User Count
Show 1
Show 2
Show 3
Show 4
123
House 1
2
Shooter
Dark
1234
House 2
4
Awake
Arrow
Lou
Ozark
And I need an expanded table where each row represents an individual user
ID
Household
User Count
Show 1
Show 2
Show 3
Show 4
123
House 1
1
Shooter
123
House 1
1
Dark
1234
House 2
1
Awake
1234
House 2
1
Arrow
1234
House 2
1
Lou
1234
House 2
1
Ozark
I need to solve this problem using either Google Apps Script or PostgreSQL.
In your situation, when Google Apps Script is used, how about the following sample script?
Sample script:
Please copy and paste the following script to the script editor of Spreadsheet and save the script. And, please set the source and destination sheet names.
function myFunction() {
const srcSheetName = "Sheet1"; // Please set source sheet name.
const dstSheetName = "Sheet2"; // Please set source sheet name.
const ss = SpreadsheetApp.getActiveSpreadsheet();
const sheet = ss.getSheetByName(srcSheetName);
const [header, ...values] = sheet.getDataRange().getValues();
const res = [header, ...values.flatMap(([a, b, c, ...d]) => {
const len = d.length;
return [...Array(c)].map((_, i) => {
const temp = [...Array(i).fill(null), d[i]];
return [a, b, 1, ...temp, ...Array(len - temp.length).fill(null)];
});
})];
ss.getSheetByName(dstSheetName).getRange(1, 1, res.length, res[0].length).setValues(res);
}
When this script is run, the values are retrieved from source sheet, and the values are converted, and then, the converted values are put to the destination sheet. In this case, when your sample input table is used, the sample output table can be obtained.
If you want to use this script as a custom function, how about the following sample script? When your showing input table is used, please put a custom function like =SAMPLE(A1:G3) to a cell. By this, the result values are returned.
function SAMPLE(v) {
const [header, ...values] = v;
return [header, ...values.flatMap(([a, b, c, ...d]) => {
const len = d.length;
return [...Array(c)].map((_, i) => {
const temp = [...Array(i).fill(null), d[i]];
return [a, b, 1, ...temp, ...Array(len - temp.length).fill(null)];
});
})];
}
Note:
This sample script is prepared from your sample input and output tables. So, when you changed the table or your actual Spreadsheet is different from your sample input table, the script might not be able to be used. Please be careful about this.
Reference:
map()

Read a Database with a loop

my problem is as follows: i have a database, each row represents a delivery that my agent has to make. The first column contains the specific name of the delivery, the others the names of the nodes to be reached ('pad_1','pad_2,'pad_3'.......).
In the main I have a string vector that contains the name of all the columns in the database.
I also have an event that at the specific delivery time calls a function with which I would like to scroll through the columns of the database of the row related to the delivery, so as to fill a vector of nodes with the contents of columns other than 0.
The query to the database, I wanted to automate it by scrolling the vector of strings with this code: ''' int [] Pad = new int[n_pc];
for (int i=0;i< n_pc;i++){
Pad[i]=selectFrom(farmacia_clinica).where(farmacia_clinica.fascia.eq(FASCIA_A).uniqueResult(farmacia_clinica.PAD_FarmaciaClinica[i]));}
the error is in the last command "uniqueResult(farmacia_clinica.PAD_FarmaciaClinica[i])"
How can I resolve this?
Thank u.
This doesn't work for QueryDSL as you need to have a StringPath and not String type as arguments for referencing the DB column. Instead, you can build an SQL query using your String array for your code.
The code will then be:
int [] Pad = new int[n_pc];
for (int i=0; i< n_pc; i++) {
Pad[i] = selectUniqueValue(int.class,
"SELECT " + PAD_FarmaciaClinica[i] +
" FROM farmacia_clinica WHERE fascia = ?;",
"FASCIA_A");
}

Google script - send email alert

I have a script that looks into values in column G and if the correspondent cell in column A is empty, sends me an email.
--- WHAT WORKS --
It works ok for static values: it sends one email per each not empty cell in column G for which there is no value in column A
--- WHAT DOESN'T WORK --
It sends several emails for what I assume it's every Column G cell (empty or not) when the column A values are fetched from another tab. That way it's like all G and A cells have data, so I get multiple unwanted emails.
This is the script code:
const ss = SpreadsheetApp.getActive();
const sh = ss.getSheetByName('Sheet to send emails');
const data = sh.getRange('A2:G'+sh.getLastRow()).getValues();
data.forEach(r=>{
let overdueValue = r[0];
if (overdueValue === ""){
let name = r[6];
let message = 'Text ' + name;
let subject = 'TEXT.'
MailApp.sendEmail('myemail#gmail.com', subject, message);
}
});
}
And this is the link to the test sheet:
https://docs.google.com/spreadsheets/d/1OKQlm0PjEjDB7PXvt34Og2fa4vPZWnvLazTEawEtOXg/edit?usp=sharing
In this test case, I "should" only get one email, related to ID 55555. With the script as is, I get one related to 55555 and several others "undefined".
To avoid e-mail spam, I didn't add the script to that sheet but it shows the "Vlookup" idea.
Can anyone give me a hand, please?
Thank you in advance
Issue:
The issue with your original script is that the sh.getLastRow returns 1000 (it also processes those rows that doesn't have contents, result to undefined)
Fix 1: Get specific last row of column G:
const gValues = sh.getRange('G1:G').getValues();
const gLastRow = gValues.filter(String).length;
or
Fix 2: Filter data
const data = sh.getRange('A2:G' + sh.getLastRow()).getValues().filter(r => r[6]);
Note:
As Kris mentioned in the comments, there is a specific case where getting the last row above will fail (same with getNextDataCell). This will not properly get the last row WHEN there are blank rows in between the first and last row of the column. If you have this kind of data, then use the 2nd method which is filtering the data.
If your data in column G does not have blank cells in between the first and last row, then any method should work.
I checked your test sheet, and sh.getLastRow() is 1000.
OPTION 1
If column G won't have empty cells between filled ones, then you can do this:
const ss = SpreadsheetApp.getActive();
const sheet = ss.getSheetByName("Sheet to send emails");
// get the first cell in column G
var gHeader = sheet.getRange(1, 7);
// equivelent of using CTRL + down arrow to find the last da
var lastRow = gcell.getNextDataCell(SpreadsheetApp.Direction.DOWN).getRow();
const data = sheet.getRange(2, 1, lastRow, 7).getValues();
OPTION 2
Add another condition to your code - like this:
data.forEach(r=>{
let overdueValue = r[0];
let name = r[6]
// check if the value in col A is blankd and col G is not blank
if (overdueValue === "" && name !== ""){
let message = 'Text ' + name;
let subject = 'TEXT.'
MailApp.sendEmail('myemail#gmail.com', subject, message);
}
});
And to speed it up, use a named range to limit how many rows it has to iterate through:
const ss = SpreadsheetApp.getActive();
const data = ss.getRangeByName("Your_NamedRange_Here").getValues();

Exercises in programming style with Scala

I've started to read the "Exercises in programming style" book recently and one of the tasks there is to implement each programming style in a language of your choice. I decided to go with Scala (I'm fairly new to it) and I'm already stuck with the first "good old school" style. The constraints are:
Very small amount of primary memory, typically orders of magnitude smaller than the data that needs to be processed/generated. (The example sets the limit to 1024 cells)
No labels -- i.e. no variable names or tagged memory addresses. All we have is memory that is addressable with numbers.
Original example (which reads a file line by line and counts the words) is in Python and goes like this:
data = []
data.append([]) # data[1] is line (max 80 characters)
data.append(None) # data[2] is index of the start_char of word
data.append(0) # data[3] is index on characters, i = 0
data.append(False) # data[4] is flag indicating if word was found
data.append('') # data[5] is the word
data.append('') # data[6] is word,NNNN
data.append(0) # data[7] is frequency
...
f = open(sys.argv[1])
# Loop over input file's lines
while True:
data[1] = [f.readline()]
...
So we see there are some variables (f and data) but the main idea is to keep it to a minimum and use python array as a bunch of "memory addresses".
Is it even possible to implement old-school-programming style (no variable names or tagged memory addresses) in Scala? Specifically is there a way to avoid "line" variable when reading file content?
for (line <- Source.fromFile("example.txt").getLines) {
println(line.toUpperCase)
}
Reading the file content into an array similar to the original example doesn't work because it's doesn't have an extractor (value data is not a case class, nor does it have an unapply/unapplySeq member).
P.S. I'm very well aware of the fact that the whole task is probably a 5-liner in Scala but that's not the point.
Sure you can abstain from introducing variables besides the data-array (and solve the problem imperative-style). Simply put everything into your array instead of assigning it to a local variable.
Obviously, the code will be a nightmare, because the array won't be typed and you won't have any meaningful names for any of your data, but I'm assuming that's what you're aiming for with this exercise.
import scala.io.Source
/**
* data 0 : file as line iterator
* data 1 : index of first unused data cell
* data 2 : current line
* data 3 : index of the first letter of the current word
* data 4 : index of the last letter of the current word
* data 5 : current word
* data 6 : temp index to find already initialized words
* data 7 : flag: Word found
* data 8, 10, 12, ... words
* data 9, 11, 13, ... frequencies
*/
object GoodOldSchool {
def main(args: Array[String]): Unit = {
val data: Array[Any] = new Array[Any](1024)
data(0) = Source.fromFile(args(0)).getLines()
data(1) = 8 // first free cell
while (data(0).asInstanceOf[Iterator[String]].hasNext) {
data(2) = data(0).asInstanceOf[Iterator[String]].next()
data(3) = 0 // index first letter of current word
data(4) = 0 // index last letter of current word
// find index last letter of current word
while (data(4).asInstanceOf[Int] < data(2).asInstanceOf[String].length) {
// find the next space (we ignore punctuation)
while (data(4).asInstanceOf[Int] < data(2).asInstanceOf[String].length && data(2).asInstanceOf[String].charAt(data(4).asInstanceOf[Int]) != ' ') {
data(4) = data(4).asInstanceOf[Int] + 1
}
data(5) = data(2).asInstanceOf[String].substring(data(3).asInstanceOf[Int], data(4).asInstanceOf[Int]) // current word
data(6) = 8 // cell index
data(7) = false // word already found
8 until data(1).asInstanceOf[Int] by 2 foreach { _ =>
// Here, we do a case-sensitive word comparison
if (data(5) == data(data(6).asInstanceOf[Int])) {
data(data(6).asInstanceOf[Int] + 1) = data(data(6).asInstanceOf[Int] + 1).asInstanceOf[Int] + 1 // increment frequency
data(7) = true
}
data(6) = data(6).asInstanceOf[Int] + 2
}
if (data(7) == false) {
// create new frequency, because word was not discovered before
data(data(1).asInstanceOf[Int]) = data(5) // set word
data(data(1).asInstanceOf[Int] + 1) = 1 // set frequency
data(1) = data(1).asInstanceOf[Int] + 2 // used up two cells, update index of next free cell
}
// move to next word
data(3) = data(4).asInstanceOf[Int] + 1
data(4) = data(3)
}
}
data foreach println // let's have a look at our result
}
}
To get the total words count in the given file, the following scala code can be used:
Source.fromFile("example.txt")
.getLines.map { line => line.trim.split(" ").length}
.reduceLeft { _ + _ }

How to automatically generate sequent numbers when using a form

Ahab stated in 2010: the complex looking number based on the Timestamp has one important property, the number can not change when rows are deleted or inserted.
As long as the submitted data is not changed by inserting deleting rows the simple formula =ArrayFormula(ROW(A2:A) - 1) may be the easiest one to use.
For other situations there is no nice reliable solution. :(
Now we live in 2015. Maybe times have changed?
I need a reliable way to number entries using a form.
Maybe a script can do the trick? A script that can add 1 to each entry?
That certain entry has to keep that number even when rows are deleted or inserted.
I created this simple spreadsheet in which I added 1,2, and 3 manually,please have a look:
https://docs.google.com/spreadsheets/d/1H9EXns8-7m9oLbCrTyIZhLKXk6TGxzWlO9pOvQSODYs/edit?usp=sharing
The script has to find the maximum of the former entries, which is 3, and then add 1 automatically.
Who can help me with this?
Grtz, Bij
Maybe a script can do the trick? A script that can add 1 to each
entry?
Yes, that would be what you need to resort to. I took the liberty of entering this in your example ss:
function onEdit(e) {
var watchColumns = [1, 2]; //when text is entered in any of these columns, auto-numbering will be triggered
var autoColumn = 3;
var headerRows = 1;
var watchSheet = "Form";
var range = e.range;
var sheet = range.getSheet();
if (e.value !== undefined && sheet.getName() == watchSheet) {
if (watchColumns.indexOf(range.getColumn()) > -1) {
var row = range.getRow();
if (row > headerRows) {
var autoCell = sheet.getRange(row, autoColumn);
if (!autoCell.getValue()) {
var data = sheet.getDataRange().getValues();
var temp = 1;
for (var i = headerRows, length = data.length; i < length; i++)
if (data[i][autoColumn - 1] > temp)
temp = data[i][autoColumn - 1];
autoCell.setValue(temp + 1);
}
}
}
}
}
For me the best way is to create a query in a second sheet pulling everything from form responses in to second column and so on. then use the first column for numbering.
In your second sheet B1 you would use:
=QUERY(Form!1:1004)
In your second sheet A2 you would use:
=ARRAYFORMULA(if(B2:B="",,Row(B2:B)-1))
I made a second sheet in your example spreadsheet, have a look at it.