Code Monkey home page Code Monkey logo

tdms's Introduction

TDMS · latest release license Build and test MATLAB tests codecov DOI

Time-Domain Maxwell Solver

TDMS, the Time Domain Maxwell Solver, is a hybrid C++ and MATLAB tool for simulating light propagation through a medium by solving Maxwell's equations. For further details about the method, please refer to the PDF documentation.

The normed z-component of the H field incident on a cylinder

Getting started

We don't ship binaries at the moment, so to use TDMS, it has to be compiled. It needs to be built against FFTW and MATLAB, which must be downloaded and installed first.

Linux prerequisite setup

Assuming you don't already have them, you'll need a C++ compiler, CMake, OpenMP and FFTW.

For Debian-based distributions this should be as simple as

$ sudo apt install git gcc cmake libfftw3-dev libgomp1
MacOS prerequisite setup

On MacOS you will need an x86 compiler with libraries for OpenMP. You'll need to download the latest Xcode tools.

Everything else can be installed using Homebrew:

$ brew install cmake fftw llvm

On an ARM Mac, you will need to install the x86 version of Homebrew:

$ arch -x86_64 zsh
$ arch -x86_64 /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
$ arch -x86_64 /usr/local/bin/brew install cmake fftw llvm
Windows prerequisite setup

TDMS was developed - and extensively tested - on linux. Support for Windows is quite new and experimental (please report any issues you encounter!).

It might be more straightforward to use the Windows subsystem for Linux (WSL2), or set up an linux virtual machine.

However, TDMS can be compiled natively on Windows. This has been tested Windows 10 and 11, with PowerShell.

Assuming you don't already have them, you'll need to download and install:

You can check that the Visual Studio compiler was installed with:

PS> MSBuild.exe -h

Potentially the simplest way to get FFTW is via conda:

PS> conda install -c conda-forge fftw --yes

You'll need to ensure the paths to FFTW and MATLAB (the locations of fftw3.dll and libmex.dll respectively) are in the env:Path.

These can be found, e.g. by

PS> conda list fftw # assuming you installed via conda
PS> which.exe MATLAB

Which should return something like C:\Program Files (x86)\MATLAB\R20XXx\bin\matlab and maybe C:\ProgramData\envs\base\bin. If you downloaded FFTW and created fftw3.dll with lib.exe, you just need to know where you saved it.

You can append the paths:

PS> $env:Path += ";C:\Program Files (x86)\MATLAB\R20XXx\bin\;C:\ < wherever fftw3.dll is >"

Which will help Windows locate .dll files later. For all following instructions, you'll have to substitute our mentions of tdms with tdms.exe and $ is used to denote a command prompt which, in PowerShell, would look like PS>

Even more Windows troubleshooting

We've seen that in a fresh PowerShell window, Windows does not remember the location of the .dll files, so you may have to re-add them to the path, or copy them into the directory where TDMS was installed.

TDMS typically installs to "C:\Program Files (x86)\tdms\bin\tdms.exe".


You'll need to download and install MATLAB, and take note where the headers are installed.

Installation

To compile and install, follow these steps:

$ git clone [email protected]:UCL/TDMS.git
$ cd TDMS
$ git checkout v1.0.1 # the stable version
$ mkdir build; cd build
$ cmake ../tdms \
$ # -DMatlab_ROOT_DIR=/usr/local/MATLAB/R20XXx/ \
$ # -DFFTW_ROOT=/usr/local/fftw3/ \
$ # -DCMAKE_INSTALL_PREFIX=$HOME/.local/
$ cmake --build . --target install --config Release

If CMake cannot find MATLAB, FFTW, or install to the default installation prefix, uncomment the relevant line(s) and modify the path(s) accordingly.

You can check that tdms was installed correctly and is in your PATH by running:

$ tdms --help
$ tdms --version

in a new terminal.

How to run

You can run TDMS either directly or from a MATLAB script. For beginners, we recommend starting with the demonstration MATLAB script, which you can find in the examples/arc_01 directory. Move into this directory, launch MATLAB, and run the MATLAB script run_pstd_bscan.m. This script will generate the input to TDMS, run TDMS, and display sample output. There are comments explaining what it is doing, so you can follow along with what is being setup and created at each stage. We have also commented the input file arc_01_example_input.m that this script passes to iteratefdtd_matrix.m.

Troubleshooting

We've seen that launching MATLAB on MacOS via the launcher (cmd + space) may not preserve the system PATH.

command not found: tdms

Assuming tdms --help works in a new terminal, try launching MATLAB from that terminal.

$ tdms --help
$ /Applications/MATLAB_<version>.app/bin/matlab

The MATLAB example scripts should then find tdms. If you still have problems, you can try hard-coding the full path to tdms into the MATLAB script.

In a terminal run

$ which tdms

Copy the full path (something like /usr/local/bin/tdms) into run_pstd_bscan.m, replacing the 'tdms' text in the calls to the system() function.

MATLAB file version

In order to be readable by TDMS, files need to be saved in .mat (MATLAB file) version 7.3 or newer. This can be done by passing '-v7.3' to MATLAB's save command as the final argument, for example:

save('my_input_file.mat', 'my_input_var_1', 'my_input_var_2', ..., 'my_input_var_N', '-v7.3');
Or set v7.3 as the default in MATLAB's settings.

On the command line

If you want to run TDMS standalone at the command line, the basic operation is with two arguments: an input file containing simulation parameters, and an output file name. You can choose between two solver methods: finite-difference or pseudo-spectral, as well as two interpolation methods: cubic or bandlimited. These options can be selected by setting the corresponding flag variables in the input file. When tdms reads the input, it will verify if the input file contains a dataset that matches the names of these flags.

There are two flags available for configuration in the input file.

`use_pstd` - If not provided, or provided as `false`, then the default timestepping method of finite-differences (FDTD) will be used. - If present and set to `true`, then `tdms` will use the pseudo-spectral (PSTD) method when performing simulation timesteps.
`use_bli` - If not provided, or provided as `false`, then the default interpolation method of cubic interpolation will be used to obtain field values at the centres of Yee cells. - If present and set to `true`, then `tdms` will use bandlimited interpolation (BLI) when obtaining field values at Yee cell centres.

\note Typically bandlimited interpolation is superior to cubic interpolation when the extent of the Yee cell is of approximately the same order as, but slightly less than, one-sixth of the shortest wavelength of interest. Otherwise, cubic interpolation typically enjoys superior accuracy.

TDMS is parallelised with OpenMP. You can set the maximum number of threads using the OMP_NUM_THREADS environment variable before calling the TDMS executable.

$ export OMP_NUM_THREADS=4 # for example

Citation

If you used TDMS in your research and found it helpful, please cite this work: 10.5281/zenodo.7950604.

BibTEX
@software{tdms,
    author       = {Munro, Peter and others},
    license      = {GPL-3.0},
    title        = {{TDMS - The Time-Domain Maxwell Solver}},
    URL          = {https://github.com/UCL/TDMS},
    publisher    = {Zenodo},
    doi          = {10.5281/zenodo.7950603}
}
LaTeX
\bibitem{tdms}
P. Munro, et al \emph{TDMS - The Time-Domain Maxwell Solver}, \url{https://github.com/UCL/TDMS}, \href{https://doi.org/10.5281/zenodo.7950603}{10.5281/zenodo.7950603}.

Acknowledgements

The TDMS source code was released under a GPL-3.0 License as part of a joint project between University College London's Medical Physics and Biomedical Engineering and Centre for Advanced Research Computing with generous funding from the Royal Society.

medphys arc

Development of this software has previously benefited from funding from the Commonwealth Scholarships Commission, the Engineering and Physical Sciences Research Council, and the Australian Research Council.

Want to contribute?

We're grateful for bug reports, feature requests, and pull requests. Please see our contribution guidelines (we also have some developer documentation).

tdms's People

Contributors

dstansby avatar giordano avatar prmunro avatar samcunliffe avatar t-young31 avatar willgraham01 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

tdms's Issues

Revise repository structure

The miscellaneous matlab scripts in the root directory should be moved/removed and maybe a more conventional project layout be adopted.

$ tree -L 1 
├── CMakeLists.txt
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── doc
├── example
├── include
├── src
└── tests

Thoughts much appreciated on this one!

Can't build the unit tests executable on linux

@prmunro very sensibly followed the instructions and:

  • the build dir didn't get populated (why?)
  • cmake .. -DCMAKE_BUILT_TYPE=Test didn't create the tdms_test file (nor did ctest work).

Very embarrassing. We should double-check the instructions vs. GitHub actions are doing the same thing.

Add option to not write non-interpolated fields

Introduce an option to the input file to choose whether to write of the Ex_out, Ey_out, etc., volume fields. These are the non-interpolated versions of the fields and are generally not used. Should be able to choose which field components will be written.

Check output on Eyi 0 and []

I noticed that there was a small difference between calculated
fields between the cases where eyi is set to 0 and where eyi is set to
[]. Although this was probably less than numerical precision, this
should be checked.

Add a github action to build macos

[Placeholder issue, we might want to reject]

We are currently building windows and linux, worth to add macos? Mention this because @samcunliffe had some strange issues compiling. If this is a workflow we expect of future users/students, we probably want to test it.

On the other hand, perhaps this is a waste of time.

More examples/demonstrations

Currently there is only one piece of example/demonstration code, examples/arc-01.
It would be beneficial for both documentation and testing purposes if we had additional examples to hand, and additionally emphasised calls to the TDMS executable rather than the supporting MATLAB scripts:

  • Suppressing the MATLAB GUI from opening when setting up the input files, and using a shell script to avoid hiding the call to tdms within MATLAB's eval()?
  • Save visualisations of the output to files, rather than opening them as figures in MATLAB

Check dimensionally of E tensors

I changed exi and eyi to have size Nx x Ny x Nt, I am not sure why
I had an additional dimension of size 1. Should check this. Should
also ensure some error checking about this.

Duplicate copies of dt variable

I picked up a bug introduced during recent refactoring work, whereby there are now two variables storing dt, in particular:

params.dt
dt

both are used. This becomes a problem since in some instances dt can be changed within the code. After refactoring, params.dt was not updated, leading to incorrect behaviour. I will add this as an issue. For example, dt and params.dt are assigned:

  if(mxIsDouble(prhs[input_counter])){
    dt = mxGetPr( (mxArray *)prhs[input_counter]);
    params.dt = *dt;
    input_counter++;
  }
  else{
    throw runtime_error("expected dt to be a double");
  }

Then, in steady state mode, dt is in general updated:

  if(sourcemode==sm_steadystate){
    dt_old = dt[0];
    Nsteps_tmp = ceil(2.*dcpi/omega_an[0]/dt[0]*3);
    dt[0] = 2.*dcpi/omega_an[0]*3/Nsteps_tmp;
    params.dt = dt[0];
  }

This is where the but was introduced. Later we see that dt and params.dt are still used, e.g.,

   if( exphasorssurface || exphasorsvolume || exdetintegral || (nvertices > 0) ){
      if(sourcemode==sm_steadystate){
	if( (tind % Nsteps)==0 ){
	  E.angular_norm = 0.0;
	  H.angular_norm = 0.0;
	}
	
        E.add_to_angular_norm(fte, tind % Nsteps, Nsteps, params);
        H.add_to_angular_norm(fth, tind % Nsteps, Nsteps, params);

        for(int ifx=0;ifx<N_f_ex_vec;ifx++){
          extractPhasorENorm(&E_norm[ifx], fte, tind % Nsteps, f_ex_vec[ifx]*2*dcpi, *dt, Nsteps);
          extractPhasorHNorm(&H_norm[ifx], fth, tind % Nsteps, f_ex_vec[ifx]*2*dcpi, *dt, Nsteps);
        }
      }

In particular,

E.add_to_angular_norm(fte, tind % Nsteps, Nsteps, params);

uses dt stored within params, yet

extractPhasorENorm(&E_norm[ifx], fte, tind % Nsteps, f_ex_vec[ifx]*2*dcpi, *dt, Nsteps);

uses dt. It would be good to remove references to dt.

Add more system tests

Currently there are only PSTD tests, at least one FDTD test should also be included, and others.

  • FDTD
  • steadystate = true
  • exdetIntegral = true
  • exi is present

Enable extraction of specific field components

Add an option to the input file, which requires implementation in the C code also, to control which field components are extracted when wanting to extract an entire volume (exphasorsvolume).

Odd behaviour in `interpolate.cpp`

Odd behaviour in interpolate.cpp [Related to #44]

Several functions in interpolate.cpp seem to have redundant for loops, and mismatches between the function doc-string and what the function actually does.
Looking at interpolateFieldCentralE_TE for example:

  • An error is thrown unless k_u $\leq 0\leq$ k_l, which is in contrast to what the docstring claims the acceptable values of k_l ( $\geq 2$ ) and k_u ( $\leq$ K $-2$) are.
  • The variables i_u, j_u, k_u have intent[out], but are never assigned to, not pointers, and not returned.
  • for(k=k_l; k<=k_u; k++) only executes when k_u $\leq 0\leq$ k_l due to the previous error checks, and so k can only take the value 0.

The same things occur in interpolateFieldCentralE_TM, interpolateFieldCentralH_TE, and interpolateFieldCentralH_TM.

If the intended behaviour is what's listed in the doc-strings; the code needs to be changed and we need to check whether the result of any demonstration code or tests depend on then also changes, due to dependence on these functions.
If what's currently in the code is the intended behaviour, it looks like it can be made more readable and the doc-strings updated to match.

Improve parallelism for 2D simulations

I noticed that parallelism wasn't being properly exploited in the
case of 2D simulations as the for loop executed in parallel had only
one iteration. I have hard-coded a solution to this which needs to be
made more general. In particular, I moved the pragma omp for statement
for the Exz and Hyz update equations to a different for loop in the
nest of for loops.

Bug in steady state part of code

Hi @samcunliffe and @willGraham01, in the process of preparing a test case for the steady state option, I found an error in my version (and therefore the TDSM version) of the code. What’s the best was to make this change on the TDSM repository. It’s a relatively simple update

The code appears in the vicinity of line 5900 in the old version of the code as follows, though let me know if you want me to make this change directly in the code. This code is now in the vicinity of line 5762 in the TDMS repo, and has been changed. Although the changes in the old code will transfer easily to the new code.

Incorrect version

     if(sourcemode==sm_steadystate){
	extractPhasorENorm(&E_norm_an, fte, tind, *omega_an, *dt, Nsteps);
	extractPhasorHNorm(&H_norm_an, fth, tind, *omega_an, *dt, Nsteps);
	for(int ifx=0;ifx<N_f_ex_vec;ifx++){
	  extractPhasorENorm(&E_norm[ifx], fte, tind, f_ex_vec[ifx]*2*dcpi, *dt, Nsteps);
	  extractPhasorHNorm(&H_norm[ifx], fth, tind, f_ex_vec[ifx]*2*dcpi, *dt, Nsteps);
	}

Correct version

      if(sourcemode==sm_steadystate){
	if( (tind % Nsteps)==0 ){
	  E_norm_an = 0.;
	  H_norm_an = 0.;
	}
	extractPhasorENorm(&E_norm_an, fte, tind % Nsteps, *omega_an, *dt, Nsteps);
	extractPhasorHNorm(&H_norm_an, fth, tind % Nsteps, *omega_an, *dt, Nsteps);
	//fprintf(stderr,"Enorm = %e+i%e, fte=%e, tinf=%d, %d\n", real(E_norm_an), imag(E_norm_an), fte, tind % Nsteps, Nsteps);
	for(int ifx=0;ifx<N_f_ex_vec;ifx++){
	  extractPhasorENorm(&E_norm[ifx], fte, tind % Nsteps, f_ex_vec[ifx]*2*dcpi, *dt, Nsteps);
	  extractPhasorHNorm(&H_norm[ifx], fth, tind % Nsteps, f_ex_vec[ifx]*2*dcpi, *dt, Nsteps);
	}

Potentially unused arrays

Compiling with -Wall throws a warning

.../tdms_iterator.cpp:429:29: warning: variable 'mx_fieldsample_x' set but not used [-Wunused-but-set-variable]
  mxArray *mx_fieldsample, *mx_fieldsample_x, *mx_fieldsample_y, *mx_fieldsample_z;

as the place where it may be used is commented out

fieldsample_x[nt][kt][jt][it] = fieldsample_x[nt][kt][jt][it] + pow( Exz[ (int)fieldsample_k[kt] + Dzl[0] - 1 ][ (int)fieldsample_j[jt] + Dyl[0] - 1][ (int)fieldsample_i[it] + Dxl[0] - 1] + Exy[ (int)fieldsample_k[kt] + Dzl[0] - 1][ (int)fieldsample_j[jt] + Dyl[0] - 1][ (int)fieldsample_i[it] + Dxl[0] - 1], (int)fieldsample_n[nt])/Nsteps;

Can the commented out bock and associated allocations be removed, or would it be better as an input file configurable option?
@prmunro's thoughts would be much appreciated!

Check no e/hfile with illfile

There should be an error message when a user specifies a particular
efield and hfield file when they also pass an illfile

Build system

The makefiles in iterater/ should be removed in favour of a more generic build system (likely CMake). A pair of makefiles suitable for building on an M1 mac are here.

MATLAB unit tests

Some utility functions in the matlab/ directory are currently unused. Unit tests should be added to test the functionality. Specifically,

  • fdtdduration.m
  • minsteps_fdtd.m
  • minsteps_pstd.m
  • fdtdts.m

Dependencies


Starting point

(from @prmunro)

%exports the constants used internally in the PSTD/FDTD
%code when using pulsed illumination
[to hwhm] = fdtdduration('pstd_input_file_2D_01.m');

%calculates the minimum number of time steps required for light to
%make one double pass of the computational domain. If using the
%FDTD algorithm, the script fdtdminsteps.m should be used
Nt = minsteps_pstd('pstd_input_file_2D_01.m');

%the maximum allowable timestep
dt_upper = fdtdts('pstd_input_file_2D_01.m');

[CI] Build TDMS with `-Wall -Werror` and run a linter

For better future-proof development of this package, I think we should

  1. clear up all warnings. In particular, we should
    1. i. build the package in CI with -Wall
    2. ii. once all warnings are solved, build in CI with -Werror, to make sure no more warnings are introduced. To be clear: I'm not suggesting to use -Wall -Werror by default for all users, that's a disruptive setup
  2. use a linter, like clang-tidy in CI:
    1. i. I think we can start with a job which runs clang-tidy and reports annotations if there are warnings in the changed lines
    2. ii. Ideally, clang-tidy should always come back clean, and if it doesn't the job should fail. But this can be enabled at a later stage, when all problems are resolved

Note that point 1.ii depends on 1.i, and point 2.ii depends on 2.i, but point 2.i is independent from whole of point 1 (although warnings reported by clang-tidy will usually be a superset of those reported by -Wall).

https://github.com/cpp-linter/cpp-linter-action looks a decent linter action, for point 2. I don't think 2 (and in particular 2.ii) is a high priority (also because clang-tidy can be particularly over-zealous), but in the long term it may be helpful.

Lower the system size to speed up the tests.

apologies – don't really have time for a proper review today. but in general more tests = better so generally happy. only thought is to reduce the system size so we can be more comprehensive i.e. have both 3D and 2D examples, for instance(?)

Originally posted by @t-young31 in #98 (comment)

Refactoring ~`iterator.cpp`~ `SimulationManager::execute()`

mexFunction in iterator.cpp is the best part of 7k lines. This should be broken out into smaller functions with structs/classes for the commonly grouped function arguments.


  • Convert tabs -> spaces
  • Smaller function
  • Common classes
  • Extract methods
  • Add docstrings
  • Create generic field classes
  • #132

Demonstration code: MATLAB `save()` errors

The demonstration script run_pstd_bscan.m throws a MATLAB error when run.

MATLAB attempts to save the generated input/output files (that are to be passed to tdms) to the sub-directories gridfiles/, in/, and out/, all of which don't exist after cloning the repository (and successfully installing tdms) which causes the save() function to error.

MATLAB needs to check whether these directories need to be created, then call to mkdir if necessary, prior to attempting to generate the input and output files.

Improve empty fieldsample

There should be a better way of handling the case of when
fieldsample=[], at present I just set the number elements in the
locally stored versions of the members of fieldsample to 0.

Broken relative paths in makefiles

Improve `extractPhasorsVertices`

For consistency I need to implement a version of
extractPhasorsVertices that does not use interpolation

I should make the extractPhasorsVertices functionality available
if using steady state source condition

Improve domain field export

I have introduced a way to export time domain fields. This is
purely experimental and needs to be formalised in every aspect.

Add .tex for masterdoc.pdf

masterdoc.pdf was generated with latex rather than pdflatex. The tex file needs to be updated to be compilable, and added to the repository. It is also lacking information about some features in the code.

Extract properties at vertices

Introducing a feature to extract complex amplitudes from specific
vertices, also allowing for particular field components to be
specified.

Remove MATLAB dependency

The MATLAB dependency from TDMS can be removed, which will (a) simplify the build, (b) allow running on machines without a MATLAB licence and (c) allow static linking such that no runtime paths need to be set and a compiled binary distributed.


Decisions

  • Tensor library vs. nested std::vector vs. raw arrays
  • #181

Dependencies

Use the new logging

[Low priority]

Now we have spdlog we should use it. (A few cerrs should be spdlog::error and even spdlog::info.)

Add contributing guidelines

Adding a set of contributing guidelines (as CONTRIBUTING.md) in the root directory covering: main branch protection, PRs enforced, work on issues, max size of PRs etc.

Modify interpolation scheme

Overhaul interpolation from the split grid to the central grid.

  1. Different scheme required for each field component.
  2. Is implemented for the electric field, although interpolateTimeDomainFieldCentralEBandLimited was hacked to work for the 2D case, this should be checked.
  3. More significant work required for the magnetic field
  4. Enable interpolation to be performed right up to the edge of the computational domain.

Dependencies:


Tasks specified in PSTD_interpolation_scheme.pdf:

  • Write (time-domain) interpolation methods for E-field components. Should use BLi, and if not possible, fall back on cubic interpolation. Closed by #62.
  • Write (time-domain) interpolation methods for H-field components using the 2D-method interpolation method. Interpolation in each dimension should again use BLi if possible, and failing that fall back on cubic. Closed by #62.
  • #112
  • Unit tests for cubic interpolation methods. Closed by #62.
  • #111
  • #110
  • #109
  • #113
  • #114
  • #115

Unit testing

Currently there is only system tests, it would be helpful for development if there were some fast unit tests using e.g. catch2. This will depend on some refactoring (splitting functions)

Check structure fieldsample

There is currently no error checking at all on the structure
fieldsample

What kind of checks do there need to be?

Check illumination file contents

Error checking where the contents of illfile are loaded, in
particular, i don't currently check that the loaded file has the
correct element names, only the number of elements

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.