Skip to content

Commit 8bfc879

Browse files
authored
Merge branch 'main' into main
2 parents b4e8766 + 06a2511 commit 8bfc879

66 files changed

Lines changed: 2705 additions & 73 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/discovery.yml

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
name: EPDE Discovery (slow) tests
2+
3+
on:
4+
workflow_dispatch:
5+
6+
jobs:
7+
discovery:
8+
runs-on: ubuntu-latest
9+
timeout-minutes: 360
10+
11+
strategy:
12+
fail-fast: false
13+
matrix:
14+
python-version: ["3.11"]
15+
operator: ["DeepXDEBasedFitness", "PIC", "L2LRFitness"]
16+
17+
steps:
18+
- uses: actions/checkout@v4
19+
20+
- name: Set up Python
21+
uses: actions/setup-python@v5
22+
with:
23+
python-version: ${{ matrix.python-version }}
24+
cache: 'pip'
25+
26+
- name: Install dependencies
27+
run: |
28+
python -m pip install --upgrade pip
29+
pip install -r requirements.txt
30+
pip install torch
31+
echo "PYTHONPATH=$PYTHONPATH:$(pwd)" >> $GITHUB_ENV
32+
33+
- name: Run discovery tests
34+
run: |
35+
pytest tests/functional/ -m functional \
36+
--discovery --report \
37+
--operators ${{ matrix.operator }} \
38+
--ignore=tests/functional/tests/test_ns.py \
39+
--timeout=3600
40+
41+
- name: Upload reports
42+
uses: actions/upload-artifact@v4
43+
if: always()
44+
with:
45+
name: reports-${{ matrix.operator }}
46+
path: reports/
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
name: EPDE Core Tests
2+
3+
on:
4+
workflow_dispatch:
5+
push:
6+
branches: [ main ]
7+
pull_request:
8+
branches: [ main ]
9+
10+
jobs:
11+
test:
12+
name: pytest (${{ matrix.python-version }}) / ${{ matrix.split }}
13+
runs-on: ubuntu-latest
14+
timeout-minutes: 30
15+
16+
strategy:
17+
fail-fast: false
18+
matrix:
19+
python-version: ["3.11"]
20+
operator: ["L2LRFitness"]
21+
split: [1, 2, 3, 4]
22+
23+
steps:
24+
- uses: actions/checkout@v4
25+
26+
- name: Set up Python
27+
uses: actions/setup-python@v5
28+
with:
29+
python-version: ${{ matrix.python-version }}
30+
cache: 'pip'
31+
32+
- name: Install dependencies
33+
run: |
34+
python -m pip install --upgrade pip
35+
pip install -r requirements.txt
36+
pip install torch
37+
pip install pytest-xdist pytest-split pytest-timeout
38+
echo "PYTHONPATH=$PYTHONPATH:$(pwd)" >> $GITHUB_ENV
39+
40+
- name: Run split tests
41+
run: |
42+
pytest tests/functional/ \
43+
--splits 4 --group ${{ matrix.split }} \
44+
--durations=20 \
45+
--timeout=600 \
46+
-m "not slow" \
47+
--operators ${{ matrix.operator }}

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ coverage.xml
5050
*.py,cover
5151
.hypothesis/
5252
.pytest_cache/
53+
reports/
5354

5455
# Translations
5556
*.mo

epde/integrate/deepxde_integration.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
import deepxde as dde
1010
from abc import ABC, abstractmethod
1111

12+
os.makedirs(os.path.expanduser('~/.deepxde'), exist_ok=True)
13+
1214
class SolverStrategy(ABC):
1315
@abstractmethod
1416
def solve(self, eq_list: List[Equation], var_names: List[str],

epde/operators/utils/parameters/default_parameters_multi_objective.json

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,20 @@
3030
"penalty_coeff" : 0.2,
3131
"pinn_loss_mult" : 1e4
3232
},
33-
"DeepXDEBasedFitness" : {
34-
"penalty_coeff" : 0.2,
35-
"pinn_loss_mult" : 1e4
36-
},
33+
"DeepXDEBasedFitness": {
34+
"deepxde_config": {
35+
"net": [95, 100, 95],
36+
"activation": "tanh",
37+
"optimizer": "adam",
38+
"lr": 1e-3,
39+
"num_domain": 1000,
40+
"num_boundary": 200,
41+
"num_initial": 200,
42+
"epochs": 2000
43+
},
44+
"penalty_coeff": 0.2,
45+
"error_metric": "rmse"
46+
},
3747
"ParetoLevelsCrossover" : {
3848

3949
},

projects/pic/data/ac/ac.py

Lines changed: 42 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -78,15 +78,13 @@ def prepare_suboperators(fitness_operator: CompoundOperator, operator_params: di
7878
sparsity = LASSOSparsity()
7979
coeff_calc = LinRegBasedCoeffsEquation()
8080

81-
# sparsity = map_operator_between_levels(sparsity, 'gene level', 'chromosome level')
82-
# coeff_calc = map_operator_between_levels(coeff_calc, 'gene level', 'chromosome level')
83-
84-
fitness_operator.set_suboperators({'sparsity': sparsity,
85-
'coeff_calc': coeff_calc})
86-
fitness_cond = lambda x: not getattr(x, 'fitness_calculated')
81+
fitness_operator.set_suboperators({'sparsity': sparsity, 'coeff_calc': coeff_calc})
8782
fitness_operator.params = operator_params
88-
fitness_operator = map_operator_between_levels(fitness_operator, 'gene level', 'chromosome level',
89-
objective_condition=fitness_cond)
83+
84+
if 'chromosome level' not in fitness_operator._tags:
85+
fitness_cond = lambda x: not getattr(x, 'fitness_calculated')
86+
fitness_operator = map_operator_between_levels(fitness_operator, 'gene level', 'chromosome level',
87+
objective_condition=fitness_cond)
9088
return fitness_operator
9189

9290
def ac_data(filename: str):
@@ -98,6 +96,14 @@ def ac_data(filename: str):
9896
return grids, data
9997

10098

99+
def get_pic_network_summary(operator):
100+
if operator.adapter is None or operator.adapter.net is None:
101+
return None
102+
net = operator.adapter.net
103+
total_params = sum(p.numel() for p in net.parameters())
104+
layers = [str(layer) for layer in net.layers] if hasattr(net, 'layers') else []
105+
return {'total_parameters': total_params, 'layers': layers}
106+
101107
def AC_test(operator: CompoundOperator, foldername: str, noise_level: int = 0):
102108
# Test scenario to evaluate performance on Allen-Cahn equation
103109
eq_ac_symbolic = '0.0001 * d^2u/dx1^2{power: 1.0} + -5.0 * u{power: 3.0} + 5.0 * u{power: 1.0} + 0.0 = du/dx0{power: 1.0}'
@@ -172,36 +178,41 @@ def ac_discovery(foldername, noise_level):
172178
if __name__ == "__main__":
173179
import torch
174180
from epde.operators.utils.default_parameter_loader import EvolutionaryParams
181+
global_var.solution_guess_nn = None
175182
print(torch.cuda.is_available())
176183
print(f"CUDA version linked with PyTorch: {torch.version.cuda}")
177184
# Operator = fitness.SolverBasedFitness # Replace by the developed PIC-based operator.
178-
# Operator = fitness.PIC
179-
# Operator = fitness.L2LRFitness
180-
Operator = fitness.DeepXDEBasedFitness
185+
#Operator = fitness.PIC
186+
Operator = fitness.L2LRFitness
187+
#Operator = fitness.DeepXDEBasedFitness
181188
params = EvolutionaryParams()
182-
# operator_params = params.get_default_params_for_operator('DiscrepancyBasedFitnessWithCV') #{"penalty_coeff": 0.2, "pinn_loss_mult": 1e4}
183-
try:
184-
operator_params = params.get_default_params_for_operator('DeepXDEBasedFitness')
185-
except Exception as e:
186-
print(f"Предупреждение: не удалось загрузить параметры для DeepXDEBasedFitness: {e}")
187-
print("Использую ручную конфигурацию.")
188-
operator_params = {
189-
"deepxde_config": {
190-
"net": [50, 50, 50],
191-
"activation": "tanh",
192-
"optimizer": "adam",
193-
"lr": 1e-3,
194-
"num_domain": 1000,
195-
"num_boundary": 200,
196-
"num_initial": 200,
197-
"iterations": 2
198-
},
199-
"penalty_coeff": 0.2,
200-
"error_metric": "rmse"
201-
}
189+
operator_params = params.get_default_params_for_operator('DiscrepancyBasedFitnessWithCV') #{"penalty_coeff": 0.2, "pinn_loss_mult": 1e4}
190+
#operator_params = params.get_default_params_for_operator('PIC')
191+
192+
# try:
193+
# operator_params = params.get_default_params_for_operator('DeepXDEBasedFitness')
194+
# except Exception as e:
195+
# print(f"Предупреждение: не удалось загрузить параметры для DeepXDEBasedFitness: {e}")
196+
# print("Использую ручную конфигурацию.")
197+
# operator_params = {
198+
# "deepxde_config": {
199+
# "net": [50, 50, 50],
200+
# "activation": "tanh",
201+
# "optimizer": "adam",
202+
# "lr": 1e-3,
203+
# "num_domain": 1000,
204+
# "num_boundary": 200,
205+
# "num_initial": 200,
206+
# "iterations": 2
207+
# },
208+
# "penalty_coeff": 0.2,
209+
# "error_metric": "rmse"
210+
# }
202211

203212
print('operator_params ', operator_params)
213+
204214
fit_operator = prepare_suboperators(Operator(list(operator_params.keys())), operator_params)
215+
#get_pic_network_summary(fit_operator)
205216

206217
# Paths
207218
directory = os.path.dirname(os.path.realpath(__file__))

projects/pic/data/burgers/burgers.py

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -49,13 +49,19 @@ def compare_equations(correct_symbolic: str, eq_incorrect_symbolic: str,
4949
for var in all_vars:
5050
correct_eq.vals[var].main_var_to_explain = var
5151
correct_eq.vals[var].metaparameters = metaparams
52+
correct_eq.vals[var].weights_internal = np.ones(len(correct_eq.vals[var].structure) - 1)
53+
correct_eq.vals[var].weights_internal_evald = True
54+
correct_eq.vals[var].weights_final_evald = True
5255
print(correct_eq.text_form)
5356

5457
incorrect_eq = translate_equation(eq_incorrect_symbolic, search_obj.pool,
5558
all_vars=all_vars) # , all_vars = ['u', 'v'])
5659
for var in all_vars:
5760
incorrect_eq.vals[var].main_var_to_explain = var
5861
incorrect_eq.vals[var].metaparameters = metaparams
62+
incorrect_eq.vals[var].weights_internal = np.ones(len(incorrect_eq.vals[var].structure) - 1)
63+
incorrect_eq.vals[var].weights_internal_evald = True
64+
incorrect_eq.vals[var].weights_final_evald = True
5965
print(incorrect_eq.text_form)
6066

6167
fit_operator.apply(correct_eq, {})
@@ -109,8 +115,8 @@ def burgers_data(filename: str):
109115

110116
def burgers_sindy_test(operator: CompoundOperator, foldername: str, noise_level: int = 0):
111117
# Test scenario to evaluate performance on Allen-Cahn equation
112-
eq_burgers_symbolic = '0.0001 * d^2u/dx1^2{power: 1.0} + -5.0 * u{power: 3.0} + 5.0 * u{power: 1.0} + 0.0 = du/dx0{power: 1.0}'
113-
eq_burgers_incorrect = '-1.0 * d^2u/dx0^2{power: 1.0} + 1.5 * u{power: 1.0} + -0.0 = du/dx0{power: 1.0}'
118+
eq_burgers_symbolic = '-1.0 * u{power: 1.0} * du/dx1{power: 1.0} + 0.01 * d^2u/dx1^2{power: 1.0} + 0.0 = du/dx0{power: 1.0}'
119+
eq_burgers_incorrect = '0.02 * d^2u/dx1^2{power: 1.0} + -0.98 * u{power: 1.0} * du/dx1{power: 1.0} + 0.0 * u{power: 1.0} + 0.0 = du/dx0{power: 1.0}'
114120

115121
grid, data = burgers_sindy_data(os.path.join(foldername, 'burgers.mat'))
116122
noised_data = noise_data(data, noise_level)
@@ -240,6 +246,6 @@ def burgers_sindy_discovery(foldername, noise_level):
240246
directory = os.path.dirname(os.path.realpath(__file__))
241247
burgers_folder_name = os.path.join(directory)
242248

243-
burgers_discovery(burgers_folder_name, 0)
249+
# burgers_discovery(burgers_folder_name, 0)
244250
# burgers_sindy_test(fit_operator, burgers_folder_name, 0)
245-
# burgers_sindy_discovery(burgers_folder_name, 0)
251+
burgers_sindy_discovery(burgers_folder_name, 0)

projects/pic/data/kdv/kdv.py

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,8 @@
2626

2727
def load_pretrained_PINN(ann_filename):
2828
try:
29-
with open(ann_filename, 'rb') as data_input_file:
30-
data_nn = pickle.load(data_input_file)
29+
import torch
30+
data_nn = torch.load(ann_filename, map_location=torch.device('cpu'))
3131
except FileNotFoundError:
3232
print('No model located, proceeding with ann approx. retraining.')
3333
data_nn = None
@@ -47,13 +47,19 @@ def compare_equations(correct_symbolic: str, eq_incorrect_symbolic: str,
4747
for var in all_vars:
4848
correct_eq.vals[var].main_var_to_explain = var
4949
correct_eq.vals[var].metaparameters = metaparams
50+
correct_eq.vals[var].weights_internal = np.ones(len(correct_eq.vals[var].structure) - 1)
51+
correct_eq.vals[var].weights_internal_evald = True
52+
correct_eq.vals[var].weights_final_evald = True
5053
print(correct_eq.text_form)
5154

5255
incorrect_eq = translate_equation(eq_incorrect_symbolic, search_obj.pool,
5356
all_vars=all_vars) # , all_vars = ['u', 'v'])
5457
for var in all_vars:
5558
incorrect_eq.vals[var].main_var_to_explain = var
5659
incorrect_eq.vals[var].metaparameters = metaparams
60+
incorrect_eq.vals[var].weights_internal = np.ones(len(correct_eq.vals[var].structure) - 1)
61+
incorrect_eq.vals[var].weights_internal_evald = True
62+
incorrect_eq.vals[var].weights_final_evald = True
5763
print(incorrect_eq.text_form)
5864

5965
fit_operator.apply(correct_eq, {})
@@ -143,7 +149,7 @@ def KdV_test(operator: CompoundOperator, foldername: str, noise_level: int = 0):
143149
grid, data = kdv_data(os.path.join(foldername, 'data.csv'))
144150
# grid, data = kdv_data(os.path.join(foldername, 'Kdv.mat'))
145151
noised_data = noise_data(data, noise_level)
146-
data_nn = load_pretrained_PINN(os.path.join(foldername, 'kdv_0_ann.pickle'))
152+
data_nn = None #load_pretrained_PINN(os.path.join(foldername, 'kdv_0_ann.pickle'))
147153

148154
print('Shapes:', data.shape, grid[0].shape)
149155
dimensionality = 1
@@ -153,7 +159,7 @@ def KdV_test(operator: CompoundOperator, foldername: str, noise_level: int = 0):
153159

154160
epde_search_obj = EpdeSearch(use_solver = False, use_pic=True, boundary = 10,
155161
coordinate_tensors = (grid[0], grid[1]), verbose_params = {'show_iter_idx' : True},
156-
device = 'cuda')
162+
device = 'cuda' if torch.cuda.is_available() else 'cpu')
157163

158164
custom_trigonometric_eval_fun = {
159165
'cos(t)sin(x)': lambda *grids, **kwargs: (np.cos(grids[0]) * np.sin(grids[1])) ** kwargs['power']}
@@ -200,7 +206,7 @@ def KdV_h_test(operator: CompoundOperator, foldername: str, noise_level: int = 0
200206

201207
epde_search_obj = EpdeSearch(use_solver = False, use_pic=True, boundary = 20,
202208
coordinate_tensors = (grid[0], grid[1]), verbose_params = {'show_iter_idx' : True},
203-
device = 'cuda')
209+
device = 'cuda' if torch.cuda.is_available() else 'cpu')
204210

205211
epde_search_obj.set_preprocessor(default_preprocessor_type='FD',
206212
preprocessor_kwargs={}) #'epochs_max': 5e4
@@ -232,7 +238,7 @@ def KdV_sga_test(operator: CompoundOperator, foldername: str, noise_level: int =
232238

233239
epde_search_obj = EpdeSearch(use_solver = False, use_pic=True, boundary = 10,
234240
coordinate_tensors = (grid[0], grid[1]), verbose_params = {'show_iter_idx' : True},
235-
device = 'cuda')
241+
device = 'cuda' if torch.cuda.is_available() else 'cpu')
236242

237243
epde_search_obj.set_preprocessor(default_preprocessor_type='FD',
238244
preprocessor_kwargs={}) #'epochs_max': 5e4
@@ -254,7 +260,7 @@ def kdv_discovery(foldername, noise_level):
254260

255261
epde_search_obj = EpdeSearch(use_solver=False, use_pic=True,
256262
boundary=5,
257-
coordinate_tensors=grid, device='cuda')
263+
coordinate_tensors=grid, device='cuda' if torch.cuda.is_available() else 'cpu')
258264

259265
# epde_search_obj.set_preprocessor(default_preprocessor_type='ANN',
260266
# preprocessor_kwargs={'epochs_max' : 1e3})
@@ -307,7 +313,7 @@ def kdv_h_discovery(foldername, noise_level):
307313

308314
epde_search_obj = EpdeSearch(use_solver=False, use_pic=True,
309315
boundary=20,
310-
coordinate_tensors=grid, device='cuda')
316+
coordinate_tensors=grid, device='cuda' if torch.cuda.is_available() else 'cpu')
311317

312318
# epde_search_obj.set_preprocessor(default_preprocessor_type='ANN',
313319
# preprocessor_kwargs={'epochs_max' : 1e3})
@@ -363,7 +369,7 @@ def kdv_sga_discovery(foldername, noise_level):
363369

364370
epde_search_obj = EpdeSearch(use_solver=False, use_pic=True,
365371
boundary=20,
366-
coordinate_tensors=grid, device='cuda')
372+
coordinate_tensors=grid, device='cuda' if torch.cuda.is_available() else 'cpu')
367373

368374
epde_search_obj.set_preprocessor(default_preprocessor_type='ANN',
369375
preprocessor_kwargs={'epochs_max' : 1e3})
@@ -421,7 +427,7 @@ def kdv_sindy_discovery(foldername, noise_level):
421427

422428
epde_search_obj = EpdeSearch(use_solver=False, use_pic=True,
423429
boundary=(40, 100),
424-
coordinate_tensors=grid, device='cuda')
430+
coordinate_tensors=grid, device='cuda' if torch.cuda.is_available() else 'cpu')
425431

426432
# epde_search_obj.set_preprocessor(default_preprocessor_type='ANN',
427433
# preprocessor_kwargs={'epochs_max' : 1e3})
@@ -470,8 +476,8 @@ def kdv_sindy_discovery(foldername, noise_level):
470476
from epde.operators.utils.default_parameter_loader import EvolutionaryParams
471477
print("CUDA available:", torch.cuda.is_available())
472478
# Operator = fitness.SolverBasedFitness # Replace by the developed PIC-based operator.
473-
# Operator = fitness.PIC
474-
Operator = fitness.L2LRFitness
479+
Operator = fitness.PIC
480+
# Operator = fitness.L2LRFitness
475481
params = EvolutionaryParams()
476482
operator_params = params.get_default_params_for_operator('DiscrepancyBasedFitnessWithCV') #{"penalty_coeff": 0.2, "pinn_loss_mult": 1e4}
477483
# operator_params = {"penalty_coeff": 0.2, "pinn_loss_mult": 1e4}

0 commit comments

Comments
 (0)