# Transparent execution of Fortran code from the Erlang machine using ports

## Desk of Contents

Joe Armstrong, creator of the Erlang programming language, stated a few occasions that, although the Erlang system is the proper software for writing applications designed for concurrent execution, it’s not one of the best software for compute-intensive duties, resembling numerical calculations. These duties, he stated, can be finest served by calling an exterior program written in Fortran.

The issue, nonetheless, is that he by no means instructed us how one can run such a program from contained in the Erlang machine.

## The plan

We’re going to write a Fortran program that receives enter and does some calculations with the values offered by the person. As a result of our downside right here shouldn’t be how one can write Fortran, however reasonably how one can run this system from contained in the Erlang runtime, a easy program will just do wonderful. For this train, we are going to write a program that calculates the power in accordance with Newton’s 2nd legislation.

As a way to interface with the Fortran program, we use a genserver course of that manages an Erlang port. Ports are Erlang processes that permit operating exterior applications and work together with them in the identical approach we work together with processes within the Erlang machine, by sending and receiving messages.

Our goal is to name the genserver API in Erlang, have the perform transparently execute within the Fortran program (that’s, as if it had been referred to as domestically), and return the proper end result.

``````    Eshell V13.1.2  (abort with ^G)
{okay,<0.84.0>}
2> f90:power(90,80).
7200
``````

## The Fortran program

First, we concentrate on the Fortran program that may successfully carry out the calculations. As we stated, we’re going to calculate the power utilizing newton’s system, which is, as everyone knows, outlined as: `f = m * a`.

Let’s begin with the only program potential:

``````    ! newton0.f90
program newton
implicit none
integer mass, accel

mass = 90
accel = 80

write (*,'(10i0)') power(mass, accel)

incorporates
perform power(m, a) end result (f)
implicit none
integer m, a, f

f = m * a
finish perform power
finish program newton
``````

This system consists of a easy perform definition for the Newtonian system, a few variable declarations and assignments, and a write assertion that prints the results of making use of the perform to the variables as arguments.

We compile this system with `gfortran newton0.f90 -o newton`. Operating it within the terminal produces the proper end result.

For the following step, we have to course of person enter:

``````    ! newton.f90
program newton

implicit none
integer rstat
integer mass, accel
character(20) :: enter

do whereas(.true.)
do whereas(.true.)
learn(*,'(A)',iostat=rstat) enter

if (rstat /= 0) then
cease
else
if (enter(1:4) == 'mass') then
else if (enter(1:5) == 'accel') then
else if (enter(1:6) == 'return') then
exit
else
write(*,*) 'unhealthy enter'
finish if
finish if
finish do

write (*,'(10i0)') power(mass, accel)

mass = 0
accel = 0
finish do

incorporates
implicit none
integer discipline, index

learn(enter(index:), *, iostat=rstat) discipline
if (rstat == 0) then
write(*,'(10i0)') discipline
else
write(*,*) 'unhealthy enter'
endif

perform power(m, a) end result (f)
implicit none
integer m, a, f

f = m * a
finish perform power
finish program newton
``````

This system begins with a loop, which reads the usual enter, and assigns its worth to a string. The enter is matched to the anticipated patterns:

• mass [value]: shops the worth within the mass variable
• accel [value]: shops the worth within the accel variable
• return: exits the loop and proceeds to the following step

Subsequent, this system prints the results of the power perform over the variables, similar to within the earlier snippet. Let’s compile this system and run it within the terminal to see it in motion.

``````    > ./newton
> mass 90
90
> accel 80
80
> return
7200
``````

Nice, we have now efficiently written a Fortran program that calculates the power utilizing the Newtonian system. Now, we have to write an Erlang program that is ready to run it.

## The Erlang program

As we stated, we wish to have the ability to name an Erlang perform that produces the end result from the Fortran program’s execution. The suitable approach to do that in Erlang is utilizing ports. Acording to the documentation:

Ports present the essential mechanism for communication with the exterior world, from Erlang’s standpoint. The ports present a byte-oriented interface to an exterior program. When a port is created, Erlang can talk with it by sending and receiving lists of bytes (not Erlang phrases). Which means that the programmer might need to invent an appropriate encoding and decoding scheme.

When to make use of: Ports can be utilized for all types of interoperability conditions the place the Erlang program and the opposite program runs on the identical machine. Programming is pretty straight-forward.

Most issues within the Erlang system are processes, and ports are not any exception. A port is a processes that sends and receives messages from different processes within the Erlang runtime, and sends and receives messages from the exterior program.

One key distinction of message passing from ports to the exterior program, in contrast with message passing between processes contained in the Erlang runtime, is that inner processes perceive Erlang phrases (e.g. atoms, tuples, information, maps), whereas the exterior program completely doesn’t. Every part we will do is ship and obtain binaries.

That is similar to what occurs within the distributed structure of microservices applied in several programming languages. For instance, three providers operating Node, JVM, and Python can not share objects native to their respective languages. They have to as an alternative resort to a standard binary (string) protocol (e.g. JSON) for the API, and implement encoding/decoding internally.

Fortunately for us, our Fortran program is designed to anticipate quite simple binary patterns. Let’s have a look at how we create a port and ship and obtain messages.

``````    Eshell V13.1.2  (abort with ^G)
1> Port = open_port({spawn, "./newton"}, [use_stdio, exit_status]).
#Port<0.5>
2> Port ! {self(), {command, "mass 90n"}}.
{<0.82.0>,{command,"mass 90n"}}
3> flush().
Shell bought {#Port<0.5>,{knowledge,"90n"}}
okay
4> Port ! {self(), {command, "accel 90n"}}.
{<0.82.0>,{command,"accel 90n"}}
5> flush().
Shell bought {#Port<0.5>,{knowledge,"90n"}}
okay
6> Port ! {self(), {command, "returnn"}}.
{<0.82.0>,{command,"returnn"}}
6> flush().
Shell bought {#Port<0.5>,{knowledge,"8100n"}}
okay
``````

We create a port with the Erlang library perform open_port/2, which receives the command to the exterior program and a few choices, and returns the port Pid. We use the Pid to ship messages to the port, which it is going to relay to the exterior program utilizing the stdin.

Right here, we’re making a port to the Fortran program “./newton”, and sending it three messages. The flush() name reads the messages acquired by the Erlang shell course of. Discover the third message: it’s the results of the `power()` perform, executed by the Fortran program!

We’re very near wrapping this up. All that’s left is to place this performance in a genserver that manages the port and gives a transparent interface in accordance with the OTP requirements.

``````    %% f90.erl
-module(f90).
-behaviour(gen_server).

-export([init/1, handle_call/3, handle_cast/2]).

%% API

cease() ->
gen_server:solid(?MODULE, cease).

power(Mass, Accel) ->
gen_server:name(?MODULE, {power, Mass, Accel}).

%% callbacks
init(Filename) ->
process_flag(trap_exit, true),
Port = open_port({spawn, Filename}, [use_stdio, exit_status]),
{okay, {port, Port}}.

handle_call({power, Mass, Accel}, _From, {port, Port} = State) ->
call_port(mass(Mass), Port),
call_port(accel(Accel), Port),
Res = call_port(end result(), Port),

handle_cast(cease, {port, Port}) ->
port_close(Port),
{cease, regular, []}.

call_port(X, Port) ->
port_command(Port, X),
obtain
{_, {knowledge, Knowledge}} ->
TrimmedData = string:trim(Knowledge),
list_to_integer(TrimmedData)
after 500 -> nil
finish.

accel(X) -> "accel " ++ integer_to_list(X) ++ "n".
mass(X) -> "mass " ++ integer_to_list(X) ++ "n".
end result() -> "returnn".
``````

We begin the genserver with `start_link/1` by offering the exterior program command as argument. The `init/1` perform runs as a callback, spawns the port, and shops the port Pid within the genserver state.

The `power/2` perform takes two integers, mass and acceleration, and can callback a handler that sends messages to the port and receives the response from the exterior program.

With this, we have now applied precisely the performance we wished at first: a server that gives a easy Erlang perform and produces the results of a calculation accomplished in an exterior Fortran program.

## Conclusion

The pc is an superior machine, and it gives so many alternative instruments and patterns with which we will create applications. It’s a waste of intelligence to be confined to a single programming language.

On this train, we confirmed that with a easy assemble, the Erlang port, we will interface with exterior applications in different languages. As soon as we arrange a standard binary protocol between the 2 applications, we will ship and obtain messages similar to we do contained in the Erlang machine, requesting execution and getting again outcomes.

The Article was Inspired from tech community site.
Contact us if this is inspired from your article and we will give you credit for it for serving the community.