strange character in Fortran write output - io

I want to time some subroutines. Here is the template I use to write the name and duration of execution:
SUBROUTINE get_sigma_vrelp
...declarations...
real(8) :: starttime, endtime
CHARACTER (LEN = 200) timebuf
starttime = MPI_Wtime()
...do stuff...
endtime = MPI_Wtime()
write (timebuf, '(30a,e20.10e3)') 'get_sigma_vrelp',endtime-starttime
call pout(timebuf)
END SUBROUTINE get_sigma_vrelp
And here is a sample output:
(thread 4):get_sigma_vrelp �>
Why is a strange character printed instead of a numerical value for endtime-starttime? Incidentally, pout() simply writes the buffer to a process-specific file in a threadsafe manner. It shouldn't have anything to do with the problem, but if there is nothing else here that would cause the erroneous output then I can post its body.

You have it the wrong way round! The line should read
write (timebuf, '(a30,e20.10e3)') 'get_sigma_vrelp',endtime-starttime
This way, you expect one string that is 30 characters long (a30) instead of 30 strings of arbitrary length (30a). The write statement does not receive characters after the first string, but the corresponding bytes of the float. Hence the garbage.
Your character literal is only 15 chars long, so you could write the line as
write (timebuf, '(a15,e20.10e3)') 'get_sigma_vrelp',endtime-starttime
or let the compiler decide the length on its own:
write (timebuf, '(a,e20.10e3)') 'get_sigma_vrelp',endtime-starttime

Related

Properly write into string in Matlab (efficient and preserving escape characters)

I have an abstract class Writer which allows clients to write into something. Could be the screen, could be a file. Now, I try to create a derived class to write into a string.
I have two problems with the denoted line in method write(...):
It's probably very inefficient. Is there something like a string buffer in Matlab?
It writes escape sequences like \n plain into the string, instead of taking their actual meaning.
How can I get the denoted line properly?
Code:
classdef StringTextWriter < Writer
properties
str;
end
methods
function this = StringTextWriter()
% Init the write-target which is a string in our case.
% (Other Writer classes would maybe open a file.)
this.str = '';
end
function write(this, val)
% Write to writer target.
% (Other Writer classes would maybe use fprinf here for file write.)
% ?????????????????????????????
this.str = [this.str val]; % How to do this properly?
% ?????????????????????????????
end
end
end
To answer your questions point by point:
The closest notion to a string buffer would be a string cell. Instead of:
str = '';
str = [strbuf, 'abc\n'];
str = [strbuf, 'def\n'];
str = [strbuf, 'ghi\n'];
%// and so on...
one may use
strbuf = {};
strbuf{end+1} = 'abc\n';
strbuf{end+1} = 'def\n';
strbuf{end+1} = 'ghi\n';
%// and so on...
str = sprintf([strbuf{:}]); %// careful about percent signs and single quotes in string
the drawback being that you have to reconstruct the string every time you ask for it. This can be alleviated by setting a modified flag every time you add strings to the end of strbuf, resetting it every time you concatenate the strings, and memoizing the result of concatenation in the last line (rebuild if modified, or last result if not).
Further improvement can be achieved by choosing a better strategy for growing the strbuf cell array; probably this would be effective if you have a lot of write method calls.
The escape sequences are really linked to the <?>printf family and not to the string literals, so MATLAB in general doesn't care about them, but sprintf in particular might.

Lua: Capturing String Based on Number of Symbols Received

I currently have a string that can be any length in size based on a single digit in one or two specific locations (based on the first digit captured). For example:
Changed
First digit captured tells me IF a file name is to follow: "1" = Object Name Follows. "0" = Next input captured is Length Multiplier.
"1" is not always received. But "0" is always received.
With "1" Capture it looks like this:
START|(1)|NAMEOFGRAPHIC|(0)|(#)|INPUT|INPUT|INPUT|INPUT|... etc
With "0" (no "1" captured)
START|(0)|(#)|INPUT|INPUT|INPUT|INPUT|... etc
The Length Multiplier bit (always follows "0") is the number of INPUT groups to follow. A "group" is a set of 4xINPUT's. So, if it was a "4", the string I want to completely capture looks like this:
With a "1":
START|(1)|NAMEOFGRAPHIC|(0)|(4)|INPUT|INPUT|INPUT|INPUT|INPUT|INPUT|INPUT|INPUT|INPUT|INPUT|INPUT|INPUT|INPUT|INPUT|INPUT|INPUT|
With a "0":
START|(0)|(4)|INPUT|INPUT|INPUT|INPUT|INPUT|INPUT|INPUT|INPUT|INPUT|INPUT|INPUT|INPUT|INPUT|INPUT|INPUT|INPUT|
As each INPUT is received, a pipe symbol is added after. I want to use the pipes to monitor the length of the input based on the digit. If the digit is 5, for example, it would capture the 3x INPUT, 5, then 5x INPUT after (with all pipes included). Once this is done, the function would send the fully captured string to other function(s) for use.
I am having problems working out the receiving function to capture this full string. I have tried to count the number of pipes in different loop functions and all are resulting in errors.
Attempts include (please understand I'm pretty new to all of this):
local buffer = ""
function pipe_count(input)
a = "|"
buffer = buffer..input.."|"
while #a < 5 do
buffer = buffer..input.."|"
return buffer
end
end
local buffer = ""
function pipe_count(input)
buffer = buffer..input.."|"
mult = tonumber(buffer:match("(.-|.-|.-|(%d)|.*)"))
while buffer do
for i = 1, mult do
buffer = buffer..input.."|"
end
return buffer
end
Those were two examples I tried. I deleted my other futile attempts to capture the exact string length. My current issue that it is taking the INPUT captures, as each one is received, and sending it to the next function prior to capturing the entire string. So, if I had received the string at the top, it would look like this:
`INPUT`
`INPUT|INPUT`
`INPUT|INPUT|INPUT`
`INPUT|INPUT|INPUT|5`
`INPUT|INPUT|INPUT|5|INPUT`
`INPUT|INPUT|INPUT|5|INPUT|INPUT` etc
until finally the string below is received:
`INPUT|INPUT|INPUT|5|INPUT|INPUT|INPUT|INPUT|INPUT|`
At this point, my file runs as it should. But up until this point, I'm getting errors since the parameters of the function(s) aren't fully met.
Ideally, I want that last string before moving on.
Any ideas would be very welcomed and appreciated.
Cheers
ETA: These INPUT's are filling a buffer. I want that check digit to be responsible for the string to only be used if the length value is met. Again, I really appreciate all input. Thank you.
ETA: Example code tried and more input details.
All strings in Lua are internalized, so it's usually a better idea to push strings onto an array than to repeatedly rebuild the same string. This example takes input line by line from stdin. 3 data inputs, followed by a number, followed by that number of data inputs. There are plenty of other ways to do it, but this is pretty easy to follow.
local buffer = {}
function process_input(input)
if #buffer == 3 then
input = tonumber(input)
end
table.insert(buffer,input)
if #buffer > 4 and #buffer == buffer[4] + 4 then
local pipe_delim = table.concat(buffer,'|')
buffer = {}
return pipe_delim
end
end
repeat
local input = io.read()
local pipe_delim = process_input( input )
if pipe_delim then
print('Got:', pipe_delim)
end
until false

Parsing strings in Fortran

I am reading from a file in Fortran which has an undetermined number of floating point values on each line (for now, there are about 17 values on a line). I would like to read the 'n'th value on each line to a given floating point variable. How should i go about doing this?
In C the way I wrote it was to read the entire line onto the string and then do something like the following:
for(int il = 0; il < l; il++)
{
for(int im = -il; im <= il; im++)
pch = strtok(NULL, "\t ");
}
for(int im = -l; im <= m; im++)
pch = strtok(NULL, "\t ");
dval = atof(pch);
Here I am continually reading a value and throwing it away (thus shortening the string) until I am ready to accept the value I am trying to read.
Is there any way I can do this in Fortran? Is there a better way to do this in Fortran? The problem with my Fortran code seems to be that read(tline, '(f10.15)') tline1 does not shorten tline (tline is my string holding the entire line and tline1 what i am trying to parse it into), thus I cannot use the same method as I did in my C routine.
Any help?
The issue is that Fortran is a record-based I/O system while C is stream-based.
If you have access to a Fortran 2003 compliant compiler (modern versions of gfortran should work), you can use the stream ACCESS specifier to do what you want.
An example can be found here.
Of course, if you were really inclined, you could just use your C function directly from Fortran. Interfacing the two languages is generally simple, typically only requiring a wrapper with a lowercase name and an appended underscore (depending on compiler and platform of course). Passing arrays or strings back and forth is not so trivial typically; but for this example that wouldn't be needed.
Once the data is in a character array, you can read it into another variable as you are doing with the ADVANCE=no signature, ie.
do i = 1, numberIWant
read(tline, '(F10.15)', ADVANCE="no") tline1
end do
where tline should contain your number at the end of the loop.
Because of the record-based I/O, a READ statement will typically throw out what is after the end of the record. But the ADVANCE=no tells it not to.
If you know exactly at what position the value you want starts, you can use the T edit descriptor to initiate the next read from that position.
Let's say, for instance, that the width of each field is 10 characters and you want to read the fifth value. The read statement will then look something like the following.
read(file_unit, '(t41, f10.5)') value1
P.s.: You can dynamically create a format string at runtime, with the correct number after the t, by using a character variable as format and use an internal file write to put in this number.
Let's say you want the value that starts at position n. It will then look something like this (I alternated between single and double quotes to try to make it more clear where each string starts and stops):
write(my_format, '(a, i0, a)') "(t", n, ', f10.5)'
read(file_unit, my_format) value1

Reading a string with spaces in Fortran

Using read(*,*) in Fortran doesn't seem to work if the string to be read from the user contains spaces.
Consider the following code:
character(Len = 1000) :: input = ' '
read(*,*) input
If the user enters the string "Hello, my name is John Doe", only "Hello," will be stored in input; everything after the space is disregarded. My assumption is that the compiler assumes that "Hello," is the first argument, and that "my" is the second, so to capture the other words, we'd have to use something like read(*,*) input1, input2, input3... etc. The problem with this approach is that we'd need to create large character arrays for each input, and need to know exactly how many words will be entered.
Is there any way around this? Some function that will actually read the whole sentence, spaces and all?
character(100) :: line
write(*,'("Enter some text: ",\)')
read(*,'(A)') line
write(*,'(A)') line
end
... will read a line of text of maximum length 100 (enough for most practical purposes) and write it out back to you. Modify to your liking.
Instead of read(*, *), try read(*, '(a)'). I'm no Fortran expert, but the second argument to read is the format specifier (equivalent to the second argument to sscanf in C). * there means list format, which you don't want. You can also say a14 if you want to read 14 characters as a string, for example.

Array of Strings in Fortran 77

I've a question about Fortran 77 and I've not been able to find a solution.
I'm trying to store an array of strings defined as the following:
character matname(255)*255
Which is an array of 255 strings of length 255.
Later I read the list of names from a file and I set the content of the array like this:
matname(matcount) = mname
EDIT: Actually mname value is hardcoded as mname = 'AIR' of type character*255, it is a parameter of a function matadd() which executes the previous line. But this is only for testing, in the future it will be read from a file.
Later on I want to print it with:
write(*,*) matname(matidx)
But it seems to print all the 255 characters, it prints the string I assigned and a lot of garbage.
So that is my question, how can I know the length of the string stored?
Should I have another array with all the lengths?
And how can I know the length of the string read?
Thanks.
You can use this function to get the length (without blank tail)
integer function strlen(st)
integer i
character st*(*)
i = len(st)
do while (st(i:i) .eq. ' ')
i = i - 1
enddo
strlen = i
return
end
Got from here: http://www.ibiblio.org/pub/languages/fortran/ch2-13.html
PS: When you say: matname(matidx) it gets the whole string(256) chars... so that is your string plus blanks or garbage
The function Timotei posted will give you the length of the string as long as the part of the string you are interested in only contains spaces, which, if you are assigning the values in the program should be true as FORTRAN is supposed to initialize the variables to be empty and for characters that means a space.
However, if you are reading in from a file you might pick up other control characters at the end of the lines (particularly carriage return and/or line feed characters, \r and/or \n depending on your OS). You should also toss those out in the function to get the correct string length. Otherwise you could get some funny print statements as those characters are printed as well.
Here is my version of the function that checks for alternate white space characters at the end besides spaces.
function strlen(st)
integer i,strlen
character st*(*)
i = len(st)
do while ((st(i:i).eq.' ').or.(st(i:i).eq.'\r').or.
+ (st(i:i).eq.'\n').or.(st(i:i).eq.'\t'))
i = i - 1
enddo
strlen = i
return
end
If there are other characters in the "garbage" section this still won't work completely.
Assuming that it does work for your data, however, you can then change your write statement to look like this:
write(*,*) matname(matidx)(1:strlen(matname(matidx)))
and it will print out just the actual string.
As to whether or not you should use another array to hold the lengths of the string, that is up to you. the strlen() function is O(n) whereas looking up the length in a table is O(1). If you find yourself computing the lengths of these static strings often, it may improve performance to compute the length once when they are read in, store them in an array and look them up if you need them. However, if you don't notice the slowdown, I wouldn't worry about it.
Depending on the compiler that you are using, you may be able to use the trim() intrinsic function to remove any leading/trailing spaces from a string, then process it as you normally would, i.e.
character(len=25) :: my_string
my_string = 'AIR'
write (*,*) ':', trim(my_string), ':'
should print :AIR:.
Edit:
Better yet, it looks like there is a len_trim() function that returns the length of a string after it has been trimmed.
intel and Compaq Visual Fortran have the intrinsic function LEN_TRIM(STRING) which returns the length without trailing blanks or spaces.
If you want to suppress leading blanks or spaces, use "Adjust Left" i.e. ADJUSTF(STRING)
In these FORTRANs I also note a useful feature: If you pass a string in to a function or subroutine as an argument, and inside the subroutine it is declared as CHARACTER*(*), then
using the LEN(STRING) function in the subroutine retruns the actual string length passed in, and not the length of the string as declared in the calling program.
Example:
CHARACTER*1000 STRING
.
.
CALL SUBNAM(STRING(1:72)
SUBROUTINE SYBNAM(STRING)
CHARACTER*(*) STRING
LEN(STRING) will be 72, not 1000

Resources