Adjoint-based optimization and inverse design of photonic devices