Book Description
Modern Fortran teaches you to develop fast, efficient parallel applications using twenty-first-century Fortran. In this guide, you'll dive into Fortran by creating fun apps, including a tsunami simulator and a stock price analyzer. Filled with real-world use cases, insightful illustrations, and hands-on exercises, Modern Fortran helps you see this classic language in a whole new light.
Table of Contents
- Modern Fortran
- Copyright
- contents
- front matter
- foreword
- preface
- acknowledgments
- about this book
- Who should read this book
- A bit of Fortran history
- How this book is organized: a roadmap
- About the code
- Requirements
- Get involved
- liveBook discussion forum
- about the author
- about the cover illustration
- Part 1. Getting started with Modern Fortran
- 1 Introducing Fortran
- 1.1 What is Fortran?
- 1.2 Fortran features
- 1.3 Why learn Fortran?
- 1.4 Advantages and disadvantages
- 1.4.1 Side-by-side comparison with Python
- 1.5 Parallel Fortran, illustrated
- 1.6 What will you learn in this book?
- 1.7 Think parallel!
- 1.7.1 Copying an array from one processor to another
- 1.8 Running example: A parallel tsunami simulator
- 1.8.1 Why tsunami simulator?
- 1.8.2 Shallow water equations
- 1.8.3 What we want our app to do
- 1.9 Further reading
- Summary
- 2 Getting started: Minimal working app
- 2.1 Compiling and running your first program
- 2.2 Simulating the motion of an object
- 2.2.1 What should our app do?
- 2.2.2 What is advection?
- 2.3 Implementing the minimal working app
- 2.3.1 Implementation strategy
- 2.3.2 Defining the main program
- 2.3.3 Declaring and initializing variables
- 2.3.4 Numeric data types
- 2.3.5 Declaring the data to use in our app
- 2.3.6 Branching with an if block
- 2.3.7 Using a do loop to iterate
- 2.3.8 Setting the initial water height values
- 2.3.9 Predicting the movement of the object
- 2.3.10 Printing results to the screen
- 2.3.11 Putting it all together
- 2.4 Going forward with the tsunami simulator
- 2.5 Answer key
- 2.5.1 Exercise: Cold front propagation
- 2.6 New Fortran elements, at a glance
- 2.7 Further reading
- Summary
- Part 2. Core elements of Fortran
- 3 Writing reusable code with functions and subroutines
- 3.1 Toward higher app complexity
- 3.1.1 Refactoring the tsunami simulator
- 3.1.2 Revisiting the cold front problem
- 3.1.3 An overview of Fortran program units
- 3.2 Don’t repeat yourself, use procedures
- 3.2.1 Your first function
- 3.2.2 Expressing finite difference as a function in the tsunami simulator
- 3.3 Modifying program state with subroutines
- 3.3.1 Defining and calling a subroutine
- 3.3.2 When do you use a subroutine over a function?
- 3.3.3 Initializing water height in the tsunami simulator
- 3.4 Writing pure procedures to avoid side effects
- 3.4.1 What is a pure procedure?
- 3.4.2 Some restrictions on pure procedures
- 3.4.3 Why are pure functions important?
- 3.5 Writing procedures that operate on both scalars and arrays
- 3.6 Procedures with optional arguments
- 3.7 Tsunami simulator: Putting it all together
- 3.8 Answer key
- 3.8.1 Exercise 1: Modifying state with a subroutine
- 3.8.2 Exercise 2: Writing an elemental function that operates on both scalars and arrays
- 3.9 New Fortran elements, at a glance
- 3.10 Further reading
- Summary
- 4 Organizing your Fortran code using modules
- 4.1 Accessing a module
- 4.1.1 Getting compiler version and options
- 4.1.2 Using portable data types
- 4.2 Creating your first module
- 4.2.1 The structure of a custom module
- 4.2.2 Defining a module
- 4.2.3 Compiling Fortran modules
- 4.2.4 Controlling access to variables and procedures
- 4.2.5 Putting it all together in the tsunami simulator
- 4.3 Toward realistic wave simulations
- 4.3.1 A brief look at the physics
- 4.3.2 Updating the finite difference calculation
- 4.3.3 Renaming imported entities to avoid name conflict
- 4.3.4 The complete code
- 4.4 Answer key
- 4.4.1 Exercise 1: Using portable type kinds in the tsunami simulator
- 4.4.2 Exercise 2: Defining the set_gaussian subroutine in a module
- 4.5 New Fortran elements, at a glance
- 4.6 Further reading
- Summary
- 5 Analyzing time series data with arrays
- 5.1 Analyzing stock prices with Fortran arrays
- 5.1.1 Objectives for this exercise
- 5.1.2 About the data
- 5.1.3 Getting the data and code
- 5.2 Finding the best and worst performing stocks
- 5.2.1 Declaring arrays
- 5.2.2 Array constructors
- 5.2.3 Reading stock data from files
- 5.2.4 Allocating arrays of a certain size or range
- 5.2.5 Allocating an array from another array
- 5.2.6 Automatic allocation on assignment
- 5.2.7 Cleaning up after use
- 5.2.8 Checking for allocation status
- 5.2.9 Catching allocation and deallocation errors
- 5.2.10 Implementing the CSV reader subroutine
- 5.2.11 Indexing and slicing arrays
- 5.3 Identifying risky stocks
- 5.4 Finding good times to buy and sell
- 5.5 Answer key
- 5.5.1 Exercise 1: Convenience (de)allocator subroutines
- 5.5.2 Exercise 2: Reversing an array
- 5.5.3 Exercise 3: Calculating moving average and standard deviation
- 5.6 New Fortran elements, at a glance
- 5.7 Further reading
- Summary
- 6 Reading, writing, and formatting your data
- 6.1 Your first I/O: Input from the keyboard and output to the screen
- 6.1.1 The simplest I/O
- 6.1.2 Reading and writing multiple variables at once
- 6.1.3 Standard input, output, and error
- 6.2 Formatting numbers and text
- 6.2.1 Designing the aircraft dashboard
- 6.2.2 Formatting strings, broken down
- 6.2.3 Format statements in legacy Fortran code
- 6.3 Writing to files on disk: A minimal note-taking app
- 6.3.1 Opening a file and writing to it
- 6.3.2 Opening a file
- 6.3.3 Writing to a file
- 6.3.4 Appending to a file
- 6.3.5 Opening files in read-only or write-only mode
- 6.3.6 Checking whether a file exists
- 6.3.7 Error handling and closing the file
- 6.4 Answer key
- 6.4.1 Exercise: Redirect stdout and stderr to files
- 6.5 New Fortran elements, at a glance
- Summary
- Part 3. Advanced Fortran use
- 7 Going parallel with Fortran coarrays
- 7.1 Why write parallel programs?
- 7.2 Processing real-world weather buoy data
- 7.2.1 About the data
- 7.2.2 Getting the data and code
- 7.2.3 Objectives
- 7.2.4 Serial implementation of the program
- 7.3 Parallel processing with images and coarrays
- 7.3.1 Fortran images
- 7.3.2 Getting information about the images
- 7.3.3 Telling images what to do
- 7.3.4 Gathering all data to a single image
- 7.4 Coarrays and synchronization, explained
- 7.4.1 Declaring coarrays
- 7.4.2 Allocating dynamic coarrays
- 7.4.3 Sending and receiving data
- 7.4.4 Controlling the order of image execution
- 7.5 Toward the parallel tsunami simulator
- 7.5.1 Implementation strategy
- 7.5.2 Finding the indices of neighbor images
- 7.5.3 Allocating the coarrays
- 7.5.4 The main time loop
- 7.6 Answer key
- 7.6.1 Exercise 1: Finding the array subranges on each image
- 7.6.2 Exercise 2: Writing a function that returns the indices of neighbor images
- 7.7 New Fortran elements, at a glance
- 7.8 Further reading
- Summary
- 8 Working with abstract data using derived types
- 8.1 Recasting the tsunami simulator with derived types
- 8.2 Defining, declaring, and initializing derived types
- 8.2.1 Defining a derived type
- 8.2.2 Instantiating a derived type
- 8.2.3 Accessing derived type components
- 8.2.4 Positional vs. keyword arguments in derived type constructors
- 8.2.5 Providing default values for derived type components
- 8.2.6 Writing a custom type constructor
- 8.2.7 Custom type constructor for the Field type
- 8.3 Binding procedures to a derived type
- 8.3.1 Your first type-bound method
- 8.3.2 Type-bound methods for the Field type
- 8.3.3 Controlling access to type components and methods
- 8.3.4 Bringing it all together
- 8.4 Extending tsunami to two dimensions
- 8.4.1 Going from 1-D to 2-D arrays
- 8.4.2 Updating the equation set
- 8.4.3 Finite differences in x and y
- 8.4.4 Passing a class instance to diffx and diffy functions
- 8.4.5 Derived type implementation of the tsunami solver
- 8.5 Answer key
- 8.5.1 Exercise 1: Working with private components
- 8.5.2 Exercise 2: Invoking a type-bound method from an array of instances
- 8.5.3 Exercise 3: Computing finite difference in y direction.
- 8.6 New Fortran elements, at a glance
- 8.7 Further reading
- Summary
- 9 Generic procedures and operators for any data type
- 9.1 Analyzing weather data of different types
- 9.1.1 About the data
- 9.1.2 Objectives
- 9.1.3 Strategy for this exercise
- 9.2 Type systems and generic procedures
- 9.2.1 Static versus strong typing
- 9.3 Writing your first generic procedure
- 9.3.1 The problem with strong typing
- 9.3.2 Writing the specific functions
- 9.3.3 Writing the generic interface
- 9.3.4 Results and complete program
- 9.4 Built-in and custom operators
- 9.4.1 What’s an operator?
- 9.4.2 Things to do with operators
- 9.4.3 Fortran’s built-in operators
- 9.4.4 Operator precedence
- 9.4.5 Writing custom operators
- 9.4.6 Redefining built-in operators
- 9.5 Generic procedures and operators in the tsunami simulator
- 9.5.1 Writing user-defined operators for the Field type
- 9.6 Answer key
- 9.6.1 Exercise 1: Specific average function for a derived type
- 9.6.2 Exercise 2: Defining a new string concatenation operator
- 9.7 New Fortran elements, at a glance
- Summary
- 10 User-defined operators for derived types
- 10.1 Happy Birthday! A countdown app
- 10.1.1 Some basic specification
- 10.1.2 Implementation strategy
- 10.2 Getting user input and current time
- 10.2.1 Your first datetime class
- 10.2.2 Reading user input
- 10.2.3 Getting current date and time
- 10.3 Calculating the difference between two times
- 10.3.1 Modeling a time interval
- 10.3.2 Implementing a custom subtraction operator
- 10.3.3 Time difference algorithm
- 10.3.4 The complete program
- 10.4 Overriding operators in the tsunami simulator
- 10.4.1 A refresher on the Field class
- 10.4.2 Implementing the arithmetic for the Field class
- 10.4.3 Synchronizing parallel images on assignment
- 10.5 Answer key
- 10.5.1 Exercise 1: Validating user input
- 10.5.2 Exercise 2: Leap year in the Gregorian calendar
- 10.5.3 Exercise 3: Implementing the addition for the Field type
- 10.6 New Fortran elements, at a glance
- Summary
- Part 4. The final stretch
- 11 Interoperability with C: Exposing your app to the web
- 11.1 Interfacing C: Writing a minimal TCP client and server
- 11.1.1 Introducing networking to Fortran
- 11.1.2 Installing libdill
- 11.2 TCP server program: Receiving network connections
- 11.2.1 IP address data structures
- 11.2.2 Initializing the IP address structure
- 11.2.3 Checking IP address values
- 11.2.4 Intermezzo: Matching compatible C and Fortran data types
- 11.2.5 Creating a socket and listening for connections
- 11.2.6 Accepting incoming connections to a socket
- 11.2.7 Sending a TCP message to the client
- 11.2.8 Closing a connection
- 11.3 TCP client program: Connecting to a remote server
- 11.3.1 Connecting to a remote socket
- 11.3.2 Receiving a message
- 11.3.3 The complete client program
- 11.4 Some interesting mixed Fortran-C projects
- 11.5 Answer key
- 11.5.1 Exercise 1: The Fortran interface to ipaddr_port
- 11.5.2 Exercise 2: Fortran interfaces to suffix_detach and tcp_close
- 11.6 New Fortran elements, at a glance
- 11.7 Further reading
- Summary
- 12 Advanced parallelism with teams, events, and collectives
- 12.1 From coarrays to teams, events, and collectives
- 12.2 Grouping images into teams with common tasks
- 12.2.1 Teams in the tsunami simulator
- 12.2.2 Forming new teams
- 12.2.3 Changing execution between teams
- 12.2.4 Synchronizing teams and exchanging data
- 12.3 Posting and waiting for events
- 12.3.1 A push notification example
- 12.3.2 Posting an event
- 12.3.3 Waiting for an event
- 12.3.4 Counting event posts
- 12.4 Distributed computing using collectives
- 12.4.1 Computing the minimum and maximum of distributed arrays
- 12.4.2 Collective subroutines syntax
- 12.4.3 Broadcasting values to other images
- 12.5 Answer key
- 12.5.1 Exercise 1: Hunters and gatherers
- 12.5.2 Exercise 2: Tsunami time step logging using events
- 12.5.3 Exercise 3: Calculating the global mean of water height
- 12.6 New Fortran elements, at a glance
- 12.7 Further reading
- Summary
- appendix A. Setting up the Fortran development environment
- A.1 Editing Fortran source files
- A.2 Setting up the Fortran compiler
- Linux
- macOS
- Windows
- A.3 Setting up the MPI library (Message Passing Interface)
- A.4 Setting up OpenCoarrays
- Linux
- macOS
- Using OpenCoarrays
- A.5 Building a Docker image
- appendix B. From calculus to code
- B.1 The advection equation explained
- B.1.1 Discretizing the derivatives
- B.1.2 Casting the derivatives into code
- appendix C. Concluding remarks
- C.1 Tsunami simulator: The complete code
- C.1.1 Main program: tsunami.f90
- C.1.2 The Field module: mod_field.f90
- C.1.3 The I/O module: mod_io.f90
- C.1.4 The parallel module: mod_parallel.f90
- C.2 Going forward with the tsunami simulator
- C.3 Neural networks and deep learning
- C.4 Online resources
- C.5 Compilers
- C.6 Books
- index