- Fortran compiler:
ifort
orgfortran
- MPI compiler:
mvapich
oropenmpi
MPI compiler must be installed with the Fortran compiler that compiles magudi
.
Say the source code directory (mostly magudi
) is named as <magudi-src>
. We recommend making a separate directory for the installation, which we denote <magudi-build>
. The installation is then executed via the following commands on the terminal,
mkdir <magudi-build>
cd <magudi-build>
cmake -D<cmake-var>=% <magudi-src>
make
The flag -D<cmake-var>=%
is optional, to manually set <cmake-var>
to %
. Some useful flags <cmake-var>
are:
CMAKE_BUILD_TYPE
: set to eitherrelease
ordebug
CMAKE_Fortran_COMPILER
: set to a specific fortran compiler binary file
We copy the example directory <magudi-src>/examples/AcousticMonopole
to any location you like.
cp -r <magudi-src>/examples/AcousticMonopole/* ./
config.py
file includes all routines to generate grid, function, and flow solution files in PLOT3D format. This needs a python file from <magudi-src>/utils/python
.
cp <magudi-src>/utils/python/plot3dnasa.py ./
Note that plot3dnasa.py
and config.py
are written in python2. They are currently not compatible with python3. You can either import config.py
and use the routines, or run config.py
itself:
python2 config.py
This will generate:
- Grid file:
AcousticMonopole.xyz
- Initial condition file:
AcousticMonopole.ic.q
- Function files:
AcousticMonopole.target_mollifier.f
,AcousticMonopole.control_mollifier.f
After compiling, main binary executables are generated in <magudi-build>/bin/
. There are also auxiliary executables in <magudi-build>/utils/
. Check the codes to see what tasks they do.
For baseline simulation, make a link to <magudi-build>/bin/forward
:
ln -s <magudi-build>/bin/forward ./
forward
requires two input files:
magudi.inp
: this includes all flags/parameters for simulation.bc.dat
: this includes boundary condition information on grids. you can specify your own boundary condition file inmagudi.inp
.
To execute the baseline simulation, run:
./forward --output J0.txt
This saves the quantity-of-interest (QoI) J in J0.txt
. Additionally, solutions at designated timesteps are saved. These will be required for adjoint simulation. Please check the code to see more optional arguments for forward
.
For baseline simulation, make a link to <magudi-build>/bin/adjoint
:
ln -s <magudi-build>/bin/adjoint ./
To execute the adjoint simulation, run:
./adjoint --output Grad0.txt
This saves the gradient magnitude in Grad0.txt
. Gradient vector (forcing) will be saved as AcousticMonopole.gradient.controlRegion.dat
. Additionally, solutions at designated timesteps are saved. These will be required for adjoint simulation. Please check the code to see more optional arguments for adjoint
.
We check the gradient accuracy by applying the control forcing along the gradient direction. In magudi.inp
, change the controller_switch
flag,
controller_switch = true
To make the control forcing file, make a link to <magudi-build>/bin/zaxpy
:
ln -s <magudi-build>/bin/zaxpy ./
zaxpy
refers to z=a*x+y
, where z
, x
, and y
are the vector .dat
files with the same length of the gradient file, and a
is a scalar. We make a control forcing that is 0.0001 times smaller than the gradient,
./zaxpy AcousticMonopole.control_forcing.controlRegion.dat 1e-4 AcousticMonopole.gradient.controlRegion.dat`
where the argument y
is automatically taken to be zero. Run another forward run with this file,
./forward --output J1.txt
where QoI is saved in J1.txt
. A python3 routine to compute the finite-difference and check the accuracy is
import numpy as np
fID = open('J0.txt','r')
J0 = float(fID.read())
fID.close()
fID = open('Grad0.txt','r')
Grad0 = float(fID.read())
fID.close()
fID = open('J1.txt','r')
J1 = float(fID.read())
fID.close()
A1 = 1.0E-4
Grad1 = (J1-J0) / A1
Error = abs( (Grad1 - Grad0)/Grad0 )
print ("{:.16E}".format(A1), "{:.16E}".format(Error))
Following python3 subroutine does this job for multiple amplitudes and save the errors in AcousticMonopole.gradient_accuracy.txt
:
import numpy as np
import subprocess
fID = open('J0.txt','r')
QoI0 = float(fID.read())
fID.close()
fID = open('Grad0.txt','r')
Grad0 = float(fID.read())
fID.close()
Nk = 20
Ak = 10.0**(-2.0-0.25*np.array(range(Nk)))
QoIk = np.zeros((Nk,),dtype=np.double)
Gradk = np.zeros((Nk,),dtype=np.double)
ek = np.zeros((Nk,),dtype=np.double)
for k in range(Nk):
amp = Ak[k]
command = ''
command += './zaxpy AcousticMonopole.control_forcing.controlRegion.dat %.16E AcousticMonopole.gradient.controlRegion.dat`' % amp
command += './forward --output J1.txt'
fID = open('test-step.sh','w')
fID.write(command)
fID.close()
subprocess.check_call('bash test-step.sh', shell=True)
fID = open('J1.txt','r')
QoIk[k] = float(fID.read())
fID.close()
Gradk[k] = (QoIk[k]-QoI0)/Ak[k]
ek[k] = abs( (Gradk[k]-Grad0)/Grad0 )
print ("{:.16E}".format(Ak[k]), "{:.16E}".format(QoIk[k]), "{:.16E}".format(Gradk[k]), "{:.16E}".format(ek[k]))
fId = open(globalPrefix+'.gradient_accuracy.txt','a+')
fId.write('%.16E\t%.16E\t%.16E\t%.16E\n' % (Ak[k], QoIk[k], Gradk[k], ek[k]))
fId.close()