I want to retrieve A, h, b, tw, tf, r from a table of steelprofiles based on their name (first column).
With these data I can calculate all the other characteristics (Iy, Avz, Wy…).
In Excel this can be done pretty easily with LOOKUP.
I would like to put the data in a textfile . I wonder if there is an easy way to do this in Fortran other than using an endless if…then loop.
To me this looks like something you would do with a hash list/table. I think there is an implementation in stdlib but I don’t know if it will handle your case
In Excel you won’t be able to use LOOKUP directly on a text file, you first have to open and decode the file (“text to columns”). Same in Fortran: you first have to read the file and put the values into some arrays, and then it’s quite easy to retrieve the desired values using the findloc() intrinsic function.
Sounds like a job for SQLite. Why not import the data from file (CSV) into a database and use SQL queries to select the rows? You could even use an in-memory database just for scanning, and keep everything in flat files. And you have access to SQL databases from Fortran, too.
This really looks like a simple problem that doesn’t need a complex solution.
Rather than “an array”, I would however use a derived type array, where you can mix variable types for easier data management and still do a simple array search.
How many data entries should there be before resorting to a hash table ?
Using SQLite for a simple lookup is hardly applying the “KISS” principle !
As for using a .csv file imput, the data example provided puts a stop to that !
I have never tried to read the (European?) data format that is provided in the opening post. I wish it was never used.
Also, why not retrieve all the other characteristics (Iy, Avz, Wy…), especially as you are including “r” in the definition.
Is a HEA340 section based on h or b or something else ?
There are several ways to do this, but the best solution depends on the details. Are there just a few rows, ~10, or ~100 rows, or ~1M rows? Are they originally ordered, or do you add them in some arbitrary order? Once entered into your data structure, do you access them sequentially, or mostly sequentially, or entirely randomly. These details can make a huge difference in the effort required to compile and access your data, and the best answer cannot be given without knowing also those kinds of details. To get a starting point, look up how hash tables, binary searches, and binary search trees work.
edit: Ok, it looks like the entries are regularly spaced by the integer value in the first column. In this situation, I think a simple array should work. Make a derived type that has the appropriate character, integer, and real values (and whatever other data you need to add in the future), and make an array of that derived type. It looks like the spacing of the grid is 20, and the first element is HEA100, so if you divide by 20 the first index of the array should be 5. If you have 200 rows, then the last element would be HEA4080 (or something like that) with an index of 204. HEA400 could correspond to index of 20, the index of 50 would correspond to HEA1000, so you can go back and forth between grid values and array index values easily with integer division and multiplication.
Thank you all for your advice.
There are ~200 rows, sequentially ordered and accessed.
I’m a structural engineer, not a sofware engineer, trying to write a Fortran program to check a crane runway.
The table is taken from a catalogue of wide flange beams.
Another option would be to call the Fortran program from Excel.
I already did this for part of the program. I call a Fortran DLL from Excel to calculate the moment and shear forces in the runway under moving loads.
It cost me blood, sweat and tears but now it works like a charm.
Maybe I should continue down this pad since part of the work is already done.
However, starting with Fortran 2003, the DECIMAL specifier in the OPEN statement allows you to control whether a comma or period is used as the decimal point.
and gave a code (lightly edited)
implicit none
real :: x(2)
open(unit=10, file="comma.txt", decimal="comma", action="read")
read(10, *) x
print*,x
end
Fortran 2003 is good for reading 2,3 as 2.3, but what do you do with a text file that has data like “2,300” then the supplier much later tells you it is not two thousand three hundred, but 2 point 3.
The answer is to find a better data provider !
What a mess
No worry. In calculations and programs I always use the anglo-saxon notation with a point. I think we all do over here. In text files I replace the comma’s by points.
You just have to be carefull when transferring money digitally not transfering 1000* the amount you had in mind.
Well, maybe half of the countries in the world officially use the comma as the decimal separator, so it’s probably better to not assume that the dot is always used.
Try processing french files !
We use “;” as separators in csv, “,” for decimals, " " for the thousands. On Windows you can get the info from the registry under “Computer\HKEY_CURRENT_USER\Control Panel\International”, but of course you have no control over csv files received from another computer .
250 years ago at least one Englishman used “,” as a separator for decimals. See James Cook (1771) Phil. Trans. Roy. Soc. London 61, 397-421 “Observations made, by appointment of the Royal Society, at King George’s Island in the South Sea …”
Most of the English-speaking world now uses “.” and everybody now calls King George’s Island Tahiti.
If you have stdlib, this should be fairly easy to do with a hashmap.
We have been working to get the stdlib hashmap functions simplier and easier to use, still have a ways to go though imho. But something like below should work with the current implementation.
program example_hashamp
use stdlib_hashmaps, only: chaining_hashmap_type
use stdlib_hashmap_wrappers, only: fnv_1_hasher, set, get
implicit none
type(other_type) :: other
type(chaining_hashmap_type) :: map
type steel_profile
integer :: a
real :: mm, h, b, tw, tf, r
end type steel_profile
type(steel_profile) :: profile
character(len=32) :: profile_name
character(len=:), allocatable :: name_to_lookup
! Initialize hashmap
call map%init(fnv_1_hasher)
! Add code here to read text file, and store data in steel_profile type and profile_name.
! Perhaps looks something like below?
do i = 1, num_lines
read(*,*) profile_name, profile % mm, profile % b
! Store dervied type with profile name as the lookup key.
call set(other, profile) ! Hope to remove this step in a future version of stdlib
call map%map_entry(trim(profile_name), other)
enddo
! Then to retrieve
name_to_lookup = 'HEA340'
call map%get_other_data(name_to_lookup , other)
get(other,data) ! Hope to remove this step in a future version of stdlib
select type (data) ! Stored as unlimited polymorphic. Must be wrapped in a select type construct.
type is (steel_profile)
print *, name_to_lookup, "A values is ", data % A
end select
end program
Given that it took Fortran until 2003 to allow for the alternate use of a comma, I doubt your estimate that half of the countries in the world officially use the comma ?
Did you check before doubting? Actually it’s more than half that use the comma, but since China and India use the dot, it’s more than half of the population that use the dot.
Great! I downloaded the fortran stdlib and fpm but I have no idea how to build it an integrate it in the compiler.
Windows 11, Intel ifx, VS2022 or oneAPI command line.
I didn’t know either that comma (,) is so widely used (particularly in the European countries). The Wiki page seems to describe more info about the history:
In 1958, disputes between European and American delegates over the correct representation of the decimal separator nearly stalled the development of the ALGOL computer programming language.[23] ALGOL ended up allowing different decimal separators, but most computer languages and standard data formats (e.g., C, Java, Fortran, Cascading Style Sheets (CSS)) specify a dot. C++ and a couple of others permit a quote (') as thousands separator, and many others like Python and Julia, (only) allow ‘_’ as such a separator (it’s usually ignored, i.e. also allows 1_00_00_000 aligning with the Indian number style of 1,00,00,000 that would be 10,000,000 in the US).