/* * Copyright 2014-2015 Anton Khirnov * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include #include #include #include "brill_data.h" #include "basis.h" #include "cpu.h" #include "internal.h" #include "qfunc.h" #include "threadpool.h" double bdi_scalarproduct_metric_fma3(size_t len1, size_t len2, double *mat, double *vec1, double *vec2); double bdi_scalarproduct_metric_avx(size_t len1, size_t len2, double *mat, double *vec1, double *vec2); double bdi_scalarproduct_metric_sse3(size_t len1, size_t len2, double *mat, double *vec1, double *vec2); double bdi_scalarproduct_metric_c(size_t len1, size_t len2, double *mat, double *vec1, double *vec2); static int brill_init_check_options(BDContext *bd) { BDPriv *s = bd->priv; int ret; bdi_init_cpu_flags(bd); s->scalarproduct_metric = bdi_scalarproduct_metric_c; if (EXTERNAL_SSE3(s->cpu_flags)) s->scalarproduct_metric = bdi_scalarproduct_metric_sse3; if (EXTERNAL_AVX(s->cpu_flags)) s->scalarproduct_metric = bdi_scalarproduct_metric_avx; if (EXTERNAL_FMA3(s->cpu_flags)) s->scalarproduct_metric = bdi_scalarproduct_metric_fma3; if (!bd->nb_threads) { bd->nb_threads = bdi_cpu_count(); if (!bd->nb_threads) bd->nb_threads = 1; } ret = bdi_qfunc_init(bd, &s->qfunc, bd->q_func_type, bd->amplitude, bd->eppley_n, bd->rho0); if (!s->qfunc) return ret; s->coord_system = COORD_SYSTEM_RADIAL; s->basis[0] = bdi_basis_init(BASIS_FAMILY_SB_EVEN, bd->basis_scale_factor[0]); if (s->coord_system == COORD_SYSTEM_RADIAL) s->basis[1] = bdi_basis_init(BASIS_FAMILY_COS_EVEN, 0); else s->basis[1] = bdi_basis_init(BASIS_FAMILY_SB_EVEN, bd->basis_scale_factor[0]); if (!s->basis[0] || !s->basis[1]) return -ENOMEM; s->nb_colloc_points[0] = bd->nb_coeffs[0]; s->nb_colloc_points[1] = bd->nb_coeffs[1]; s->nb_coeffs[0] = bd->nb_coeffs[0]; s->nb_coeffs[1] = bd->nb_coeffs[1]; return 0; } int bd_solve(BDContext *bd) { BDPriv *s = bd->priv; int ret; if (bd->psi_minus1_coeffs) { bdi_log(bd, 0, "Solve called multiple times on the same context.\n"); return -EINVAL; } ret = brill_init_check_options(bd); if (ret < 0) return ret; ret = bdi_solve(bd); if (ret < 0) return ret; bd->psi_minus1_coeffs = s->coeffs; bd->stride = s->coeffs_stride; return 0; } BDContext *bd_context_alloc(void) { BDContext *bd = calloc(1, sizeof(*bd)); if (!bd) return NULL; bd->nb_threads = 1; bd->q_func_type = BD_Q_FUNC_GUNDLACH; bd->amplitude = 1.0; bd->eppley_n = 5; bd->nb_coeffs[0] = 80; bd->nb_coeffs[1] = 80; bd->basis_scale_factor[0] = 3.0; bd->basis_scale_factor[1] = 3.0; bd->log_callback = bdi_log_default_callback; bd->priv = calloc(1, sizeof(BDPriv)); if (!bd->priv) { free(bd); return NULL; } return bd; } void bd_context_free(BDContext **pbd) { BDContext *bd = *pbd; BDPriv *s; if (!bd) return; s = bd->priv; bdi_basis_free(&s->basis[0]); bdi_basis_free(&s->basis[1]); bdi_qfunc_free(&s->qfunc); free(s->coeffs); free(bd->priv); free(bd); *pbd = NULL; }